X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Fgame.c;h=f0875a7a1d49fefefeb72cd8cad48bfe3a2b4366;hb=5eadacd4799f667e58a7f5876cf5499e420e6d61;hp=d8eb7353a2f2b6b507c949c23c2751ec6bb03ee6;hpb=7758484aa10294db3689a7eacc9c4b64132d5d6e;p=rocksndiamonds.git diff --git a/src/game.c b/src/game.c index d8eb7353..f0875a7a 100644 --- a/src/game.c +++ b/src/game.c @@ -53,6 +53,12 @@ #define USE_UFAST_PLAYER_EXIT_BUGFIX (USE_NEW_STUFF * 1) +#define USE_GFX_RESET_ONLY_WHEN_MOVING (USE_NEW_STUFF * 1) +#define USE_GFX_RESET_PLAYER_ARTWORK (USE_NEW_STUFF * 1) + +#define USE_FIX_KILLED_BY_NON_WALKABLE (USE_NEW_STUFF * 1) +#define USE_FIX_IMPACT_COLLISION (USE_NEW_STUFF * 1) + /* for DigField() */ #define DF_NO_PUSH 0 @@ -115,8 +121,9 @@ /* values for delayed check of falling and moving elements and for collision */ #define CHECK_DELAY_MOVING 3 -#define CHECK_DELAY_FALLING 3 +#define CHECK_DELAY_FALLING CHECK_DELAY_MOVING #define CHECK_DELAY_COLLISION 2 +#define CHECK_DELAY_IMPACT CHECK_DELAY_COLLISION /* values for initial player move delay (initial delay counter value) */ #define INITIAL_MOVE_DELAY_OFF -1 @@ -1929,8 +1936,10 @@ void InitGame() player->drop_delay = 0; player->drop_pressed_delay = 0; - player->last_jx = player->last_jy = 0; - player->jx = player->jy = 0; + player->last_jx = -1; + player->last_jy = -1; + player->jx = -1; + player->jy = -1; player->shield_normal_time_left = 0; player->shield_deadly_time_left = 0; @@ -2030,6 +2039,7 @@ void InitGame() WasJustMoving[x][y] = 0; WasJustFalling[x][y] = 0; CheckCollision[x][y] = 0; + CheckImpact[x][y] = 0; Stop[x][y] = FALSE; Pushed[x][y] = FALSE; @@ -2445,6 +2455,13 @@ void InitGame() } } +#if 1 + UnmapAllGadgets(); + + MapGameButtons(); + MapTapeButtons(); +#endif + game.restart_level = FALSE; } @@ -2474,7 +2491,7 @@ void InitMovDir(int x, int y) { MV_LEFT, MV_RIGHT, MV_UP, MV_DOWN } }; - switch(element) + switch (element) { case EL_BUG_RIGHT: case EL_BUG_UP: @@ -2793,7 +2810,11 @@ void GameEnd() TapeStop(); #endif +#if 1 + SaveTapeChecked(tape.level_nr); /* ask to save tape */ +#else SaveTape(tape.level_nr); /* ask to save tape */ +#endif } if (level_editor_test_game) @@ -2913,10 +2934,9 @@ int NewHiScore() return position; } -inline static int getElementMoveStepsize(int x, int y) +inline static int getElementMoveStepsizeExt(int x, int y, int direction) { int element = Feld[x][y]; - int direction = MovDir[x][y]; int dx = (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0); int dy = (direction == MV_UP ? -1 : direction == MV_DOWN ? +1 : 0); int horiz_move = (dx != 0); @@ -2936,6 +2956,11 @@ inline static int getElementMoveStepsize(int x, int y) return step; } +inline static int getElementMoveStepsize(int x, int y) +{ + return getElementMoveStepsizeExt(x, y, MovDir[x][y]); +} + void InitPlayerGfxAnimation(struct PlayerInfo *player, int action, int dir) { if (player->GfxAction != action || player->GfxDir != dir) @@ -2996,18 +3021,51 @@ void InitMovingField(int x, int y, int direction) int dy = (direction == MV_UP ? -1 : direction == MV_DOWN ? +1 : 0); int newx = x + dx; int newy = y + dy; + boolean is_moving_before, is_moving_after; +#if 0 + boolean continues_moving = (WasJustMoving[x][y] && direction == MovDir[x][y]); +#endif + + /* check if element was/is moving or being moved before/after mode change */ +#if 1 + is_moving_before = WasJustMoving[x][y]; +#else + is_moving_before = (getElementMoveStepsizeExt(x, y, MovDir[x][y]) != 0); +#endif + is_moving_after = (getElementMoveStepsizeExt(x, y, direction) != 0); - if (!WasJustMoving[x][y] || direction != MovDir[x][y]) + /* reset animation only for moving elements which change direction of moving + or which just started or stopped moving + (else CEs with property "can move" / "not moving" are reset each frame) */ +#if USE_GFX_RESET_ONLY_WHEN_MOVING +#if 1 + if (is_moving_before != is_moving_after || + direction != MovDir[x][y]) + ResetGfxAnimation(x, y); +#else + if ((is_moving_before || is_moving_after) && !continues_moving) ResetGfxAnimation(x, y); +#endif +#else + if (!continues_moving) + ResetGfxAnimation(x, y); +#endif MovDir[x][y] = direction; GfxDir[x][y] = direction; + +#if USE_GFX_RESET_ONLY_WHEN_MOVING + GfxAction[x][y] = (!is_moving_after ? ACTION_WAITING : + direction == MV_DOWN && CAN_FALL(element) ? + ACTION_FALLING : ACTION_MOVING); +#else GfxAction[x][y] = (direction == MV_DOWN && CAN_FALL(element) ? ACTION_FALLING : ACTION_MOVING); +#endif /* this is needed for CEs with property "can move" / "not moving" */ - if (getElementMoveStepsize(x, y) != 0) /* moving or being moved */ + if (is_moving_after) { if (Feld[newx][newy] == EL_EMPTY) Feld[newx][newy] = EL_BLOCKED; @@ -3867,7 +3925,7 @@ void Bang(int x, int y) } } - switch(element) + switch (element) { case EL_BUG: case EL_SPACESHIP: @@ -5579,9 +5637,14 @@ void StartMoving(int x, int y) Store[x][y] = EL_ACID; } - else if ((game.engine_version >= VERSION_IDENT(3,1,0,0) && + else if ( +#if USE_FIX_IMPACT_COLLISION + (game.engine_version >= VERSION_IDENT(3,1,0,0) && + CheckImpact[x][y] && !IS_FREE(x, y + 1)) || +#else + (game.engine_version >= VERSION_IDENT(3,1,0,0) && CheckCollision[x][y] && !IS_FREE(x, y + 1)) || - +#endif (game.engine_version >= VERSION_IDENT(3,0,7,0) && CAN_FALL(element) && WasJustFalling[x][y] && (Feld[x][y + 1] == EL_BLOCKED || IS_PLAYER(x, y + 1))) || @@ -5601,6 +5664,7 @@ void StartMoving(int x, int y) simply not covered here... :-/ ) */ CheckCollision[x][y] = 0; + CheckImpact[x][y] = 0; Impact(x, y); } @@ -6545,6 +6609,11 @@ void ContinueMoving(int x, int y) if ((!CAN_FALL(element) || direction == MV_DOWN) && check_collision_again) CheckCollision[newx][newy] = CHECK_DELAY_COLLISION; + +#if USE_FIX_IMPACT_COLLISION + if (CAN_FALL(element) && direction == MV_DOWN && check_collision_again) + CheckImpact[newx][newy] = CHECK_DELAY_IMPACT; +#endif } if (DONT_TOUCH(element)) /* object may be nasty to player or others */ @@ -6612,7 +6681,7 @@ void ContinueMoving(int x, int y) if (IS_CUSTOM_ELEMENT(element) && ei->move_enter_element != EL_EMPTY && IS_EQUAL_OR_IN_GROUP(stored_new, ei->move_enter_element)) CheckElementChangeBySide(newx, newy, element, stored_new, CE_DIGGING_X, - MV_DIR_OPPOSITE(direction)); + MV_DIR_OPPOSITE(direction)); } int AmoebeNachbarNr(int ax, int ay) @@ -7219,7 +7288,7 @@ static void CloseAllOpenTimegates() } } -void EdelsteinFunkeln(int x, int y) +void DrawTwinkleOnField(int x, int y) { if (!IN_SCR_FIELD(SCREENX(x), SCREENY(y)) || IS_MOVING(x, y)) return; @@ -7662,7 +7731,7 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) /* ---------- execute action -------------------------------------------- */ - switch(action_type) + switch (action_type) { case CA_NO_ACTION: { @@ -7890,6 +7959,11 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) (level.use_artwork_element[i] ? level.artwork_element[i] : stored_player[i].element_nr); +#if USE_GFX_RESET_PLAYER_ARTWORK + if (stored_player[i].artwork_element != artwork_element) + stored_player[i].Frame = 0; +#endif + stored_player[i].artwork_element = artwork_element; SetPlayerWaiting(&stored_player[i], FALSE); @@ -7997,6 +8071,7 @@ static void CreateFieldExt(int x, int y, int element, boolean is_change) #if USE_NEW_CUSTOM_VALUE int last_ce_value = CustomValue[x][y]; #endif + boolean player_explosion_protected = PLAYER_EXPLOSION_PROTECTED(x, y); boolean new_element_is_player = ELEM_IS_PLAYER(new_element); boolean add_player_onto_element = (new_element_is_player && #if USE_CODE_THAT_BREAKS_SNAKE_BITE @@ -8060,6 +8135,15 @@ static void CreateFieldExt(int x, int y, int element, boolean is_change) /* check if element under the player changes from accessible to unaccessible (needed for special case of dropping element which then changes) */ /* (must be checked after creating new element for walkable group elements) */ +#if USE_FIX_KILLED_BY_NON_WALKABLE + if (IS_PLAYER(x, y) && !player_explosion_protected && + IS_ACCESSIBLE(old_element) && !IS_ACCESSIBLE(new_element)) + { + Bang(x, y); + + return; + } +#else if (IS_PLAYER(x, y) && !PLAYER_EXPLOSION_PROTECTED(x, y) && IS_ACCESSIBLE(old_element) && !IS_ACCESSIBLE(new_element)) { @@ -8067,6 +8151,7 @@ static void CreateFieldExt(int x, int y, int element, boolean is_change) return; } +#endif #endif /* "ChangeCount" not set yet to allow "entered by player" change one time */ @@ -8573,10 +8658,18 @@ static boolean CheckElementChangeExt(int x, int y, { struct ElementChangeInfo *change = &element_info[element].change_page[p]; + /* check trigger element for all events where the element that is checked + for changing interacts with a directly adjacent element -- this is + different to element changes that affect other elements to change on the + whole playfield (which is handeld by CheckTriggeredElementChangeExt()) */ boolean check_trigger_element = (trigger_event == CE_TOUCHING_X || trigger_event == CE_HITTING_X || - trigger_event == CE_HIT_BY_X); + trigger_event == CE_HIT_BY_X || +#if 1 + /* this one was forgotten until 3.2.3 */ + trigger_event == CE_DIGGING_X); +#endif if (change->can_change_or_has_action && change->has_event[trigger_event] && @@ -9350,6 +9443,8 @@ void GameActions_RND() WasJustFalling[x][y]--; if (CheckCollision[x][y] > 0) CheckCollision[x][y]--; + if (CheckImpact[x][y] > 0) + CheckImpact[x][y]--; GfxFrame[x][y]++; @@ -9434,7 +9529,7 @@ void GameActions_RND() DrawLevelGraphicAnimationIfNeeded(x, y, graphic); if (IS_GEM(element) || element == EL_SP_INFOTRON) - EdelsteinFunkeln(x, y); + DrawTwinkleOnField(x, y); } else if ((element == EL_ACID || element == EL_EXIT_OPEN || @@ -11986,7 +12081,13 @@ boolean DropElement(struct PlayerInfo *player) nexty = dropy + GET_DY_FROM_DIR(move_direction); ChangeCount[dropx][dropy] = 0; /* allow at least one more change */ + +#if USE_FIX_IMPACT_COLLISION + /* do not cause impact style collision by dropping elements that can fall */ + CheckCollision[dropx][dropy] = CHECK_DELAY_COLLISION; +#else CheckCollision[dropx][dropy] = CHECK_DELAY_COLLISION; +#endif } player->drop_delay = GET_NEW_DROP_DELAY(drop_element); @@ -12313,7 +12414,7 @@ void RaiseScore(int value) void RaiseScoreElement(int element) { - switch(element) + switch (element) { case EL_EMERALD: case EL_BD_DIAMOND: @@ -12612,6 +12713,9 @@ void SaveEngineSnapshot() { FreeEngineSnapshot(); /* free previous snapshot, if needed */ + if (level_editor_test_game) /* do not save snapshots from editor */ + return; + /* copy some special values to a structure better suited for the snapshot */ SaveEngineSnapshotValues_RND(); @@ -12665,6 +12769,7 @@ void SaveEngineSnapshot() SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(WasJustMoving)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(WasJustFalling)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(CheckCollision)); + SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(CheckImpact)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(Stop)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(Pushed));