X-Git-Url: https://git.artsoft.org/?p=rocksndiamonds.git;a=blobdiff_plain;f=src%2Fgame.c;h=4e4c901c990286248b043614b2716d243a3d822e;hp=837d41036992abab6a31ddacf701f4de7c409f49;hb=c0c5862d9ee59c70412b1c35e558101b109a8ec9;hpb=f2d0f3fed679ea3573f51aa298adce2d9a78d8be diff --git a/src/game.c b/src/game.c index 837d4103..4e4c901c 100644 --- a/src/game.c +++ b/src/game.c @@ -44,9 +44,17 @@ #define USE_GFX_RESET_GFX_ANIMATION (USE_NEW_STUFF * 1) #define USE_BOTH_SWITCHGATE_SWITCHES (USE_NEW_STUFF * 1) #define USE_PLAYER_GRAVITY (USE_NEW_STUFF * 1) +#define USE_FIXED_BORDER_RUNNING_GFX (USE_NEW_STUFF * 1) +#define USE_QUICKSAND_BD_ROCK_BUGFIX (USE_NEW_STUFF * 0) #define USE_QUICKSAND_IMPACT_BUGFIX (USE_NEW_STUFF * 0) +#define USE_CODE_THAT_BREAKS_SNAKE_BITE (USE_NEW_STUFF * 1) + +#define USE_UFAST_PLAYER_EXIT_BUGFIX (USE_NEW_STUFF * 1) +#define USE_NEW_GAME_WON (USE_NEW_STUFF * 1) + + /* for DigField() */ #define DF_NO_PUSH 0 #define DF_DIG 1 @@ -72,6 +80,28 @@ #define EX_TYPE_DYNA (1 << 4) #define EX_TYPE_SINGLE_TILE (EX_TYPE_CENTER | EX_TYPE_BORDER) +#if 1 + +#define PANEL_DEACTIVATED(p) ((p).x < 0 || (p).y < 0) + +/* special positions in the game control window (relative to control window) */ +#define XX_LEVEL1 (game.panel.level.x) +#define XX_LEVEL2 (game.panel.level.x - 1) +#define YY_LEVEL (game.panel.level.y) +#define XX_EMERALDS (game.panel.gems.x) +#define YY_EMERALDS (game.panel.gems.y) +#define XX_DYNAMITE (game.panel.inventory.x) +#define YY_DYNAMITE (game.panel.inventory.y) +#define XX_KEYS (game.panel.keys.x) +#define YY_KEYS (game.panel.keys.y) +#define XX_SCORE (game.panel.score.x) +#define YY_SCORE (game.panel.score.y) +#define XX_TIME1 (game.panel.time.x) +#define XX_TIME2 (game.panel.time.x + 1) +#define YY_TIME (game.panel.time.y) + +#else + /* special positions in the game control window (relative to control window) */ #define XX_LEVEL 37 #define YY_LEVEL 20 @@ -87,8 +117,11 @@ #define XX_TIME2 30 #define YY_TIME 194 +#endif + /* special positions in the game control window (relative to main window) */ -#define DX_LEVEL (DX + XX_LEVEL) +#define DX_LEVEL1 (DX + XX_LEVEL1) +#define DX_LEVEL2 (DX + XX_LEVEL2) #define DY_LEVEL (DY + YY_LEVEL) #define DX_EMERALDS (DX + XX_EMERALDS) #define DY_EMERALDS (DY + YY_EMERALDS) @@ -162,13 +195,21 @@ ((e) >= NUM_FILE_ELEMENTS ? EL_UNKNOWN : (e)) #endif -#define GET_TARGET_ELEMENT(e, ch, cv, cs) \ +#define RESOLVED_REFERENCE_ELEMENT(be, e) \ + ((be) + (e) - EL_SELF < EL_CUSTOM_START ? EL_CUSTOM_START : \ + (be) + (e) - EL_SELF > EL_CUSTOM_END ? EL_CUSTOM_END : \ + (be) + (e) - EL_SELF) + +#define GET_TARGET_ELEMENT(be, e, ch, cv, cs) \ ((e) == EL_TRIGGER_PLAYER ? (ch)->actual_trigger_player : \ (e) == EL_TRIGGER_ELEMENT ? (ch)->actual_trigger_element : \ (e) == EL_TRIGGER_CE_VALUE ? (ch)->actual_trigger_ce_value : \ (e) == EL_TRIGGER_CE_SCORE ? (ch)->actual_trigger_ce_score : \ (e) == EL_CURRENT_CE_VALUE ? (cv) : \ - (e) == EL_CURRENT_CE_SCORE ? (cs) : (e)) + (e) == EL_CURRENT_CE_SCORE ? (cs) : \ + (e) >= EL_LAST_CE_8 && (e) <= EL_NEXT_CE_8 ? \ + RESOLVED_REFERENCE_ELEMENT(be, e) : \ + (e)) #define CAN_GROW_INTO(e) \ ((e) == EL_SAND || (IS_DIGGABLE(e) && level.grow_into_diggable)) @@ -1196,6 +1237,7 @@ static void InitField(int x, int y, boolean init_game) InitField(x, y, init_game); #endif } + break; } @@ -1254,6 +1296,9 @@ inline void DrawGameValue_Emeralds(int value) { int xpos = (3 * 14 - 3 * getFontWidth(FONT_TEXT_2)) / 2; + if (PANEL_DEACTIVATED(game.panel.gems)) + return; + DrawText(DX_EMERALDS + xpos, DY_EMERALDS, int2str(value, 3), FONT_TEXT_2); } @@ -1261,6 +1306,9 @@ inline void DrawGameValue_Dynamite(int value) { int xpos = (3 * 14 - 3 * getFontWidth(FONT_TEXT_2)) / 2; + if (PANEL_DEACTIVATED(game.panel.inventory)) + return; + DrawText(DX_DYNAMITE + xpos, DY_DYNAMITE, int2str(value, 3), FONT_TEXT_2); } @@ -1269,19 +1317,23 @@ inline void DrawGameValue_Keys(int key[MAX_NUM_KEYS]) int base_key_graphic = EL_KEY_1; int i; + if (PANEL_DEACTIVATED(game.panel.keys)) + return; + if (level.game_engine_type == GAME_ENGINE_TYPE_EM) base_key_graphic = EL_EM_KEY_1; /* currently only 4 of 8 possible keys are displayed */ for (i = 0; i < STD_NUM_KEYS; i++) { + int x = XX_KEYS + i * MINI_TILEX; + int y = YY_KEYS; + if (key[i]) - DrawMiniGraphicExt(drawto, DX_KEYS + i * MINI_TILEX, DY_KEYS, - el2edimg(base_key_graphic + i)); + DrawMiniGraphicExt(drawto, DX + x,DY + y, el2edimg(base_key_graphic + i)); else BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto, - DOOR_GFX_PAGEX5 + XX_KEYS + i * MINI_TILEX, YY_KEYS, - MINI_TILEX, MINI_TILEY, DX_KEYS + i * MINI_TILEX, DY_KEYS); + DOOR_GFX_PAGEX5 + x, y, MINI_TILEX, MINI_TILEY, DX + x,DY + y); } } @@ -1289,6 +1341,9 @@ inline void DrawGameValue_Score(int value) { int xpos = (5 * 14 - 5 * getFontWidth(FONT_TEXT_2)) / 2; + if (PANEL_DEACTIVATED(game.panel.score)) + return; + DrawText(DX_SCORE + xpos, DY_SCORE, int2str(value, 5), FONT_TEXT_2); } @@ -1297,9 +1352,12 @@ inline void DrawGameValue_Time(int value) int xpos3 = (3 * 14 - 3 * getFontWidth(FONT_TEXT_2)) / 2; int xpos4 = (4 * 10 - 4 * getFontWidth(FONT_LEVEL_NUMBER)) / 2; + if (PANEL_DEACTIVATED(game.panel.time)) + return; + /* clear background if value just changed its size */ if (value == 999 || value == 1000) - ClearRectangle(drawto, DX_TIME1, DY_TIME, 14 * 3, 14); + ClearRectangleOnBackground(drawto, DX_TIME1, DY_TIME, 14 * 3, 14); if (value < 1000) DrawText(DX_TIME1 + xpos3, DY_TIME, int2str(value, 3), FONT_TEXT_2); @@ -1309,9 +1367,15 @@ inline void DrawGameValue_Time(int value) inline void DrawGameValue_Level(int value) { + if (PANEL_DEACTIVATED(game.panel.level)) + return; + if (level_nr < 100) - DrawText(DX_LEVEL, DY_LEVEL, int2str(value, 2), FONT_TEXT_2); + DrawText(DX_LEVEL1, DY_LEVEL, int2str(value, 2), FONT_TEXT_2); else +#if 1 + DrawText(DX_LEVEL2, DY_LEVEL, int2str(value, 3), FONT_LEVEL_NUMBER); +#else { /* misuse area for displaying emeralds to draw bigger level number */ DrawTextExt(drawto, DX_EMERALDS, DY_EMERALDS, @@ -1329,6 +1393,7 @@ inline void DrawGameValue_Level(int value) /* yes, this is all really ugly :-) */ } +#endif } void DrawAllGameValues(int emeralds, int dynamite, int score, int time, @@ -1352,6 +1417,7 @@ void DrawAllGameValues(int emeralds, int dynamite, int score, int time, void DrawGameDoorValues() { + int time_value = (level.time == 0 ? TimePlayed : TimeLeft); int dynamite_state = 0; int key_bits = 0; int i, j; @@ -1400,7 +1466,7 @@ void DrawGameDoorValues() } DrawAllGameValues(local_player->gems_still_needed, dynamite_state, - local_player->score, TimeLeft, key_bits); + local_player->score, time_value, key_bits); #endif } @@ -1450,6 +1516,18 @@ static void resolve_group_element(int group_element, int recursion_depth) } #endif +#if 0 +static void replace_reference_element(int base_element, int *element) +{ + if (*element >= EL_LAST_CE_8 && *element <= EL_NEXT_CE_8) + { + *element = base_element + *element - EL_SELF; + *element = (*element < EL_CUSTOM_START ? EL_CUSTOM_START : + *element > EL_CUSTOM_END ? EL_CUSTOM_END : *element); + } +} +#endif + /* ============================================================================= InitGameEngine() @@ -1752,6 +1830,11 @@ static void InitGameEngine() for (l = 0; l < group->num_elements_resolved; l++) trigger_events[group->element_resolved[l]][k] = TRUE; } +#if 1 + else if (trigger_element == EL_ANY_ELEMENT) + for (l = 0; l < MAX_NUM_ELEMENTS; l++) + trigger_events[l][k] = TRUE; +#endif else trigger_events[trigger_element][k] = TRUE; } @@ -1767,8 +1850,22 @@ static void InitGameEngine() { if (!IS_CUSTOM_ELEMENT(i)) { +#if 1 + /* set default push delay values (corrected since version 3.0.7-1) */ + if (game.engine_version < VERSION_IDENT(3,0,7,1)) + { + element_info[i].push_delay_fixed = 2; + element_info[i].push_delay_random = 8; + } + else + { + element_info[i].push_delay_fixed = 8; + element_info[i].push_delay_random = 8; + } +#else element_info[i].push_delay_fixed = game.default_push_delay_fixed; element_info[i].push_delay_random = game.default_push_delay_random; +#endif } } @@ -1875,6 +1972,29 @@ static void InitGameEngine() EL_EMPTY); } } + +#if 0 + /* ---------- initialize reference elements ------------------------------- */ + for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) + { + int element = EL_CUSTOM_START + i; + struct ElementInfo *ei = &element_info[element]; + + for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) + replace_reference_element(element, &ei->content.e[x][y]); + + for (j = 0; j < ei->num_change_pages; j++) + { + struct ElementChangeInfo *change = &ei->change_page[j]; + + replace_reference_element(element, &change->target_element); + replace_reference_element(element, &change->trigger_element); + + for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) + replace_reference_element(element, &change->target_content.e[x][y]); + } + } +#endif } int get_num_special_action(int element, int action_first, int action_last) @@ -1917,8 +2037,11 @@ void InitGame() boolean emulate_bd = TRUE; /* unless non-BOULDERDASH elements found */ boolean emulate_sb = TRUE; /* unless non-SOKOBAN elements found */ boolean emulate_sp = TRUE; /* unless non-SUPAPLEX elements found */ + boolean do_fading = (game_status == GAME_MODE_MAIN); int i, j, x, y; + game_status = GAME_MODE_PLAYING; + InitGameEngine(); /* don't play tapes over network */ @@ -1979,6 +2102,8 @@ void InitGame() player->last_move_dir = MV_NONE; + player->is_active = FALSE; + player->is_waiting = FALSE; player->is_moving = FALSE; player->is_auto_moving = FALSE; @@ -2058,6 +2183,10 @@ void InitGame() player->LevelSolved = FALSE; player->GameOver = FALSE; + + player->LevelSolved_GameEnd = FALSE; + player->LevelSolved_SaveTape = FALSE; + player->LevelSolved_SaveScore = FALSE; } network_player_action_received = FALSE; @@ -2503,9 +2632,14 @@ void InitGame() local_player->jy - MIDPOSY); } + StopAnimation(); + if (!game.restart_level) CloseDoor(DOOR_CLOSE_1); + if (do_fading) + FadeOut(REDRAW_FIELD); + /* !!! FIX THIS (START) !!! */ if (level.game_engine_type == GAME_ENGINE_TYPE_EM) { @@ -2524,10 +2658,16 @@ void InitGame() BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY); redraw_mask |= REDRAW_FROM_BACKBUFFER; + +#if 0 FadeToFront(); +#endif } /* !!! FIX THIS (END) !!! */ + if (do_fading) + FadeIn(REDRAW_FIELD); + if (!game.restart_level) { /* copy default game door content to main double buffer */ @@ -2535,6 +2675,11 @@ void InitGame() DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, DX, DY); } +#if 1 + SetPanelBackground(); + SetDrawBackgroundMask(REDRAW_DOOR_1); +#endif + DrawGameDoorValues(); if (!game.restart_level) @@ -2778,6 +2923,194 @@ void InitAmoebaNr(int x, int y) AmoebaCnt2[group_nr]++; } +#if USE_NEW_GAME_WON + +void GameWon() +{ + static boolean score_done = FALSE; + static boolean player_done = FALSE; + static int game_over_delay = 0; + int game_over_delay_value = 50; + + /* do not start end game actions before the player stops moving (to exit) */ + if (local_player->MovPos) + return; + + if (tape.auto_play) /* tape might already be stopped here */ + tape.auto_play_level_solved = TRUE; + + if (!local_player->LevelSolved_GameEnd) + { + local_player->LevelSolved_GameEnd = TRUE; + local_player->LevelSolved_SaveTape = tape.recording; + local_player->LevelSolved_SaveScore = !tape.playing; + + score_done = FALSE; + player_done = FALSE; + game_over_delay = 0; + } + + PlaySoundStereo(SND_GAME_WINNING, SOUND_MIDDLE); + + if (TimeLeft > 0) + { + if (!tape.playing) + { + if (setup.sound_loops) + PlaySoundExt(SND_GAME_LEVELTIME_BONUS, SOUND_MAX_VOLUME, SOUND_MIDDLE, + SND_CTRL_PLAY_LOOP); + else + PlaySoundStereo(SND_GAME_LEVELTIME_BONUS, SOUND_MIDDLE); + } + + if (TimeLeft > 100 && TimeLeft % 10 == 0) + { + TimeLeft -= 10; + RaiseScore(level.score[SC_TIME_BONUS] * 10); + } + else + { + TimeLeft--; + RaiseScore(level.score[SC_TIME_BONUS]); + } + + DrawGameValue_Time(TimeLeft); + +#if 0 + if (!tape.playing) + Delay(10); +#endif + + if (TimeLeft <= 0 && !tape.playing && setup.sound_loops) + StopSound(SND_GAME_LEVELTIME_BONUS); + } + else if (level.time == 0 && TimePlayed < 999) /* level without time limit */ + { + if (!tape.playing) + { + if (setup.sound_loops) + PlaySoundExt(SND_GAME_LEVELTIME_BONUS, SOUND_MAX_VOLUME, SOUND_MIDDLE, + SND_CTRL_PLAY_LOOP); + else + PlaySoundStereo(SND_GAME_LEVELTIME_BONUS, SOUND_MIDDLE); + } + + if (TimePlayed < 900 && TimePlayed % 10 == 0) + { + TimePlayed += 10; + RaiseScore(level.score[SC_TIME_BONUS] * 10); + } + else + { + TimePlayed++; + RaiseScore(level.score[SC_TIME_BONUS]); + } + + DrawGameValue_Time(TimePlayed); + + if (TimePlayed >= 999 && !tape.playing && setup.sound_loops) + StopSound(SND_GAME_LEVELTIME_BONUS); + } + else + { + score_done = TRUE; + } + + /* close exit door after last player */ + if (AllPlayersGone && ExitX >= 0 && ExitY >= 0 && + (Feld[ExitX][ExitY] == EL_EXIT_OPEN || + Feld[ExitX][ExitY] == EL_SP_EXIT_OPEN)) + { + int element = Feld[ExitX][ExitY]; + + Feld[ExitX][ExitY] = (element == EL_EXIT_OPEN ? EL_EXIT_CLOSING : + EL_SP_EXIT_CLOSING); + + PlayLevelSoundElementAction(ExitX, ExitY, element, ACTION_CLOSING); + } + + /* player disappears */ + if (ExitX >= 0 && ExitY >= 0 && !player_done) + { + DrawLevelField(ExitX, ExitY); + + player_done = TRUE; + } + + game_over_delay++; + + if (game_over_delay < game_over_delay_value || !score_done) + return; +} + +void GameEnd() +{ + int hi_pos; + boolean raise_level = FALSE; + + CloseDoor(DOOR_CLOSE_1); + + if (local_player->LevelSolved_SaveTape) + { + TapeStop(); + + SaveTape(tape.level_nr); /* Ask to save tape */ + } + + if (!local_player->LevelSolved_SaveScore) + { + FadeOut(REDRAW_FIELD); + + game_status = GAME_MODE_MAIN; + + DrawAndFadeInMainMenu(REDRAW_FIELD); + + return; + } + + if (level_nr == leveldir_current->handicap_level) + { + leveldir_current->handicap_level++; + SaveLevelSetup_SeriesInfo(); + } + + if (level_editor_test_game) + local_player->score = -1; /* no highscore when playing from editor */ + else if (level_nr < leveldir_current->last_level) + raise_level = TRUE; /* advance to next level */ + + if ((hi_pos = NewHiScore()) >= 0) + { + game_status = GAME_MODE_SCORES; + + DrawHallOfFame(hi_pos); + + if (raise_level) + { + level_nr++; + TapeErase(); + } + } + else + { + FadeOut(REDRAW_FIELD); + + game_status = GAME_MODE_MAIN; + + if (raise_level) + { + level_nr++; + TapeErase(); + } + + DrawAndFadeInMainMenu(REDRAW_FIELD); + } + + local_player->LevelSolved_SaveScore = FALSE; +} + +#else + void GameWon() { int hi_pos; @@ -2932,6 +3265,8 @@ void GameWon() BackToFront(); } +#endif + int NewHiScore() { int k, l; @@ -5844,7 +6179,12 @@ void StartMoving(int x, int y) started_moving = TRUE; Feld[x][y] = EL_QUICKSAND_EMPTYING; +#if USE_QUICKSAND_BD_ROCK_BUGFIX + if (Store[x][y] != EL_ROCK && Store[x][y] != EL_BD_ROCK) + Store[x][y] = EL_ROCK; +#else Store[x][y] = EL_ROCK; +#endif PlayLevelSoundAction(x, y, ACTION_EMPTYING); } @@ -7787,7 +8127,8 @@ void MauerAbleger(int ax, int ay) if (element == EL_EXPANDABLE_WALL_HORIZONTAL || element == EL_EXPANDABLE_WALL_ANY || - element == EL_EXPANDABLE_WALL) + element == EL_EXPANDABLE_WALL || + element == EL_BD_EXPANDABLE_WALL) { if (links_frei) { @@ -8396,6 +8737,8 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) if (ei->collect_score == 0) { + int xx, yy; + #if 0 printf("::: CE_SCORE_GETS_ZERO\n"); #endif @@ -8406,6 +8749,26 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) #if 0 printf("::: RESULT: %d, %d\n", Feld[x][y], ChangePage[x][y]); #endif + +#if 1 + /* + This is a very special case that seems to be a mixture between + CheckElementChange() and CheckTriggeredElementChange(): while + the first one only affects single elements that are triggered + directly, the second one affects multiple elements in the playfield + that are triggered indirectly by another element. This is a third + case: Changing the CE score always affects multiple identical CEs, + so every affected CE must be checked, not only the single CE for + which the CE score was changed in the first place (as every instance + of that CE shares the same CE score, and therefore also can change)! + */ + SCAN_PLAYFIELD(xx, yy) + { + if (Feld[xx][yy] == element) + CheckElementChange(xx, yy, element, EL_UNDEFINED, + CE_SCORE_GETS_ZERO); + } +#endif } } @@ -8436,8 +8799,15 @@ 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 add_player = (ELEM_IS_PLAYER(new_element) && - IS_WALKABLE(old_element)); + 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 + /* this breaks SnakeBite when a snake is + halfway through a door that closes */ + /* NOW FIXED AT LEVEL INIT IN files.c */ + new_element != EL_SOKOBAN_FIELD_PLAYER && +#endif + IS_WALKABLE(old_element)); #if 0 /* check if element under the player changes from accessible to unaccessible @@ -8451,7 +8821,7 @@ static void CreateFieldExt(int x, int y, int element, boolean is_change) } #endif - if (!add_player) + if (!add_player_onto_element) { if (IS_MOVING(x, y) || IS_BLOCKED(x, y)) RemoveMovingField(x, y); @@ -8502,7 +8872,7 @@ static void CreateFieldExt(int x, int y, int element, boolean is_change) #endif /* "ChangeCount" not set yet to allow "entered by player" change one time */ - if (ELEM_IS_PLAYER(new_element)) + if (new_element_is_player) RelocatePlayer(x, y, new_element); if (is_change) @@ -8663,7 +9033,7 @@ static boolean ChangeElement(int x, int y, int element, int page) ChangeEvent[ex][ey] = ChangeEvent[x][y]; content_element = change->target_content.e[xx][yy]; - target_element = GET_TARGET_ELEMENT(content_element, change, + target_element = GET_TARGET_ELEMENT(element, content_element, change, ce_value, ce_score); CreateElementFromChange(ex, ey, target_element); @@ -8685,7 +9055,7 @@ static boolean ChangeElement(int x, int y, int element, int page) } else { - target_element = GET_TARGET_ELEMENT(change->target_element, change, + target_element = GET_TARGET_ELEMENT(element, change->target_element, change, ce_value, ce_score); if (element == EL_DIAGONAL_GROWING || @@ -9475,10 +9845,6 @@ void StartGameActions(boolean init_network_game, boolean record_tape, } #endif - StopAnimation(); - - game_status = GAME_MODE_PLAYING; - InitGame(); } @@ -9625,6 +9991,10 @@ void GameActions_EM_Main() for (i = 0; i < MAX_PLAYERS; i++) effective_action[i] = stored_player[i].effective_action; +#if 0 + printf("::: %04d: %08x\n", FrameCounter, effective_action[0]); +#endif + GameActions_EM(effective_action, warp_mode); CheckLevelTime(); @@ -9995,7 +10365,8 @@ void GameActions_RND() else if (element == EL_EXPANDABLE_WALL || element == EL_EXPANDABLE_WALL_HORIZONTAL || element == EL_EXPANDABLE_WALL_VERTICAL || - element == EL_EXPANDABLE_WALL_ANY) + element == EL_EXPANDABLE_WALL_ANY || + element == EL_BD_EXPANDABLE_WALL) MauerAbleger(x, y); else if (element == EL_FLAMES) CheckForDragon(x, y); @@ -10348,7 +10719,7 @@ static void CheckGravityMovement(struct PlayerInfo *player) { int move_dir_horizontal = player->effective_action & MV_HORIZONTAL; int move_dir_vertical = player->effective_action & MV_VERTICAL; - boolean player_is_snapping = player->effective_action & JOY_BUTTON_1; + boolean player_is_snapping = (player->effective_action & JOY_BUTTON_1); int jx = player->jx, jy = player->jy; boolean player_is_moving_to_valid_field = (!player_is_snapping && @@ -10503,7 +10874,14 @@ boolean MovePlayerOneStep(struct PlayerInfo *player, PlayerVisit[jx][jy] = FrameCounter; +#if USE_UFAST_PLAYER_EXIT_BUGFIX + player->is_moving = TRUE; +#endif + +#if 1 + /* should better be called in MovePlayer(), but this breaks some tapes */ ScrollPlayer(player, SCROLL_INIT); +#endif return MP_MOVING; } @@ -10571,6 +10949,8 @@ boolean MovePlayer(struct PlayerInfo *player, int dx, int dy) player->move_delay_value = original_move_delay_value; } + player->is_active = FALSE; + if (player->last_move_dir & MV_HORIZONTAL) { if (!(moved |= MovePlayerOneStep(player, 0, dy, dx, dy))) @@ -10582,6 +10962,17 @@ boolean MovePlayer(struct PlayerInfo *player, int dx, int dy) moved |= MovePlayerOneStep(player, 0, dy, dx, dy); } +#if USE_FIXED_BORDER_RUNNING_GFX + if (!moved && !player->is_active) + { + player->is_moving = FALSE; + player->is_digging = FALSE; + player->is_collecting = FALSE; + player->is_snapping = FALSE; + player->is_pushing = FALSE; + } +#endif + jx = player->jx; jy = player->jy; @@ -10688,6 +11079,11 @@ boolean MovePlayer(struct PlayerInfo *player, int dx, int dy) player->is_dropping = FALSE; player->is_dropping_pressed = FALSE; player->drop_pressed_delay = 0; + +#if 0 + /* should better be called here than above, but this breaks some tapes */ + ScrollPlayer(player, SCROLL_INIT); +#endif } else { @@ -11681,6 +12077,8 @@ int DigField(struct PlayerInfo *player, game.engine_version >= VERSION_IDENT(2,2,0,0)) old_element = Back[jx][jy]; + /* checking here causes player to move into acid even if the current field + cannot be left to that direction */ #if 0 #if USE_FIXED_DONT_RUN_INTO if (player_can_move && DONT_RUN_INTO(element)) @@ -11702,6 +12100,43 @@ int DigField(struct PlayerInfo *player, #endif #endif +#if 1 /* ------------------------------ NEW ------------------------------ */ + + if (IS_WALKABLE(old_element) && !ACCESS_FROM(old_element, move_direction)) + return MP_NO_ACTION; /* field has no opening in this direction */ + + if (IS_PASSABLE(old_element) && !ACCESS_FROM(old_element,opposite_direction)) + return MP_NO_ACTION; /* field has no opening in this direction */ + +#if USE_FIXED_DONT_RUN_INTO + if (player_can_move && element == EL_ACID && move_direction == MV_DOWN) + { + SplashAcid(x, y); +#if 1 + Feld[jx][jy] = player->artwork_element; +#else + Feld[jx][jy] = EL_PLAYER_1; +#endif + InitMovingField(jx, jy, MV_DOWN); + Store[jx][jy] = EL_ACID; + ContinueMoving(jx, jy); + BuryPlayer(player); + + return MP_DONT_RUN_INTO; + } +#endif + +#if USE_FIXED_DONT_RUN_INTO + if (player_can_move && DONT_RUN_INTO(element)) + { + TestIfPlayerRunsIntoBadThing(jx, jy, player->MovDir); + + return MP_DONT_RUN_INTO; + } +#endif + +#else /* ------------------------------ OLD ------------------------------ */ + #if 1 #if USE_FIXED_DONT_RUN_INTO if (player_can_move && DONT_RUN_INTO(element)) @@ -11719,6 +12154,7 @@ int DigField(struct PlayerInfo *player, if (IS_PASSABLE(old_element) && !ACCESS_FROM(old_element,opposite_direction)) return MP_NO_ACTION; /* field has no opening in this direction */ + /* checking here causes player to explode when moving into acid */ #if 1 #if USE_FIXED_DONT_RUN_INTO if (player_can_move && element == EL_ACID && move_direction == MV_DOWN) @@ -11735,6 +12171,8 @@ int DigField(struct PlayerInfo *player, #endif #endif +#endif /* ------------------------------ END ------------------------------ */ + #if 0 #if USE_FIXED_DONT_RUN_INTO if (player_can_move && DONT_RUN_INTO(element)) @@ -11861,6 +12299,21 @@ int DigField(struct PlayerInfo *player, if (!player->key[EM_GATE_GRAY_ACTIVE_NR(element)]) return MP_NO_ACTION; } + else if (IS_EMC_GATE(element)) + { + if (!player->key[EMC_GATE_NR(element)]) + return MP_NO_ACTION; + } + else if (IS_EMC_GATE_GRAY(element)) + { + if (!player->key[EMC_GATE_GRAY_NR(element)]) + return MP_NO_ACTION; + } + else if (IS_EMC_GATE_GRAY_ACTIVE(element)) + { + if (!player->key[EMC_GATE_GRAY_ACTIVE_NR(element)]) + return MP_NO_ACTION; + } else if (IS_SP_PORT(element)) { if (element == EL_SP_GRAVITY_PORT_LEFT || @@ -12109,6 +12562,7 @@ int DigField(struct PlayerInfo *player, } player->is_pushing = TRUE; + player->is_active = TRUE; if (!(IN_LEV_FIELD(nextx, nexty) && (IS_FREE(nextx, nexty) || @@ -12361,7 +12815,10 @@ int DigField(struct PlayerInfo *player, if (is_player) /* function can also be called by EL_PENGUIN */ { if (Feld[x][y] != element) /* really digged/collected something */ + { player->is_collecting = !player->is_digging; + player->is_active = TRUE; + } } return MP_MOVING; @@ -12430,6 +12887,7 @@ boolean SnapField(struct PlayerInfo *player, int dx, int dy) return FALSE; player->is_snapping = TRUE; + player->is_active = TRUE; if (player->MovPos == 0) { @@ -12968,8 +13426,20 @@ void RequestQuitGame(boolean ask_if_really_quit) else #endif { - game_status = GAME_MODE_MAIN; - DrawMainMenu(); + if (!ask_if_really_quit || level_editor_test_game) + { + game_status = GAME_MODE_MAIN; + + DrawMainMenu(); + } + else + { + FadeOut(REDRAW_FIELD); + + game_status = GAME_MODE_MAIN; + + DrawAndFadeInMainMenu(REDRAW_FIELD); + } } } else