X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Fgame.c;h=30af0fcbbd7a50affb604b234f7da58d87e9e1bd;hb=842f9050c68d9c9f0741e444a052e00cf81ee90b;hp=88f2c53c32bbd122c54a991945d68e413a513040;hpb=aacdd16335c68a011fab047272b828792a2a884e;p=rocksndiamonds.git diff --git a/src/game.c b/src/game.c index 88f2c53c..30af0fcb 100644 --- a/src/game.c +++ b/src/game.c @@ -107,7 +107,7 @@ (condition))) #define ELEMENT_CAN_ENTER_FIELD(e, x, y) \ - ELEMENT_CAN_ENTER_FIELD_GENERIC(e, x, y, 1) + ELEMENT_CAN_ENTER_FIELD_GENERIC(e, x, y, 0) #define ELEMENT_CAN_ENTER_FIELD_OR_ACID(e, x, y) \ ELEMENT_CAN_ENTER_FIELD_GENERIC(e, x, y, (Feld[x][y] == EL_ACID)) @@ -750,6 +750,33 @@ static void InitGameEngine() if (HAS_CHANGE_EVENT(i, CE_BY_OTHER)) trigger_events[element_info[i].change.trigger] |= element_info[i].change.events; + + /* set push delay value for all non-custom elements */ + for (i=0; iPushing && player->MovPos != 0); +#else boolean pushing = (player != NULL && player->Pushing && player->is_moving); +#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; @@ -3819,13 +3876,27 @@ void ContinueMoving(int x, int y) MovPos[x][y] += step; #if 1 +#if 1 + if (Pushed[x][y]) /* 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 (pushing) - printf("::: OOPS! pushing '%s'\n", element_info[element].token_name); + 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 */ @@ -3903,6 +3974,16 @@ void ContinueMoving(int x, int y) Feld[x][y] = get_next_element(element); element = Feld[newx][newy] = Store[x][y]; } + else if (element == EL_SOKOBAN_OBJECT) + { + if (Back[x][y]) + Feld[x][y] = Back[x][y]; + + if (Back[newx][newy]) + Feld[newx][newy] = EL_SOKOBAN_FIELD_FULL; + + Back[x][y] = Back[newx][newy] = 0; + } else if (Store[x][y] == EL_ACID) { element = Feld[newx][newy] = EL_ACID; @@ -3920,22 +4001,34 @@ void ContinueMoving(int x, int y) GfxAction[newx][newy] = GfxAction[x][y]; /* keep action one frame */ GfxRandom[newx][newy] = GfxRandom[x][y]; /* keep same random value */ + Pushed[x][y] = Pushed[newx][newy] = FALSE; + 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)) MovDir[newx][newy] = 0; #else - /* + +#if 0 + /* (does not work for falling objects that slide horizontally) */ if (CAN_FALL(element) && MovDir[newx][newy] == MV_DOWN) MovDir[newx][newy] = 0; +#else + /* + if (!CAN_MOVE(element) || + (element == EL_SPRING && MovDir[newx][newy] == MV_DOWN)) + MovDir[newx][newy] = 0; */ if (!CAN_MOVE(element) || - (element == EL_SPRING && MovDir[newx][newy] == MV_DOWN)) + (CAN_FALL(element) && MovDir[newx][newy] == MV_DOWN)) MovDir[newx][newy] = 0; #endif + +#endif #endif DrawLevelField(x, y); @@ -4991,7 +5084,12 @@ static void CheckPlayerElementChange(int x, int y, int element, if (!CAN_CHANGE(element) || !HAS_CHANGE_EVENT(element, trigger_event)) return; +#if 1 + ChangeDelay[x][y] = 1; + ChangeElement(x, y); +#else ChangeElementDoIt(x, y, element_info[element].change.successor); +#endif } static void PlayerActions(struct PlayerInfo *player, byte player_action) @@ -6347,6 +6445,7 @@ static boolean checkDiagonalPushing(struct PlayerInfo *player, int DigField(struct PlayerInfo *player, int x, int y, int real_dx, int real_dy, int mode) { + boolean use_spring_bug = (game.engine_version < VERSION_IDENT(2,2,0)); int jx = player->jx, jy = player->jy; int dx = x - jx, dy = y - jy; int move_direction = (dx == -1 ? MV_LEFT : @@ -6741,6 +6840,8 @@ int DigField(struct PlayerInfo *player, return MF_ACTION; break; +#if 0 + /* the following elements cannot be pushed by "snapping" */ case EL_ROCK: case EL_BOMB: @@ -6760,6 +6861,10 @@ int DigField(struct PlayerInfo *player, if (dy) return MF_NO_ACTION; + if (CAN_FALL(element) && IN_LEV_FIELD(x, y + 1) && IS_FREE(x, y + 1) && + !(element == EL_SPRING && use_spring_bug)) + return MF_NO_ACTION; + player->Pushing = TRUE; #if 0 @@ -6817,11 +6922,13 @@ int DigField(struct PlayerInfo *player, FrameCounter, player->push_delay_value); #endif +#if 0 if (element == EL_SPRING) { Feld[x + dx][y + dy] = EL_SPRING; MovDir[x + dx][y + dy] = move_direction; } +#endif player->push_delay_value = (element == EL_SPRING ? 0 : 2 + RND(8)); @@ -6832,6 +6939,8 @@ int DigField(struct PlayerInfo *player, break; +#endif + case EL_GATE_1: case EL_GATE_2: case EL_GATE_3: @@ -7016,6 +7125,8 @@ int DigField(struct PlayerInfo *player, return MF_ACTION; break; +#if 0 + #if 0 case EL_SOKOBAN_FIELD_EMPTY: break; @@ -7055,6 +7166,44 @@ int DigField(struct PlayerInfo *player, if (IS_SB_ELEMENT(element)) { +#if 1 + if (element == EL_SOKOBAN_FIELD_FULL) + { + Back[x][y] = EL_SOKOBAN_FIELD_EMPTY; + local_player->sokobanfields_still_needed++; + } + + if (Feld[x + dx][y + dy] == EL_SOKOBAN_FIELD_EMPTY) + { + Back[x + dx][y + dy] = EL_SOKOBAN_FIELD_EMPTY; + local_player->sokobanfields_still_needed--; + } + + Feld[x][y] = EL_SOKOBAN_OBJECT; + + if (Back[x][y] == Back[x + dx][y + dy]) + PlaySoundLevelAction(x, y, ACTION_PUSHING); + else if (Back[x][y] != 0) + PlaySoundLevelElementAction(x, y, EL_SOKOBAN_FIELD_FULL, + ACTION_EMPTYING); + else + PlaySoundLevelElementAction(x + dx, y + dy, EL_SOKOBAN_FIELD_EMPTY, + ACTION_FILLING); + + InitMovingField(x, y, (dx < 0 ? MV_LEFT : + dx > 0 ? MV_RIGHT : + dy < 0 ? MV_UP : MV_DOWN)); + MovPos[x][y] = (dx != 0 ? dx : dy); + +#if 0 + printf("::: %s -> %s [%s -> %s]\n", + element_info[Feld[x][y]].token_name, + element_info[Feld[x + dx][y + dy]].token_name, + element_info[Back[x][y]].token_name, + element_info[Back[x + dx][y + dy]].token_name); +#endif + +#else if (element == EL_SOKOBAN_FIELD_FULL) { Feld[x][y] = EL_SOKOBAN_FIELD_EMPTY; @@ -7096,11 +7245,19 @@ int DigField(struct PlayerInfo *player, PlaySoundLevel(x, y, SND_SOKOBAN_OBJECT_PUSHING); #endif } +#endif } else { +#if 1 + InitMovingField(x, y, (dx < 0 ? MV_LEFT : + dx > 0 ? MV_RIGHT : + dy < 0 ? MV_UP : MV_DOWN)); + MovPos[x][y] = (dx != 0 ? dx : dy); +#else RemoveField(x, y); - Feld[x+dx][y+dy] = element; + Feld[x + dx][y + dy] = element; +#endif PlaySoundLevelElementAction(x, y, element, ACTION_PUSHING); } @@ -7121,6 +7278,8 @@ int DigField(struct PlayerInfo *player, break; +#endif + case EL_PENGUIN: case EL_PIG: case EL_DRAGON: @@ -7168,19 +7327,29 @@ int DigField(struct PlayerInfo *player, } else if (IS_PUSHABLE(element)) { - if (mode == DF_SNAP) + if (mode == DF_SNAP && element != EL_BD_ROCK) return MF_NO_ACTION; if (CAN_FALL(element) && dy) return MF_NO_ACTION; + if (CAN_FALL(element) && IN_LEV_FIELD(x, y + 1) && IS_FREE(x, y + 1) && + !(element == EL_SPRING && use_spring_bug)) + return MF_NO_ACTION; + + if (element == EL_SPRING && MovDir[x][y] != MV_NO_MOVING) + return MF_NO_ACTION; + if (!player->Pushing && game.engine_version >= RELEASE_IDENT(2,2,0,7)) player->push_delay_value = GET_NEW_PUSH_DELAY(element); player->Pushing = TRUE; - if (!IN_LEV_FIELD(x + dx, y + dy) || !IS_FREE(x + dx, y + dy)) + if (!(IN_LEV_FIELD(x + dx, y + dy) && + (IS_FREE(x + dx, y + dy) || + (Feld[x + dx][y + dy] == EL_SOKOBAN_FIELD_EMPTY && + IS_SB_ELEMENT(element))))) return MF_NO_ACTION; if (!checkDiagonalPushing(player, x, y, real_dx, real_dy)) @@ -7190,31 +7359,60 @@ int DigField(struct PlayerInfo *player, player->push_delay = FrameCounter; if (!FrameReached(&player->push_delay, player->push_delay_value) && - !(tape.playing && tape.file_version < FILE_VERSION_2_0)) + !(tape.playing && tape.file_version < FILE_VERSION_2_0) && + element != EL_SPRING && element != EL_BALLOON) return MF_NO_ACTION; -#if 1 - InitMovingField(x, y, (dx < 0 ? MV_LEFT : - dx > 0 ? MV_RIGHT : - dy < 0 ? MV_UP : MV_DOWN)); - MovPos[x][y] = (dx != 0 ? dx : dy); -#else - RemoveField(x, y); - Feld[x + dx][y + dy] = element; -#endif + if (IS_SB_ELEMENT(element)) + { + if (element == EL_SOKOBAN_FIELD_FULL) + { + Back[x][y] = EL_SOKOBAN_FIELD_EMPTY; + local_player->sokobanfields_still_needed++; + } + + if (Feld[x + dx][y + dy] == EL_SOKOBAN_FIELD_EMPTY) + { + Back[x + dx][y + dy] = EL_SOKOBAN_FIELD_EMPTY; + local_player->sokobanfields_still_needed--; + } + + Feld[x][y] = EL_SOKOBAN_OBJECT; + + if (Back[x][y] == Back[x + dx][y + dy]) + PlaySoundLevelAction(x, y, ACTION_PUSHING); + else if (Back[x][y] != 0) + PlaySoundLevelElementAction(x, y, EL_SOKOBAN_FIELD_FULL, + ACTION_EMPTYING); + else + PlaySoundLevelElementAction(x + dx, y + dy, EL_SOKOBAN_FIELD_EMPTY, + ACTION_FILLING); + + if (local_player->sokobanfields_still_needed == 0 && + game.emulation == EMU_SOKOBAN) + { + player->LevelSolved = player->GameOver = TRUE; + PlaySoundLevel(x, y, SND_GAME_SOKOBAN_SOLVING); + } + } + else + PlaySoundLevelElementAction(x, y, element, ACTION_PUSHING); + + InitMovingField(x, y, move_direction); + + if (mode == DF_SNAP) + ContinueMoving(x, y); + else + MovPos[x][y] = (dx != 0 ? dx : dy); + + Pushed[x][y] = TRUE; + Pushed[x + dx][y + dy] = TRUE; -#if 1 if (game.engine_version < RELEASE_IDENT(2,2,0,7)) player->push_delay_value = GET_NEW_PUSH_DELAY(element); -#else - player->push_delay_value = 2 + RND(8); -#endif - - DrawLevelField(x + dx, y + dy); - PlaySoundLevelElementAction(x, y, element, ACTION_PUSHING); CheckTriggeredElementChange(element, CE_OTHER_PUSHING); - CheckPlayerElementChange(x + dx, y + dy, element, CE_PUSHED_BY_PLAYER); + CheckPlayerElementChange(x, y, element, CE_PUSHED_BY_PLAYER); break; }