X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Fgame.c;h=47f3611731f7bf4bff3741f45681d2b1fb37b73d;hb=50e762bca8b7cbca1d0a12674b559e81a4f2c3f9;hp=53410d5ace4c808511e21dad4c6e2e8cf04e6ada;hpb=b4962aefbc6cf3356112afe7cf421e073360de14;p=rocksndiamonds.git diff --git a/src/game.c b/src/game.c index 53410d5a..47f36117 100644 --- a/src/game.c +++ b/src/game.c @@ -89,123 +89,126 @@ // game panel display and control definitions #define GAME_PANEL_LEVEL_NUMBER 0 #define GAME_PANEL_GEMS 1 -#define GAME_PANEL_INVENTORY_COUNT 2 -#define GAME_PANEL_INVENTORY_FIRST_1 3 -#define GAME_PANEL_INVENTORY_FIRST_2 4 -#define GAME_PANEL_INVENTORY_FIRST_3 5 -#define GAME_PANEL_INVENTORY_FIRST_4 6 -#define GAME_PANEL_INVENTORY_FIRST_5 7 -#define GAME_PANEL_INVENTORY_FIRST_6 8 -#define GAME_PANEL_INVENTORY_FIRST_7 9 -#define GAME_PANEL_INVENTORY_FIRST_8 10 -#define GAME_PANEL_INVENTORY_LAST_1 11 -#define GAME_PANEL_INVENTORY_LAST_2 12 -#define GAME_PANEL_INVENTORY_LAST_3 13 -#define GAME_PANEL_INVENTORY_LAST_4 14 -#define GAME_PANEL_INVENTORY_LAST_5 15 -#define GAME_PANEL_INVENTORY_LAST_6 16 -#define GAME_PANEL_INVENTORY_LAST_7 17 -#define GAME_PANEL_INVENTORY_LAST_8 18 -#define GAME_PANEL_KEY_1 19 -#define GAME_PANEL_KEY_2 20 -#define GAME_PANEL_KEY_3 21 -#define GAME_PANEL_KEY_4 22 -#define GAME_PANEL_KEY_5 23 -#define GAME_PANEL_KEY_6 24 -#define GAME_PANEL_KEY_7 25 -#define GAME_PANEL_KEY_8 26 -#define GAME_PANEL_KEY_WHITE 27 -#define GAME_PANEL_KEY_WHITE_COUNT 28 -#define GAME_PANEL_SCORE 29 -#define GAME_PANEL_HIGHSCORE 30 -#define GAME_PANEL_TIME 31 -#define GAME_PANEL_TIME_HH 32 -#define GAME_PANEL_TIME_MM 33 -#define GAME_PANEL_TIME_SS 34 -#define GAME_PANEL_TIME_ANIM 35 -#define GAME_PANEL_HEALTH 36 -#define GAME_PANEL_HEALTH_ANIM 37 -#define GAME_PANEL_FRAME 38 -#define GAME_PANEL_SHIELD_NORMAL 39 -#define GAME_PANEL_SHIELD_NORMAL_TIME 40 -#define GAME_PANEL_SHIELD_DEADLY 41 -#define GAME_PANEL_SHIELD_DEADLY_TIME 42 -#define GAME_PANEL_EXIT 43 -#define GAME_PANEL_EMC_MAGIC_BALL 44 -#define GAME_PANEL_EMC_MAGIC_BALL_SWITCH 45 -#define GAME_PANEL_LIGHT_SWITCH 46 -#define GAME_PANEL_LIGHT_SWITCH_TIME 47 -#define GAME_PANEL_TIMEGATE_SWITCH 48 -#define GAME_PANEL_TIMEGATE_SWITCH_TIME 49 -#define GAME_PANEL_SWITCHGATE_SWITCH 50 -#define GAME_PANEL_EMC_LENSES 51 -#define GAME_PANEL_EMC_LENSES_TIME 52 -#define GAME_PANEL_EMC_MAGNIFIER 53 -#define GAME_PANEL_EMC_MAGNIFIER_TIME 54 -#define GAME_PANEL_BALLOON_SWITCH 55 -#define GAME_PANEL_DYNABOMB_NUMBER 56 -#define GAME_PANEL_DYNABOMB_SIZE 57 -#define GAME_PANEL_DYNABOMB_POWER 58 -#define GAME_PANEL_PENGUINS 59 -#define GAME_PANEL_SOKOBAN_OBJECTS 60 -#define GAME_PANEL_SOKOBAN_FIELDS 61 -#define GAME_PANEL_ROBOT_WHEEL 62 -#define GAME_PANEL_CONVEYOR_BELT_1 63 -#define GAME_PANEL_CONVEYOR_BELT_2 64 -#define GAME_PANEL_CONVEYOR_BELT_3 65 -#define GAME_PANEL_CONVEYOR_BELT_4 66 -#define GAME_PANEL_CONVEYOR_BELT_1_SWITCH 67 -#define GAME_PANEL_CONVEYOR_BELT_2_SWITCH 68 -#define GAME_PANEL_CONVEYOR_BELT_3_SWITCH 69 -#define GAME_PANEL_CONVEYOR_BELT_4_SWITCH 70 -#define GAME_PANEL_MAGIC_WALL 71 -#define GAME_PANEL_MAGIC_WALL_TIME 72 -#define GAME_PANEL_GRAVITY_STATE 73 -#define GAME_PANEL_GRAPHIC_1 74 -#define GAME_PANEL_GRAPHIC_2 75 -#define GAME_PANEL_GRAPHIC_3 76 -#define GAME_PANEL_GRAPHIC_4 77 -#define GAME_PANEL_GRAPHIC_5 78 -#define GAME_PANEL_GRAPHIC_6 79 -#define GAME_PANEL_GRAPHIC_7 80 -#define GAME_PANEL_GRAPHIC_8 81 -#define GAME_PANEL_ELEMENT_1 82 -#define GAME_PANEL_ELEMENT_2 83 -#define GAME_PANEL_ELEMENT_3 84 -#define GAME_PANEL_ELEMENT_4 85 -#define GAME_PANEL_ELEMENT_5 86 -#define GAME_PANEL_ELEMENT_6 87 -#define GAME_PANEL_ELEMENT_7 88 -#define GAME_PANEL_ELEMENT_8 89 -#define GAME_PANEL_ELEMENT_COUNT_1 90 -#define GAME_PANEL_ELEMENT_COUNT_2 91 -#define GAME_PANEL_ELEMENT_COUNT_3 92 -#define GAME_PANEL_ELEMENT_COUNT_4 93 -#define GAME_PANEL_ELEMENT_COUNT_5 94 -#define GAME_PANEL_ELEMENT_COUNT_6 95 -#define GAME_PANEL_ELEMENT_COUNT_7 96 -#define GAME_PANEL_ELEMENT_COUNT_8 97 -#define GAME_PANEL_CE_SCORE_1 98 -#define GAME_PANEL_CE_SCORE_2 99 -#define GAME_PANEL_CE_SCORE_3 100 -#define GAME_PANEL_CE_SCORE_4 101 -#define GAME_PANEL_CE_SCORE_5 102 -#define GAME_PANEL_CE_SCORE_6 103 -#define GAME_PANEL_CE_SCORE_7 104 -#define GAME_PANEL_CE_SCORE_8 105 -#define GAME_PANEL_CE_SCORE_1_ELEMENT 106 -#define GAME_PANEL_CE_SCORE_2_ELEMENT 107 -#define GAME_PANEL_CE_SCORE_3_ELEMENT 108 -#define GAME_PANEL_CE_SCORE_4_ELEMENT 109 -#define GAME_PANEL_CE_SCORE_5_ELEMENT 110 -#define GAME_PANEL_CE_SCORE_6_ELEMENT 111 -#define GAME_PANEL_CE_SCORE_7_ELEMENT 112 -#define GAME_PANEL_CE_SCORE_8_ELEMENT 113 -#define GAME_PANEL_PLAYER_NAME 114 -#define GAME_PANEL_LEVEL_NAME 115 -#define GAME_PANEL_LEVEL_AUTHOR 116 - -#define NUM_GAME_PANEL_CONTROLS 117 +#define GAME_PANEL_GEMS_TOTAL 2 +#define GAME_PANEL_GEMS_COLLECTED 3 +#define GAME_PANEL_GEMS_SCORE 4 +#define GAME_PANEL_INVENTORY_COUNT 5 +#define GAME_PANEL_INVENTORY_FIRST_1 6 +#define GAME_PANEL_INVENTORY_FIRST_2 7 +#define GAME_PANEL_INVENTORY_FIRST_3 8 +#define GAME_PANEL_INVENTORY_FIRST_4 9 +#define GAME_PANEL_INVENTORY_FIRST_5 10 +#define GAME_PANEL_INVENTORY_FIRST_6 11 +#define GAME_PANEL_INVENTORY_FIRST_7 12 +#define GAME_PANEL_INVENTORY_FIRST_8 13 +#define GAME_PANEL_INVENTORY_LAST_1 14 +#define GAME_PANEL_INVENTORY_LAST_2 15 +#define GAME_PANEL_INVENTORY_LAST_3 16 +#define GAME_PANEL_INVENTORY_LAST_4 17 +#define GAME_PANEL_INVENTORY_LAST_5 18 +#define GAME_PANEL_INVENTORY_LAST_6 19 +#define GAME_PANEL_INVENTORY_LAST_7 20 +#define GAME_PANEL_INVENTORY_LAST_8 21 +#define GAME_PANEL_KEY_1 22 +#define GAME_PANEL_KEY_2 23 +#define GAME_PANEL_KEY_3 24 +#define GAME_PANEL_KEY_4 25 +#define GAME_PANEL_KEY_5 26 +#define GAME_PANEL_KEY_6 27 +#define GAME_PANEL_KEY_7 28 +#define GAME_PANEL_KEY_8 29 +#define GAME_PANEL_KEY_WHITE 30 +#define GAME_PANEL_KEY_WHITE_COUNT 31 +#define GAME_PANEL_SCORE 32 +#define GAME_PANEL_HIGHSCORE 33 +#define GAME_PANEL_TIME 34 +#define GAME_PANEL_TIME_HH 35 +#define GAME_PANEL_TIME_MM 36 +#define GAME_PANEL_TIME_SS 37 +#define GAME_PANEL_TIME_ANIM 38 +#define GAME_PANEL_HEALTH 39 +#define GAME_PANEL_HEALTH_ANIM 40 +#define GAME_PANEL_FRAME 41 +#define GAME_PANEL_SHIELD_NORMAL 42 +#define GAME_PANEL_SHIELD_NORMAL_TIME 43 +#define GAME_PANEL_SHIELD_DEADLY 44 +#define GAME_PANEL_SHIELD_DEADLY_TIME 45 +#define GAME_PANEL_EXIT 46 +#define GAME_PANEL_EMC_MAGIC_BALL 47 +#define GAME_PANEL_EMC_MAGIC_BALL_SWITCH 48 +#define GAME_PANEL_LIGHT_SWITCH 49 +#define GAME_PANEL_LIGHT_SWITCH_TIME 50 +#define GAME_PANEL_TIMEGATE_SWITCH 51 +#define GAME_PANEL_TIMEGATE_SWITCH_TIME 52 +#define GAME_PANEL_SWITCHGATE_SWITCH 53 +#define GAME_PANEL_EMC_LENSES 54 +#define GAME_PANEL_EMC_LENSES_TIME 55 +#define GAME_PANEL_EMC_MAGNIFIER 56 +#define GAME_PANEL_EMC_MAGNIFIER_TIME 57 +#define GAME_PANEL_BALLOON_SWITCH 58 +#define GAME_PANEL_DYNABOMB_NUMBER 59 +#define GAME_PANEL_DYNABOMB_SIZE 60 +#define GAME_PANEL_DYNABOMB_POWER 61 +#define GAME_PANEL_PENGUINS 62 +#define GAME_PANEL_SOKOBAN_OBJECTS 63 +#define GAME_PANEL_SOKOBAN_FIELDS 64 +#define GAME_PANEL_ROBOT_WHEEL 65 +#define GAME_PANEL_CONVEYOR_BELT_1 66 +#define GAME_PANEL_CONVEYOR_BELT_2 67 +#define GAME_PANEL_CONVEYOR_BELT_3 68 +#define GAME_PANEL_CONVEYOR_BELT_4 69 +#define GAME_PANEL_CONVEYOR_BELT_1_SWITCH 70 +#define GAME_PANEL_CONVEYOR_BELT_2_SWITCH 71 +#define GAME_PANEL_CONVEYOR_BELT_3_SWITCH 72 +#define GAME_PANEL_CONVEYOR_BELT_4_SWITCH 73 +#define GAME_PANEL_MAGIC_WALL 74 +#define GAME_PANEL_MAGIC_WALL_TIME 75 +#define GAME_PANEL_GRAVITY_STATE 76 +#define GAME_PANEL_GRAPHIC_1 77 +#define GAME_PANEL_GRAPHIC_2 78 +#define GAME_PANEL_GRAPHIC_3 79 +#define GAME_PANEL_GRAPHIC_4 80 +#define GAME_PANEL_GRAPHIC_5 81 +#define GAME_PANEL_GRAPHIC_6 82 +#define GAME_PANEL_GRAPHIC_7 83 +#define GAME_PANEL_GRAPHIC_8 84 +#define GAME_PANEL_ELEMENT_1 85 +#define GAME_PANEL_ELEMENT_2 86 +#define GAME_PANEL_ELEMENT_3 87 +#define GAME_PANEL_ELEMENT_4 88 +#define GAME_PANEL_ELEMENT_5 89 +#define GAME_PANEL_ELEMENT_6 90 +#define GAME_PANEL_ELEMENT_7 91 +#define GAME_PANEL_ELEMENT_8 92 +#define GAME_PANEL_ELEMENT_COUNT_1 93 +#define GAME_PANEL_ELEMENT_COUNT_2 94 +#define GAME_PANEL_ELEMENT_COUNT_3 95 +#define GAME_PANEL_ELEMENT_COUNT_4 96 +#define GAME_PANEL_ELEMENT_COUNT_5 97 +#define GAME_PANEL_ELEMENT_COUNT_6 98 +#define GAME_PANEL_ELEMENT_COUNT_7 99 +#define GAME_PANEL_ELEMENT_COUNT_8 100 +#define GAME_PANEL_CE_SCORE_1 101 +#define GAME_PANEL_CE_SCORE_2 102 +#define GAME_PANEL_CE_SCORE_3 103 +#define GAME_PANEL_CE_SCORE_4 104 +#define GAME_PANEL_CE_SCORE_5 105 +#define GAME_PANEL_CE_SCORE_6 106 +#define GAME_PANEL_CE_SCORE_7 107 +#define GAME_PANEL_CE_SCORE_8 108 +#define GAME_PANEL_CE_SCORE_1_ELEMENT 109 +#define GAME_PANEL_CE_SCORE_2_ELEMENT 110 +#define GAME_PANEL_CE_SCORE_3_ELEMENT 111 +#define GAME_PANEL_CE_SCORE_4_ELEMENT 112 +#define GAME_PANEL_CE_SCORE_5_ELEMENT 113 +#define GAME_PANEL_CE_SCORE_6_ELEMENT 114 +#define GAME_PANEL_CE_SCORE_7_ELEMENT 115 +#define GAME_PANEL_CE_SCORE_8_ELEMENT 116 +#define GAME_PANEL_PLAYER_NAME 117 +#define GAME_PANEL_LEVEL_NAME 118 +#define GAME_PANEL_LEVEL_AUTHOR 119 + +#define NUM_GAME_PANEL_CONTROLS 120 struct GamePanelOrderInfo { @@ -242,6 +245,21 @@ static struct GamePanelControlInfo game_panel_controls[] = &game.panel.gems, TYPE_INTEGER, }, + { + GAME_PANEL_GEMS_TOTAL, + &game.panel.gems_total, + TYPE_INTEGER, + }, + { + GAME_PANEL_GEMS_COLLECTED, + &game.panel.gems_collected, + TYPE_INTEGER, + }, + { + GAME_PANEL_GEMS_SCORE, + &game.panel.gems_score, + TYPE_INTEGER, + }, { GAME_PANEL_INVENTORY_COUNT, &game.panel.inventory_count, @@ -1017,19 +1035,22 @@ static struct GamePanelControlInfo game_panel_controls[] = #define GAME_CTRL_ID_SAVE 5 #define GAME_CTRL_ID_PAUSE2 6 #define GAME_CTRL_ID_LOAD 7 -#define GAME_CTRL_ID_PANEL_STOP 8 -#define GAME_CTRL_ID_PANEL_PAUSE 9 -#define GAME_CTRL_ID_PANEL_PLAY 10 -#define GAME_CTRL_ID_TOUCH_STOP 11 -#define GAME_CTRL_ID_TOUCH_PAUSE 12 -#define SOUND_CTRL_ID_MUSIC 13 -#define SOUND_CTRL_ID_LOOPS 14 -#define SOUND_CTRL_ID_SIMPLE 15 -#define SOUND_CTRL_ID_PANEL_MUSIC 16 -#define SOUND_CTRL_ID_PANEL_LOOPS 17 -#define SOUND_CTRL_ID_PANEL_SIMPLE 18 - -#define NUM_GAME_BUTTONS 19 +#define GAME_CTRL_ID_RESTART 8 +#define GAME_CTRL_ID_PANEL_STOP 9 +#define GAME_CTRL_ID_PANEL_PAUSE 10 +#define GAME_CTRL_ID_PANEL_PLAY 11 +#define GAME_CTRL_ID_PANEL_RESTART 12 +#define GAME_CTRL_ID_TOUCH_STOP 13 +#define GAME_CTRL_ID_TOUCH_PAUSE 14 +#define GAME_CTRL_ID_TOUCH_RESTART 15 +#define SOUND_CTRL_ID_MUSIC 16 +#define SOUND_CTRL_ID_LOOPS 17 +#define SOUND_CTRL_ID_SIMPLE 18 +#define SOUND_CTRL_ID_PANEL_MUSIC 19 +#define SOUND_CTRL_ID_PANEL_LOOPS 20 +#define SOUND_CTRL_ID_PANEL_SIMPLE 21 + +#define NUM_GAME_BUTTONS 22 // forward declaration for internal use @@ -2241,6 +2262,8 @@ static void UpdateGameControlValues(void) int i, k; int time = (game.LevelSolved ? game.LevelSolved_CountingTime : + level.game_engine_type == GAME_ENGINE_TYPE_BD ? + game_bd.time_played : level.game_engine_type == GAME_ENGINE_TYPE_EM ? game_em.lev->time : level.game_engine_type == GAME_ENGINE_TYPE_SP ? @@ -2250,6 +2273,8 @@ static void UpdateGameControlValues(void) game.no_level_time_limit ? TimePlayed : TimeLeft); int score = (game.LevelSolved ? game.LevelSolved_CountingScore : + level.game_engine_type == GAME_ENGINE_TYPE_BD ? + game_bd.score : level.game_engine_type == GAME_ENGINE_TYPE_EM ? game_em.lev->score : level.game_engine_type == GAME_ENGINE_TYPE_SP ? @@ -2257,14 +2282,25 @@ static void UpdateGameControlValues(void) level.game_engine_type == GAME_ENGINE_TYPE_MM ? game_mm.score : game.score); - int gems = (level.game_engine_type == GAME_ENGINE_TYPE_EM ? + int gems = (level.game_engine_type == GAME_ENGINE_TYPE_BD ? + game_bd.gems_still_needed : + level.game_engine_type == GAME_ENGINE_TYPE_EM ? game_em.lev->gems_needed : level.game_engine_type == GAME_ENGINE_TYPE_SP ? game_sp.infotrons_still_needed : level.game_engine_type == GAME_ENGINE_TYPE_MM ? game_mm.kettles_still_needed : game.gems_still_needed); - int exit_closed = (level.game_engine_type == GAME_ENGINE_TYPE_EM ? + int gems_total = level.gems_needed; + int gems_collected = (level.game_engine_type == GAME_ENGINE_TYPE_BD ? + game_bd.game->cave->diamonds_collected : + gems_total - gems); + int gems_score = (level.game_engine_type == GAME_ENGINE_TYPE_BD ? + game_bd.game->cave->diamond_value : + level.score[SC_EMERALD]); + int exit_closed = (level.game_engine_type == GAME_ENGINE_TYPE_BD ? + game_bd.gems_still_needed > 0 : + level.game_engine_type == GAME_ENGINE_TYPE_EM ? game_em.lev->gems_needed > 0 : level.game_engine_type == GAME_ENGINE_TYPE_SP ? game_sp.infotrons_still_needed > 0 : @@ -2289,6 +2325,9 @@ static void UpdateGameControlValues(void) // used instead of "level_nr" (for network games) game_panel_controls[GAME_PANEL_LEVEL_NUMBER].value = levelset.level_nr; game_panel_controls[GAME_PANEL_GEMS].value = gems; + game_panel_controls[GAME_PANEL_GEMS_TOTAL].value = gems_total; + game_panel_controls[GAME_PANEL_GEMS_COLLECTED].value = gems_collected; + game_panel_controls[GAME_PANEL_GEMS_SCORE].value = gems_score; game_panel_controls[GAME_PANEL_INVENTORY_COUNT].value = 0; for (i = 0; i < MAX_NUM_KEYS; i++) @@ -3095,6 +3134,9 @@ static void InitGameEngine(void) game_em.use_single_button = (game.engine_version > VERSION_IDENT(4,0,0,2)); + game_em.use_push_delay = + (game.engine_version > VERSION_IDENT(4,3,7,1)); + game_em.use_snap_key_bug = (game.engine_version < VERSION_IDENT(4,0,1,0)); @@ -3279,6 +3321,8 @@ static void InitGameEngine(void) change->actual_trigger_side = CH_SIDE_NONE; change->actual_trigger_ce_value = 0; change->actual_trigger_ce_score = 0; + change->actual_trigger_x = -1; + change->actual_trigger_y = -1; } } @@ -3835,6 +3879,8 @@ void InitGame(void) TimeFrames = 0; TimePlayed = 0; TimeLeft = level.time; + + TapeTimeFrames = 0; TapeTime = 0; ScreenMovDir = MV_NONE; @@ -3865,6 +3911,8 @@ void InitGame(void) game.LevelSolved_CountingScore = 0; game.LevelSolved_CountingHealth = 0; + game.RestartGameRequested = FALSE; + game.panel.active = TRUE; game.no_level_time_limit = (level.time == 0); @@ -3971,6 +4019,10 @@ void InitGame(void) InitBeltMovement(); + // required if level does not contain any "empty space" element + if (element_info[EL_EMPTY].use_gfx_element) + game.use_masked_elements = TRUE; + for (i = 0; i < MAX_PLAYERS; i++) { struct PlayerInfo *player = &stored_player[i]; @@ -4445,8 +4497,17 @@ void InitGame(void) scroll_y = SCROLL_POSITION_Y(local_player->jy); } + if (game.forced_scroll_x != ARG_UNDEFINED_VALUE) + scroll_x = game.forced_scroll_x; + if (game.forced_scroll_y != ARG_UNDEFINED_VALUE) + scroll_y = game.forced_scroll_y; + // !!! FIX THIS (START) !!! - if (level.game_engine_type == GAME_ENGINE_TYPE_EM) + if (level.game_engine_type == GAME_ENGINE_TYPE_BD) + { + InitGameEngine_BD(); + } + else if (level.game_engine_type == GAME_ENGINE_TYPE_EM) { InitGameEngine_EM(); } @@ -4535,9 +4596,7 @@ void InitGame(void) } game.restart_level = FALSE; - game.request_active = FALSE; - game.request_active_or_moving = FALSE; if (level.game_engine_type == GAME_ENGINE_TYPE_MM) InitGameActions_MM(); @@ -4775,14 +4834,14 @@ void InitAmoebaNr(int x, int y) static void LevelSolved_SetFinalGameValues(void) { - game.time_final = (game.no_level_time_limit ? TimePlayed : TimeLeft); + game.time_final = (level.game_engine_type == GAME_ENGINE_TYPE_BD ? game_bd.time_played : + game.no_level_time_limit ? TimePlayed : TimeLeft); game.score_time_final = (level.use_step_counter ? TimePlayed : TimePlayed * FRAMES_PER_SECOND + TimeFrames); - game.score_final = (level.game_engine_type == GAME_ENGINE_TYPE_EM ? - game_em.lev->score : - level.game_engine_type == GAME_ENGINE_TYPE_MM ? - game_mm.score : + game.score_final = (level.game_engine_type == GAME_ENGINE_TYPE_BD ? game_bd.score : + level.game_engine_type == GAME_ENGINE_TYPE_EM ? game_em.lev->score : + level.game_engine_type == GAME_ENGINE_TYPE_MM ? game_mm.score : game.score); game.health_final = (level.game_engine_type == GAME_ENGINE_TYPE_MM ? @@ -4896,7 +4955,13 @@ void GameWon(void) time_count_steps = MAX(1, ABS(time_final - time) / 100); - if (level.game_engine_type == GAME_ENGINE_TYPE_MM) + if (level.game_engine_type == GAME_ENGINE_TYPE_BD) + { + // keep previous values (final values already processed here) + time_final = time; + score_final = score; + } + else if (level.game_engine_type == GAME_ENGINE_TYPE_MM) { health_final = 0; score_final += health * time_score; @@ -4907,7 +4972,8 @@ void GameWon(void) } // if not counting score after game, immediately update game panel values - if (level_editor_test_game || !setup.count_score_after_game) + if (level_editor_test_game || !setup.count_score_after_game || + level.game_engine_type == GAME_ENGINE_TYPE_BD) { time = time_final; score = score_final; @@ -5682,6 +5748,40 @@ static void DrawRelocateScreen(int old_x, int old_y, int x, int y, // make sure that shifted scroll position does not scroll beyond screen new_scroll_x = SCROLL_POSITION_X(shifted_scroll_x + MIDPOSX); new_scroll_y = SCROLL_POSITION_Y(shifted_scroll_y + MIDPOSY); + + // special case for teleporting from one end of the playfield to the other + // (this kludge prevents the destination area to be shifted by half a tile + // against the source destination for even screen width or screen height; + // probably most useful when used with high "game.forced_scroll_delay_value" + // in combination with "game.forced_scroll_x" and "game.forced_scroll_y") + if (quick_relocation) + { + if (EVEN(SCR_FIELDX)) + { + // relocate (teleport) between left and right border (half or full) + if (scroll_x == SBX_Left && new_scroll_x == SBX_Right - 1) + new_scroll_x = SBX_Right; + else if (scroll_x == SBX_Left + 1 && new_scroll_x == SBX_Right) + new_scroll_x = SBX_Right - 1; + else if (scroll_x == SBX_Right && new_scroll_x == SBX_Left + 1) + new_scroll_x = SBX_Left; + else if (scroll_x == SBX_Right - 1 && new_scroll_x == SBX_Left) + new_scroll_x = SBX_Left + 1; + } + + if (EVEN(SCR_FIELDY)) + { + // relocate (teleport) between top and bottom border (half or full) + if (scroll_y == SBY_Upper && new_scroll_y == SBY_Lower - 1) + new_scroll_y = SBY_Lower; + else if (scroll_y == SBY_Upper + 1 && new_scroll_y == SBY_Lower) + new_scroll_y = SBY_Lower - 1; + else if (scroll_y == SBY_Lower && new_scroll_y == SBY_Upper + 1) + new_scroll_y = SBY_Upper; + else if (scroll_y == SBY_Lower - 1 && new_scroll_y == SBY_Upper) + new_scroll_y = SBY_Upper + 1; + } + } } if (quick_relocation) @@ -9397,7 +9497,7 @@ static void Life(int ax, int ay) for (y1 = -1; y1 < 2; y1++) for (x1 = -1; x1 < 2; x1++) { - int xx = ax+x1, yy = ay+y1; + int xx = ax + x1, yy = ay + y1; int old_element = Tile[xx][yy]; int num_neighbours = 0; @@ -9406,7 +9506,7 @@ static void Life(int ax, int ay) for (y2 = -1; y2 < 2; y2++) for (x2 = -1; x2 < 2; x2++) { - int x = xx+x2, y = yy+y2; + int x = xx + x2, y = yy + y2; if (!IN_LEV_FIELD(x, y) || (x == xx && y == yy)) continue; @@ -10720,6 +10820,8 @@ static boolean ChangeElement(int x, int y, int element, int page) change->actual_trigger_side = CH_SIDE_NONE; change->actual_trigger_ce_value = 0; change->actual_trigger_ce_score = 0; + change->actual_trigger_x = -1; + change->actual_trigger_y = -1; } // do not change elements more than a specified maximum number of changes @@ -10729,7 +10831,9 @@ static boolean ChangeElement(int x, int y, int element, int page) ChangeCount[x][y]++; // count number of changes in the same frame if (ei->has_anim_event) - HandleGlobalAnimEventByElementChange(element, page, x, y); + HandleGlobalAnimEventByElementChange(element, page, x, y, + change->actual_trigger_x, + change->actual_trigger_y); if (change->explode) { @@ -11059,6 +11163,8 @@ static boolean CheckTriggeredElementChangeExt(int trigger_x, int trigger_y, change->actual_trigger_side = trigger_side; change->actual_trigger_ce_value = CustomValue[trigger_x][trigger_y]; change->actual_trigger_ce_score = GET_CE_SCORE(trigger_element); + change->actual_trigger_x = trigger_x; + change->actual_trigger_y = trigger_y; if ((change->can_change && !change_done) || change->has_action) { @@ -11173,6 +11279,8 @@ static boolean CheckElementChangeExt(int x, int y, change->actual_trigger_side = trigger_side; change->actual_trigger_ce_value = CustomValue[x][y]; change->actual_trigger_ce_score = GET_CE_SCORE(trigger_element); + change->actual_trigger_x = x; + change->actual_trigger_y = y; // special case: trigger element not at (x,y) position for some events if (check_trigger_element) @@ -11196,6 +11304,8 @@ static boolean CheckElementChangeExt(int x, int y, change->actual_trigger_ce_value = CustomValue[xx][yy]; change->actual_trigger_ce_score = GET_CE_SCORE(trigger_element); + change->actual_trigger_x = xx; + change->actual_trigger_y = yy; } if (change->can_change && !change_done) @@ -11535,7 +11645,22 @@ static void SetTapeActionFromMouseAction(byte *tape_action, static void CheckLevelSolved(void) { - if (level.game_engine_type == GAME_ENGINE_TYPE_EM) + if (level.game_engine_type == GAME_ENGINE_TYPE_BD) + { + if (game_bd.level_solved && + !game_bd.game_over) // game won + { + LevelSolved(); + + game_bd.game_over = TRUE; + + game.all_players_gone = TRUE; + } + + if (game_bd.game_over) // game lost + game.all_players_gone = TRUE; + } + else if (level.game_engine_type == GAME_ENGINE_TYPE_EM) { if (game_em.level_solved && !game_em.game_over) // game won @@ -11582,6 +11707,27 @@ static void CheckLevelSolved(void) } } +static void PlayTimeoutSound(int seconds_left) +{ + // will be played directly by BD engine (for classic bonus time sounds) + if (level.game_engine_type == GAME_ENGINE_TYPE_BD && checkBonusTime_BD()) + return; + + // try to use individual "running out of time" sound for each second left + int sound = SND_GAME_RUNNING_OUT_OF_TIME_0 - seconds_left; + + // if special sound per second not defined, use default sound + if (getSoundInfoEntryFilename(sound) == NULL) + sound = SND_GAME_RUNNING_OUT_OF_TIME; + + // if out of time, but player still alive, play special "timeout" sound, if defined + if (seconds_left == 0 && !checkGameFailed()) + if (getSoundInfoEntryFilename(SND_GAME_TIMEOUT) != NULL) + sound = SND_GAME_TIMEOUT; + + PlaySound(sound); +} + static void CheckLevelTime_StepCounter(void) { int i; @@ -11593,7 +11739,7 @@ static void CheckLevelTime_StepCounter(void) TimeLeft--; if (TimeLeft <= 10 && game.time_limit && !game.LevelSolved) - PlaySound(SND_GAME_RUNNING_OUT_OF_TIME); + PlayTimeoutSound(TimeLeft); game_panel_controls[GAME_PANEL_TIME].value = TimeLeft; @@ -11613,12 +11759,26 @@ static void CheckLevelTime_StepCounter(void) static void CheckLevelTime(void) { + int frames_per_second = FRAMES_PER_SECOND; int i; - if (TimeFrames >= FRAMES_PER_SECOND) + if (level.game_engine_type == GAME_ENGINE_TYPE_BD) + { + // level time may be running slower in native BD engine + frames_per_second = getFramesPerSecond_BD(); + + // if native engine time changed, force main engine time change + if (getTimeLeft_BD() < TimeLeft) + TimeFrames = frames_per_second; + + // if last second running, wait for native engine time to exactly reach zero + if (getTimeLeft_BD() == 1 && TimeLeft == 1) + TimeFrames = frames_per_second - 1; + } + + if (TimeFrames >= frames_per_second) { TimeFrames = 0; - TapeTime++; for (i = 0; i < MAX_PLAYERS; i++) { @@ -11642,7 +11802,7 @@ static void CheckLevelTime(void) TimeLeft--; if (TimeLeft <= 10 && game.time_limit) - PlaySound(SND_GAME_RUNNING_OUT_OF_TIME); + PlayTimeoutSound(TimeLeft); /* this does not make sense: game_panel_controls[GAME_PANEL_TIME].value is reset from other values in UpdateGameDoorValues() -- FIX THIS */ @@ -11651,11 +11811,20 @@ static void CheckLevelTime(void) if (!TimeLeft && game.time_limit) { - if (level.game_engine_type == GAME_ENGINE_TYPE_EM) + if (level.game_engine_type == GAME_ENGINE_TYPE_BD) + { + if (game_bd.game->cave->player_state == GD_PL_LIVING) + game_bd.game->cave->player_state = GD_PL_TIMEOUT; + } + else if (level.game_engine_type == GAME_ENGINE_TYPE_EM) + { game_em.lev->killed_out_of_time = TRUE; + } else + { for (i = 0; i < MAX_PLAYERS; i++) KillPlayer(&stored_player[i]); + } } } else if (game.no_level_time_limit && !game.all_players_gone) @@ -11665,6 +11834,12 @@ static void CheckLevelTime(void) game_em.lev->time = (game.no_level_time_limit ? TimePlayed : TimeLeft); } + } + + if (TapeTimeFrames >= FRAMES_PER_SECOND) + { + TapeTimeFrames = 0; + TapeTime++; if (tape.recording || tape.playing) DrawVideoDisplay(VIDEO_STATE_TIME_ON, TapeTime); @@ -11680,8 +11855,21 @@ void AdvanceFrameAndPlayerCounters(int player_nr) { int i; - // advance frame counters (global frame counter and time frame counter) + // handle game and tape time differently for native BD game engine + + // tape time is running in native BD engine even if player is not hatched yet + if (!checkGameRunning()) + return; + + // advance frame counters (global frame counter and tape time frame counter) FrameCounter++; + TapeTimeFrames++; + + // level time is running in native BD engine after player is being hatched + if (!checkGamePlaying()) + return; + + // advance time frame counter (used to control available time to solve level) TimeFrames++; // advance player counters (counters for move delay, move animation etc.) @@ -12031,7 +12219,11 @@ static void GameActionsExt(void) game.snapshot.last_action[i] = stored_player[i].effective_action; } - if (level.game_engine_type == GAME_ENGINE_TYPE_EM) + if (level.game_engine_type == GAME_ENGINE_TYPE_BD) + { + GameActions_BD_Main(); + } + else if (level.game_engine_type == GAME_ENGINE_TYPE_EM) { GameActions_EM_Main(); } @@ -12098,6 +12290,17 @@ void GameActions(void) GameActions_CheckSaveEngineSnapshot(); } +void GameActions_BD_Main(void) +{ + byte effective_action[MAX_PLAYERS]; + int i; + + for (i = 0; i < MAX_PLAYERS; i++) + effective_action[i] = stored_player[i].effective_action; + + GameActions_BD(effective_action); +} + void GameActions_EM_Main(void) { byte effective_action[MAX_PLAYERS]; @@ -15192,15 +15395,15 @@ void InitPlayLevelSound(void) loop_sound_volume = checked_calloc(num_sounds * sizeof(int)); } -static void PlayLevelSound(int x, int y, int nr) +static void PlayLevelSoundExt(int x, int y, int nr, boolean is_loop_sound) { int sx = SCREENX(x), sy = SCREENY(y); int volume, stereo_position; int max_distance = 8; - int type = (IS_LOOP_SOUND(nr) ? SND_CTRL_PLAY_LOOP : SND_CTRL_PLAY_SOUND); + int type = (is_loop_sound ? SND_CTRL_PLAY_LOOP : SND_CTRL_PLAY_SOUND); - if ((!setup.sound_simple && !IS_LOOP_SOUND(nr)) || - (!setup.sound_loops && IS_LOOP_SOUND(nr))) + if ((!setup.sound_simple && !is_loop_sound) || + (!setup.sound_loops && is_loop_sound)) return; if (!IN_LEV_FIELD(x, y) || @@ -15222,7 +15425,7 @@ static void PlayLevelSound(int x, int y, int nr) (sx + max_distance) * SOUND_MAX_LEFT2RIGHT / (SCR_FIELDX + 2 * max_distance)); - if (IS_LOOP_SOUND(nr)) + if (is_loop_sound) { /* This assures that quieter loop sounds do not overwrite louder ones, while restarting sound volume comparison with each new game frame. */ @@ -15237,6 +15440,11 @@ static void PlayLevelSound(int x, int y, int nr) PlaySoundExt(nr, volume, stereo_position, type); } +static void PlayLevelSound(int x, int y, int nr) +{ + PlayLevelSoundExt(x, y, nr, IS_LOOP_SOUND(nr)); +} + static void PlayLevelSoundNearest(int x, int y, int sound_action) { PlayLevelSound(x < LEVELX(BX1) ? LEVELX(BX1) : @@ -15325,6 +15533,226 @@ static void PlayLevelMusic(void) PlayMusicLoop(music_nr); } +static int getSoundAction_BD(int sample) +{ + switch (sample) + { + case GD_S_STONE: + case GD_S_NUT: + case GD_S_DIRT_BALL: + case GD_S_NITRO: + case GD_S_FALLING_WALL: + return ACTION_IMPACT; + + case GD_S_NUT_CRACK: + return ACTION_BREAKING; + + case GD_S_EXPANDING_WALL: + case GD_S_WALL_REAPPEAR: + case GD_S_SLIME: + case GD_S_LAVA: + case GD_S_ACID_SPREAD: + return ACTION_GROWING; + + case GD_S_DIAMOND_COLLECT: + case GD_S_SKELETON_COLLECT: + case GD_S_PNEUMATIC_COLLECT: + case GD_S_BOMB_COLLECT: + case GD_S_CLOCK_COLLECT: + case GD_S_SWEET_COLLECT: + case GD_S_KEY_COLLECT: + case GD_S_DIAMOND_KEY_COLLECT: + return ACTION_COLLECTING; + + case GD_S_BOMB_PLACE: + case GD_S_REPLICATOR: + return ACTION_DROPPING; + + case GD_S_BLADDER_MOVE: + return ACTION_MOVING; + + case GD_S_BLADDER_SPENDER: + case GD_S_BLADDER_CONVERT: + case GD_S_GRAVITY_CHANGE: + return ACTION_CHANGING; + + case GD_S_BITER_EAT: + return ACTION_EATING; + + case GD_S_DOOR_OPEN: + case GD_S_CRACK: + return ACTION_OPENING; + + case GD_S_WALK_EARTH: + return ACTION_DIGGING; + + case GD_S_WALK_EMPTY: + return ACTION_WALKING; + + case GD_S_SWITCH_BITER: + case GD_S_SWITCH_CREATURES: + case GD_S_SWITCH_GRAVITY: + case GD_S_SWITCH_EXPANDING: + case GD_S_SWITCH_CONVEYOR: + case GD_S_SWITCH_REPLICATOR: + case GD_S_STIRRING: + return ACTION_ACTIVATING; + + case GD_S_BOX_PUSH: + return ACTION_PUSHING; + + case GD_S_TELEPORTER: + return ACTION_PASSING; + + case GD_S_EXPLOSION: + case GD_S_BOMB_EXPLOSION: + case GD_S_GHOST_EXPLOSION: + case GD_S_VOODOO_EXPLOSION: + case GD_S_NITRO_EXPLOSION: + return ACTION_EXPLODING; + + case GD_S_COVER: + case GD_S_AMOEBA: + case GD_S_AMOEBA_MAGIC: + case GD_S_MAGIC_WALL: + case GD_S_PNEUMATIC_HAMMER: + case GD_S_WATER: + return ACTION_ACTIVE; + + case GD_S_DIAMOND_RANDOM: + case GD_S_DIAMOND_1: + case GD_S_DIAMOND_2: + case GD_S_DIAMOND_3: + case GD_S_DIAMOND_4: + case GD_S_DIAMOND_5: + case GD_S_DIAMOND_6: + case GD_S_DIAMOND_7: + case GD_S_DIAMOND_8: + case GD_S_TIMEOUT_0: + case GD_S_TIMEOUT_1: + case GD_S_TIMEOUT_2: + case GD_S_TIMEOUT_3: + case GD_S_TIMEOUT_4: + case GD_S_TIMEOUT_5: + case GD_S_TIMEOUT_6: + case GD_S_TIMEOUT_7: + case GD_S_TIMEOUT_8: + case GD_S_TIMEOUT_9: + case GD_S_TIMEOUT_10: + case GD_S_BONUS_LIFE: + // kludge to prevent playing as loop sound + return ACTION_OTHER; + + case GD_S_FINISHED: + return ACTION_DEFAULT; + + default: + return ACTION_DEFAULT; + } +} + +static int getSoundEffect_BD(int element_bd, int sample) +{ + int sound_action = getSoundAction_BD(sample); + int sound_effect = element_info[SND_ELEMENT(element_bd)].sound[sound_action]; + int nr; + + // standard sounds + if (sound_action != ACTION_OTHER && + sound_action != ACTION_DEFAULT) + return sound_effect; + + // special sounds + switch (sample) + { + case GD_S_DIAMOND_RANDOM: + nr = GetSimpleRandom(8); + sound_effect = SND_BD_DIAMOND_IMPACT_RANDOM_1 + nr; + break; + + case GD_S_DIAMOND_1: + case GD_S_DIAMOND_2: + case GD_S_DIAMOND_3: + case GD_S_DIAMOND_4: + case GD_S_DIAMOND_5: + case GD_S_DIAMOND_6: + case GD_S_DIAMOND_7: + case GD_S_DIAMOND_8: + nr = sample - GD_S_DIAMOND_1; + sound_effect = SND_BD_DIAMOND_IMPACT_RANDOM_1 + nr; + break; + + case GD_S_TIMEOUT_0: + case GD_S_TIMEOUT_1: + case GD_S_TIMEOUT_2: + case GD_S_TIMEOUT_3: + case GD_S_TIMEOUT_4: + case GD_S_TIMEOUT_5: + case GD_S_TIMEOUT_6: + case GD_S_TIMEOUT_7: + case GD_S_TIMEOUT_8: + case GD_S_TIMEOUT_9: + case GD_S_TIMEOUT_10: + nr = sample - GD_S_TIMEOUT_0; + sound_effect = SND_GAME_RUNNING_OUT_OF_TIME_0 + nr; + + if (getSoundInfoEntryFilename(sound_effect) == NULL && sample != GD_S_TIMEOUT_0) + sound_effect = SND_GAME_RUNNING_OUT_OF_TIME; + break; + + case GD_S_FINISHED: + sound_effect = SND_GAME_LEVELTIME_BONUS; + break; + + case GD_S_BONUS_LIFE: + sound_effect = SND_GAME_HEALTH_BONUS; + break; + + default: + sound_effect = SND_UNDEFINED; + break; + } + + return sound_effect; +} + +void PlayLevelSound_BD(int xx, int yy, int element_bd, int sample) +{ + int element = (element_bd > -1 ? map_element_BD_to_RND(element_bd) : 0); + int sound_effect = getSoundEffect_BD(element, sample); + int sound_action = getSoundAction_BD(sample); + boolean is_loop_sound = IS_LOOP_SOUND(sound_effect); + int offset = 0; + int x = xx - offset; + int y = yy - offset; + + if (sound_action == ACTION_OTHER) + is_loop_sound = FALSE; + + if (sound_effect != SND_UNDEFINED) + PlayLevelSoundExt(x, y, sound_effect, is_loop_sound); +} + +void StopSound_BD(int element_bd, int sample) +{ + int element = (element_bd > -1 ? map_element_BD_to_RND(element_bd) : 0); + int sound_effect = getSoundEffect_BD(element, sample); + + if (sound_effect != SND_UNDEFINED) + StopSound(sound_effect); +} + +boolean isSoundPlaying_BD(int element_bd, int sample) +{ + int element = (element_bd > -1 ? map_element_BD_to_RND(element_bd) : 0); + int sound_effect = getSoundEffect_BD(element, sample); + + if (sound_effect != SND_UNDEFINED) + return isSoundPlaying(sound_effect); + + return FALSE; +} + void PlayLevelSound_EM(int xx, int yy, int element_em, int sample) { int element = (element_em > -1 ? map_element_EM_to_RND_game(element_em) : 0); @@ -15644,9 +16072,15 @@ void RequestQuitGameExt(boolean skip_request, boolean quick_quit, char *message) } if (network.enabled) + { SendToServer_StopPlaying(NETWORK_STOP_BY_PLAYER); + } else { + // when using BD game engine, cover screen before fading out + if (!quick_quit && level.game_engine_type == GAME_ENGINE_TYPE_BD) + game_bd.cover_screen = TRUE; + if (quick_quit) FadeSkipNextFadeIn(); @@ -15746,10 +16180,14 @@ boolean CheckRestartGame(void) return FALSE; } - // do not handle game over if request dialog is already active + // do not ask to play again if request dialog is already active if (game.request_active) return FALSE; + // do not ask to play again if request dialog already handled + if (game.RestartGameRequested) + return FALSE; + // do not ask to play again if game was never actually played if (!game.GamePlayed) return FALSE; @@ -15758,11 +16196,35 @@ boolean CheckRestartGame(void) if (!setup.ask_on_game_over) return FALSE; + game.RestartGameRequested = TRUE; + RequestRestartGame(); return TRUE; } +boolean checkGameRunning(void) +{ + if (game_status != GAME_MODE_PLAYING) + return FALSE; + + if (level.game_engine_type == GAME_ENGINE_TYPE_BD && !checkGameRunning_BD()) + return FALSE; + + return TRUE; +} + +boolean checkGamePlaying(void) +{ + if (game_status != GAME_MODE_PLAYING) + return FALSE; + + if (level.game_engine_type == GAME_ENGINE_TYPE_BD && !checkGamePlaying_BD()) + return FALSE; + + return TRUE; +} + boolean checkGameSolved(void) { // set for all game engines if level was solved @@ -15771,7 +16233,9 @@ boolean checkGameSolved(void) boolean checkGameFailed(void) { - if (level.game_engine_type == GAME_ENGINE_TYPE_EM) + if (level.game_engine_type == GAME_ENGINE_TYPE_BD) + return (game_bd.game_over && !game_bd.level_solved); + else if (level.game_engine_type == GAME_ENGINE_TYPE_EM) return (game_em.game_over && !game_em.level_solved); else if (level.game_engine_type == GAME_ENGINE_TYPE_SP) return (game_sp.game_over && !game_sp.level_solved); @@ -15967,6 +16431,7 @@ static ListNode *SaveEngineSnapshotBuffers(void) SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(TimeFrames)); SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(TimePlayed)); SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(TimeLeft)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(TapeTimeFrames)); SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(TapeTime)); SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(ScreenMovDir)); @@ -16182,6 +16647,11 @@ static struct GAME_CTRL_ID_LOAD, NULL, TRUE, FALSE, "load game" }, + { + IMG_GFX_GAME_BUTTON_RESTART, &game.button.restart, + GAME_CTRL_ID_RESTART, NULL, + TRUE, FALSE, "restart game" + }, { IMG_GFX_GAME_BUTTON_PANEL_STOP, &game.button.panel_stop, GAME_CTRL_ID_PANEL_STOP, NULL, @@ -16197,6 +16667,11 @@ static struct GAME_CTRL_ID_PANEL_PLAY, NULL, FALSE, FALSE, "play game" }, + { + IMG_GFX_GAME_BUTTON_PANEL_RESTART, &game.button.panel_restart, + GAME_CTRL_ID_PANEL_RESTART, NULL, + FALSE, FALSE, "restart game" + }, { IMG_GFX_GAME_BUTTON_TOUCH_STOP, &game.button.touch_stop, GAME_CTRL_ID_TOUCH_STOP, NULL, @@ -16207,6 +16682,11 @@ static struct GAME_CTRL_ID_TOUCH_PAUSE, NULL, FALSE, TRUE, "pause game" }, + { + IMG_GFX_GAME_BUTTON_TOUCH_RESTART, &game.button.touch_restart, + GAME_CTRL_ID_TOUCH_RESTART, NULL, + FALSE, TRUE, "restart game" + }, { IMG_GFX_GAME_BUTTON_SOUND_MUSIC, &game.button.sound_music, SOUND_CTRL_ID_MUSIC, &setup.sound_music, @@ -16286,7 +16766,10 @@ void CreateGameButtons(void) id == GAME_CTRL_ID_PLAY || id == GAME_CTRL_ID_PANEL_PLAY || id == GAME_CTRL_ID_SAVE || - id == GAME_CTRL_ID_LOAD) + id == GAME_CTRL_ID_LOAD || + id == GAME_CTRL_ID_RESTART || + id == GAME_CTRL_ID_PANEL_RESTART || + id == GAME_CTRL_ID_TOUCH_RESTART) { button_type = GD_TYPE_NORMAL_BUTTON; checked = FALSE; @@ -16409,6 +16892,10 @@ void ModifyPauseButtons(void) }; int i; + // do not redraw pause button on closed door (may happen when restarting game) + if (!(GetDoorState() & DOOR_OPEN_1)) + return; + for (i = 0; ids[i] > -1; i++) ModifyGadget(game_gadget[ids[i]], GDI_CHECKED, tape.pausing, GDI_END); } @@ -16630,6 +17117,13 @@ static void HandleGameButtonsExt(int id, int button) TapeQuickLoad(); break; + case GAME_CTRL_ID_RESTART: + case GAME_CTRL_ID_PANEL_RESTART: + case GAME_CTRL_ID_TOUCH_RESTART: + TapeRestartGame(); + + break; + case SOUND_CTRL_ID_MUSIC: case SOUND_CTRL_ID_PANEL_MUSIC: if (setup.sound_music)