X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Fgame.c;h=3051f5ac9d93771620536c019413d08420dceec0;hb=9de8eede744c45187c7011543ef8097d1ebc879c;hp=d837dad2089889148c108b72a294c71476dcc17d;hpb=a3bc2ca4c0acf21291d20b5affed89f149b85862;p=rocksndiamonds.git diff --git a/src/game.c b/src/game.c index d837dad2..3051f5ac 100644 --- a/src/game.c +++ b/src/game.c @@ -89,6 +89,9 @@ #define DOUBLE_PLAYER_SPEED(p) (HALVE_MOVE_DELAY((p)->move_delay_value)) #define HALVE_PLAYER_SPEED(p) (DOUBLE_MOVE_DELAY((p)->move_delay_value)) +/* values for other actions */ +#define MOVE_STEPSIZE_NORMAL (TILEX / MOVE_DELAY_NORMAL_SPEED) + #define INIT_GFX_RANDOM() (SimpleRND(1000000)) #define GET_NEW_PUSH_DELAY(e) ( (element_info[e].push_delay_fixed) + \ @@ -163,8 +166,11 @@ static void CloseAllOpenTimegates(void); static void CheckGravityMovement(struct PlayerInfo *); static void KillHeroUnlessProtected(int, int); -static void CheckTriggeredElementChange(int, int); -static void CheckPlayerElementChange(int, int, int, int); +static void TestIfPlayerTouchesCustomElement(int, int); +static void TestIfElementTouchesCustomElement(int, int); + +static boolean CheckTriggeredElementChange(int, int, int, int); +static boolean CheckElementChange(int, int, int, int); static void ChangeElementNow(int, int, int); static void PlaySoundLevel(int, int, int); @@ -370,6 +376,25 @@ push_delay_list[] = { EL_UNDEFINED, 0, 0 }, }; +struct +{ + int element; + int move_stepsize; +} +move_stepsize_list[] = +{ + { EL_AMOEBA_DROP, 2 }, + { EL_AMOEBA_DROPPING, 2 }, + { EL_QUICKSAND_FILLING, 1 }, + { EL_QUICKSAND_EMPTYING, 1 }, + { EL_MAGIC_WALL_FILLING, 2 }, + { EL_BD_MAGIC_WALL_FILLING, 2 }, + { EL_MAGIC_WALL_EMPTYING, 2 }, + { EL_BD_MAGIC_WALL_EMPTYING, 2 }, + + { EL_UNDEFINED, 0 }, +}; + struct { int element; @@ -377,17 +402,17 @@ struct } gem_count_list[] = { - { EL_EMERALD, 1 }, - { EL_BD_DIAMOND, 1 }, - { EL_EMERALD_YELLOW, 1 }, - { EL_EMERALD_RED, 1 }, - { EL_EMERALD_PURPLE, 1 }, - { EL_DIAMOND, 3 }, - { EL_SP_INFOTRON, 1 }, - { EL_PEARL, 5 }, - { EL_CRYSTAL, 8 }, - - { EL_UNDEFINED, 0 }, + { EL_EMERALD, 1 }, + { EL_BD_DIAMOND, 1 }, + { EL_EMERALD_YELLOW, 1 }, + { EL_EMERALD_RED, 1 }, + { EL_EMERALD_PURPLE, 1 }, + { EL_DIAMOND, 3 }, + { EL_SP_INFOTRON, 1 }, + { EL_PEARL, 5 }, + { EL_CRYSTAL, 8 }, + + { EL_UNDEFINED, 0 }, }; static boolean changing_element[MAX_NUM_ELEMENTS]; @@ -397,7 +422,6 @@ static unsigned long trigger_events[MAX_NUM_ELEMENTS]; #define IS_JUST_CHANGING(x, y) (ChangeDelay[x][y] != 0) #define IS_CHANGING(x, y) (IS_AUTO_CHANGING(Feld[x][y]) || \ IS_JUST_CHANGING(x, y)) -#define TRIGGERS_BY_COLLECTING(e) (trigger_events[e] & CE_OTHER_COLLECTING) void GetPlayerConfig() @@ -822,7 +846,7 @@ static void InitGameEngine() /* add trigger events from element change event properties */ for (i=0; iPushing && player->MovPos != 0); -#else - boolean pushing = (player != NULL && player->Pushing && player->is_moving); -#endif -#endif - -#if 0 - if (player && player->is_moving && player->MovPos == 0) - printf("::: !!!\n"); -#endif - - if (element == EL_AMOEBA_DROP || element == EL_AMOEBA_DROPPING) - step /= 2; - else if (element == EL_QUICKSAND_FILLING || - element == EL_QUICKSAND_EMPTYING) - step /= 4; - else if (element == EL_MAGIC_WALL_FILLING || - element == EL_BD_MAGIC_WALL_FILLING || - element == EL_MAGIC_WALL_EMPTYING || - element == EL_BD_MAGIC_WALL_EMPTYING) - step /= 2; - else if (CAN_FALL(element) && horiz_move && - y < lev_fieldy-1 && IS_BELT_ACTIVE(Feld[x][y+1])) - step /= 2; - else if (element == EL_SPRING && horiz_move) - step *= 2; - else if (IS_CUSTOM_ELEMENT(element)) - step = SIGN(step) * element_info[element].move_stepsize; -#if OLD_GAME_BEHAVIOUR - else if (CAN_FALL(element) && horiz_move && !IS_SP_ELEMENT(element)) - step*=2; -#endif + /* special values for move stepsize for spring and things on conveyor belt */ + if (horiz_move) + { + if (CAN_FALL(element) && + y < lev_fieldy - 1 && IS_BELT_ACTIVE(Feld[x][y + 1])) + step = sign * MOVE_STEPSIZE_NORMAL / 2; + else if (element == EL_SPRING) + step = sign * MOVE_STEPSIZE_NORMAL * 2; + } MovPos[x][y] += step; -#if 1 -#if 1 if (pushed) /* special case: moving object pushed by player */ -#else - if (pushing) /* special case: moving object pushed by player */ -#endif -#if 1 MovPos[x][y] = SIGN(MovPos[x][y]) * (TILEX - ABS(PLAYERINFO(x,y)->MovPos)); -#else - MovPos[x][y] = SIGN(MovPos[x][y]) * (TILEX - ABS(PLAYERINFO(x,y)->GfxPos)); -#endif -#endif - -#if 0 - if (element == EL_SPRING) - printf("::: spring moves %d [%d: %d, %d, %d/%d]\n", - MovPos[x][y], - pushing, - (player?player->Pushing:-42), - (player?player->is_moving:-42), - (player?player->MovPos:-42), - (player?player->GfxPos:-42)); -#endif if (ABS(MovPos[x][y]) >= TILEX) /* object reached its destination */ { @@ -4048,31 +4033,11 @@ void ContinueMoving(int x, int y) if (element == EL_MOLE) { - int i; - static int xy[4][2] = - { - { 0, -1 }, - { -1, 0 }, - { +1, 0 }, - { 0, +1 } - }; - Feld[x][y] = EL_SAND; - DrawLevelField(x, y); - - for(i=0; i<4; i++) - { - int xx, yy; - - xx = x + xy[i][0]; - yy = y + xy[i][1]; - if (IN_LEV_FIELD(xx, yy) && Feld[xx][yy] == EL_SAND) - DrawLevelField(xx, yy); /* for "crumbled sand" */ - } + DrawLevelFieldCrumbledSandNeighbours(x, y); } - - if (element == EL_QUICKSAND_FILLING) + else if (element == EL_QUICKSAND_FILLING) { element = Feld[newx][newy] = get_next_element(element); Store[newx][newy] = Store[x][y]; @@ -4146,7 +4111,6 @@ void ContinueMoving(int x, int y) ResetGfxAnimation(x, y); /* reset animation values for old field */ -#if 1 #if 0 /* 2.1.1 (does not work correctly for spring) */ if (!CAN_MOVE(element)) @@ -4168,20 +4132,14 @@ void ContinueMoving(int x, int y) (CAN_FALL(element) && MovDir[newx][newy] == MV_DOWN)) MovDir[newx][newy] = 0; #endif - -#endif #endif DrawLevelField(x, y); DrawLevelField(newx, newy); -#if 0 - if (game.engine_version >= RELEASE_IDENT(2,2,0,7) || !pushing) -#endif - Stop[newx][newy] = TRUE; /* ignore this element until the next frame */ -#if 1 + Stop[newx][newy] = TRUE; /* ignore this element until the next frame */ + if (!pushed) /* special case: moving object pushed by player */ -#endif JustStopped[newx][newy] = 3; if (DONT_TOUCH(element)) /* object may be nasty to player or others */ @@ -4193,15 +4151,15 @@ void ContinueMoving(int x, int y) else if (element == EL_PENGUIN) TestIfFriendTouchesBadThing(newx, newy); -#if 1 if (CAN_FALL(element) && direction == MV_DOWN && (newy == lev_fieldy - 1 || !IS_FREE(x, newy + 1))) Impact(x, newy); -#else - if (CAN_SMASH(element) && direction == MV_DOWN && - (newy == lev_fieldy - 1 || !IS_FREE(x, newy + 1))) - Impact(x, newy); -#endif + + if (!IN_LEV_FIELD(nextx, nexty) || !IS_FREE(nextx, nexty)) + CheckElementChange(newx, newy, element, CE_COLLISION); + + TestIfPlayerTouchesCustomElement(newx, newy); + TestIfElementTouchesCustomElement(newx, newy); } else /* still moving on */ { @@ -5114,40 +5072,14 @@ static void ChangeElementNowExt(int x, int y, int target_element) DrawLevelField(x, y); if (CAN_BE_CRUMBLED(Feld[x][y])) - { - int sx = SCREENX(x), sy = SCREENY(y); - static int xy[4][2] = - { - { 0, -1 }, - { -1, 0 }, - { +1, 0 }, - { 0, +1 } - }; - int i; - - for(i=0; i<4; i++) - { - int xx = x + xy[i][0]; - int yy = y + xy[i][1]; - int sxx = sx + xy[i][0]; - int syy = sy + xy[i][1]; - - if (!IN_LEV_FIELD(xx, yy) || - !IN_SCR_FIELD(sxx, syy) || - !CAN_BE_CRUMBLED(Feld[xx][yy]) || - IS_MOVING(xx, yy)) - continue; - - DrawLevelField(xx, yy); - } - } + DrawLevelFieldCrumbledSandNeighbours(x, y); } static void ChangeElementNow(int x, int y, int element) { struct ElementChangeInfo *change = &element_info[element].change; - CheckTriggeredElementChange(Feld[x][y], CE_OTHER_CHANGING); + CheckTriggeredElementChange(x, y, Feld[x][y], CE_OTHER_IS_CHANGING); if (change->explode) { @@ -5203,12 +5135,17 @@ static void ChangeElementNow(int x, int y, int element) if (!change->only_complete || complete_change) { + if (change->only_complete && change->use_random_change && + RND(change->random) != 0) + return; + for (yy = 0; yy < 3; yy++) for(xx = 0; xx < 3 ; xx++) { int ex = x + xx - 1; int ey = y + yy - 1; - if (can_change[xx][yy]) + if (can_change[xx][yy] && (!change->use_random_change || + RND(change->random) == 0)) { ChangeElementNowExt(ex, ey, change->content[xx][yy]); @@ -5227,7 +5164,11 @@ static void ChangeElementNow(int x, int y, int element) static void ChangeElement(int x, int y) { +#if 1 + int element = MovingOrBlocked2Element(x, y); +#else int element = Feld[x][y]; +#endif struct ElementChangeInfo *change = &element_info[element].change; if (ChangeDelay[x][y] == 0) /* initialize element change */ @@ -5306,21 +5247,25 @@ static void ChangeElement(int x, int y) } } -static void CheckTriggeredElementChange(int trigger_element, int trigger_event) +static boolean CheckTriggeredElementChange(int lx, int ly, int trigger_element, + int trigger_event) { int i, x, y; if (!(trigger_events[trigger_element] & CH_EVENT_BIT(trigger_event))) - return; + return FALSE; for (i=0; iactive) RemoveHero(player); @@ -6368,6 +6320,75 @@ void ScrollScreen(struct PlayerInfo *player, int mode) ScreenMovDir = MV_NO_MOVING; } +void TestIfPlayerTouchesCustomElement(int x, int y) +{ + static int xy[4][2] = + { + { 0, -1 }, + { -1, 0 }, + { +1, 0 }, + { 0, +1 } + }; + boolean center_is_player = (IS_PLAYER(x, y)); + int i; + + for (i=0; i<4; i++) + { + int xx = x + xy[i][0]; + int yy = y + xy[i][1]; + + if (!IN_LEV_FIELD(xx, yy)) + continue; + + if (center_is_player) + { + CheckTriggeredElementChange(xx, yy, Feld[xx][yy], CE_OTHER_GETS_TOUCHED); + CheckElementChange(xx, yy, Feld[xx][yy], CE_TOUCHED_BY_PLAYER); + } + else if (IS_PLAYER(xx, yy)) + { + CheckTriggeredElementChange(x, y, Feld[x][y], CE_OTHER_GETS_TOUCHED); + CheckElementChange(x, y, Feld[x][y], CE_TOUCHED_BY_PLAYER); + + break; + } + } +} + +void TestIfElementTouchesCustomElement(int x, int y) +{ + static int xy[4][2] = + { + { 0, -1 }, + { -1, 0 }, + { +1, 0 }, + { 0, +1 } + }; + boolean center_is_custom = (IS_CUSTOM_ELEMENT(Feld[x][y])); + int i; + + for (i=0; i<4; i++) + { + int xx = x + xy[i][0]; + int yy = y + xy[i][1]; + + if (!IN_LEV_FIELD(xx, yy)) + continue; + + if (center_is_custom && + Feld[xx][yy] == element_info[Feld[x][y]].change.trigger_element) + { + CheckElementChange(x, y, Feld[x][y], CE_OTHER_IS_TOUCHING); + } + + if (IS_CUSTOM_ELEMENT(Feld[xx][yy]) && + Feld[x][y] == element_info[Feld[xx][yy]].change.trigger_element) + { + CheckElementChange(xx, yy, Feld[xx][yy], CE_OTHER_IS_TOUCHING); + } + } +} + void TestIfGoodThingHitsBadThing(int good_x, int good_y, int good_move_dir) { int i, kill_x = -1, kill_y = -1; @@ -7115,7 +7136,7 @@ int DigField(struct PlayerInfo *player, RaiseScoreElement(element); PlaySoundLevelElementAction(x, y, element, ACTION_COLLECTING); - CheckTriggeredElementChange(element, CE_OTHER_COLLECTING); + CheckTriggeredElementChange(x, y, element, CE_OTHER_GETS_COLLECTED); break; } @@ -7205,14 +7226,15 @@ int DigField(struct PlayerInfo *player, if (game.engine_version < RELEASE_IDENT(2,2,0,7)) player->push_delay_value = GET_NEW_PUSH_DELAY(element); - CheckTriggeredElementChange(element, CE_OTHER_PUSHING); - CheckPlayerElementChange(x, y, element, CE_PUSHED_BY_PLAYER); + CheckTriggeredElementChange(x, y, element, CE_OTHER_GETS_PUSHED); + CheckElementChange(x, y, element, CE_PUSHED_BY_PLAYER); break; } else { - CheckPlayerElementChange(x, y, element, CE_PRESSED_BY_PLAYER); + CheckTriggeredElementChange(x, y, element, CE_OTHER_GETS_PRESSED); + CheckElementChange(x, y, element, CE_PRESSED_BY_PLAYER); } return MF_NO_ACTION;