// 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_NEEDED 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
{
&game.panel.gems,
TYPE_INTEGER,
},
+ {
+ GAME_PANEL_GEMS_NEEDED,
+ &game.panel.gems_needed,
+ 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,
#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
}
}
+static void InitFieldForEngine_RND(int x, int y)
+{
+ int element = Tile[x][y];
+
+ // convert BD engine elements to corresponding R'n'D engine elements
+ element = (element == EL_BD_EMPTY ? EL_EMPTY :
+ element == EL_BD_PLAYER ? EL_PLAYER_1 :
+ element == EL_BD_INBOX ? EL_PLAYER_1 :
+ element == EL_BD_SAND ? EL_SAND :
+ element == EL_BD_STEELWALL ? EL_STEELWALL :
+ element == EL_BD_EXIT_CLOSED ? EL_EXIT_CLOSED :
+ element == EL_BD_EXIT_OPEN ? EL_EXIT_OPEN :
+ element);
+
+ Tile[x][y] = element;
+}
+
+static void InitFieldForEngine(int x, int y)
+{
+ if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
+ InitFieldForEngine_RND(x, y);
+}
+
static void InitField(int x, int y, boolean init_game)
{
int element = Tile[x][y];
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 ?
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 ?
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_needed = level.gems_needed;
+ int gems_collected = (level.game_engine_type == GAME_ENGINE_TYPE_BD ?
+ game_bd.game->cave->diamonds_collected :
+ gems_needed - 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 :
// 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_NEEDED].value = gems_needed;
+ 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++)
if (PANEL_DEACTIVATED(pos))
continue;
- if (pos->class == get_hash_from_key("extra_panel_items") &&
+ if (pos->class == get_hash_from_string("extra_panel_items") &&
!setup.prefer_extra_panel_items)
continue;
int width, height;
int dst_x = PANEL_XPOS(pos);
int dst_y = PANEL_YPOS(pos);
- boolean skip = (pos->class == get_hash_from_key("mm_engine_only") &&
+ boolean skip = (pos->class == get_hash_from_string("mm_engine_only") &&
level.game_engine_type != GAME_ENGINE_TYPE_MM);
if (graphic != IMG_UNDEFINED && !skip)
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));
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;
}
}
level.game_engine_type == GAME_ENGINE_TYPE_EM &&
!setup.forced_scroll_delay ? 0 :
setup.scroll_delay ? setup.scroll_delay_value : 0);
- game.scroll_delay_value =
- MIN(MAX(MIN_SCROLL_DELAY, game.scroll_delay_value), MAX_SCROLL_DELAY);
+ if (game.forced_scroll_delay_value == -1)
+ game.scroll_delay_value =
+ MIN(MAX(MIN_SCROLL_DELAY, game.scroll_delay_value), MAX_SCROLL_DELAY);
// ---------- initialize game engine snapshots ------------------------------
for (i = 0; i < MAX_PLAYERS; i++)
TimeFrames = 0;
TimePlayed = 0;
TimeLeft = level.time;
+
+ TapeTimeFrames = 0;
TapeTime = 0;
ScreenMovDir = MV_NONE;
game.LevelSolved_CountingScore = 0;
game.LevelSolved_CountingHealth = 0;
+ game.RestartGameRequested = FALSE;
+
game.panel.active = TRUE;
game.no_level_time_limit = (level.time == 0);
SCAN_PLAYFIELD(x, y)
{
+ InitFieldForEngine(x, y);
+
if (emulate_bd && !IS_BD_ELEMENT(Tile[x][y]))
emulate_bd = FALSE;
if (emulate_sp && !IS_SP_ELEMENT(Tile[x][y]))
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];
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();
}
}
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();
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 ?
LevelSolved_SetFinalGameValues();
}
+static boolean AdvanceToNextLevel(void)
+{
+ if (setup.increment_levels &&
+ level_nr < leveldir_current->last_level &&
+ !network_playing)
+ {
+ level_nr++; // advance to next level
+ TapeErase(); // start with empty tape
+
+ if (setup.auto_play_next_level)
+ {
+ scores.continue_playing = TRUE;
+ scores.next_level_nr = level_nr;
+
+ LoadLevel(level_nr);
+
+ SaveLevelSetup_SeriesInfo();
+ }
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
void GameWon(void)
{
static int time_count_steps;
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;
}
// 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;
int last_level_nr = levelset.level_nr;
boolean tape_saved = FALSE;
- game.LevelSolved_GameEnd = TRUE;
+ // Important note: This function is not only called after "GameWon()", but also after
+ // "game over" (if automatically asking for restarting the game is disabled in setup)
+
+ if (game.LevelSolved)
+ game.LevelSolved_GameEnd = TRUE;
if (game.LevelSolved_SaveTape && !score_info_tape_play)
{
return;
}
- if (!game.LevelSolved_SaveScore)
+ if (!game.GamePlayed || (!game.LevelSolved_SaveScore && !level.bd_intermission))
{
SetGameStatus(GAME_MODE_MAIN);
}
// save score and score tape before potentially erasing tape below
- NewHighScore(last_level_nr, tape_saved);
+ if (game.LevelSolved_SaveScore)
+ NewHighScore(last_level_nr, tape_saved);
- if (setup.increment_levels &&
- level_nr < leveldir_current->last_level &&
- !network_playing)
- {
- level_nr++; // advance to next level
- TapeErase(); // start with empty tape
-
- if (setup.auto_play_next_level)
- {
- scores.continue_playing = TRUE;
- scores.next_level_nr = level_nr;
+ // increment and load next level (if possible and not configured otherwise)
+ AdvanceToNextLevel();
- LoadLevel(level_nr);
-
- SaveLevelSetup_SeriesInfo();
- }
- }
-
- if (scores.last_added >= 0 && setup.show_scores_after_game)
+ if (game.LevelSolved_SaveScore && scores.last_added >= 0 && setup.show_scores_after_game)
{
SetGameStatus(GAME_MODE_SCORES);
{
// relocation _without_ centering of screen
- int center_scroll_x = SCROLL_POSITION_X(old_x);
- int center_scroll_y = SCROLL_POSITION_Y(old_y);
- int offset_x = x + (scroll_x - center_scroll_x);
- int offset_y = y + (scroll_y - center_scroll_y);
+ // apply distance between old and new player position to scroll position
+ int shifted_scroll_x = scroll_x + (x - old_x);
+ int shifted_scroll_y = scroll_y + (y - old_y);
- // for new screen position, apply previous offset to center position
- new_scroll_x = SCROLL_POSITION_X(offset_x);
- new_scroll_y = SCROLL_POSITION_Y(offset_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)
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;
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;
if (GFX_CRUMBLED(new_element))
TEST_DrawLevelFieldCrumbledNeighbours(x, y);
+ if (old_element == EL_EXPLOSION)
+ {
+ Store[x][y] = Store2[x][y] = 0;
+
+ // check if new element replaces an exploding player, requiring cleanup
+ if (IS_PLAYER(x, y) && !PLAYERINFO(x, y)->present)
+ StorePlayer[x][y] = 0;
+ }
+
// 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)
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
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)
{
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)
{
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)
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)
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
}
}
+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;
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;
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++)
{
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 */
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)
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);
{
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.)
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();
}
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];
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) ||
(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. */
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) :
PlayMusicLoop(music_nr);
}
+static int getSoundAction_BD(int sample)
+{
+ switch (sample)
+ {
+ case GD_S_STONE_PUSHING:
+ case GD_S_MEGA_STONE_PUSHING:
+ case GD_S_FLYING_STONE_PUSHING:
+ case GD_S_WAITING_STONE_PUSHING:
+ case GD_S_CHASING_STONE_PUSHING:
+ case GD_S_NUT_PUSHING:
+ case GD_S_NITRO_PACK_PUSHING:
+ case GD_S_BLADDER_PUSHING:
+ case GD_S_BOX_PUSHING:
+ return ACTION_PUSHING;
+
+ case GD_S_STONE_FALLING:
+ case GD_S_MEGA_STONE_FALLING:
+ case GD_S_FLYING_STONE_FALLING:
+ case GD_S_NUT_FALLING:
+ case GD_S_DIRT_BALL_FALLING:
+ case GD_S_DIRT_LOOSE_FALLING:
+ case GD_S_NITRO_PACK_FALLING:
+ case GD_S_FALLING_WALL_FALLING:
+ return ACTION_FALLING;
+
+ case GD_S_STONE_IMPACT:
+ case GD_S_MEGA_STONE_IMPACT:
+ case GD_S_FLYING_STONE_IMPACT:
+ case GD_S_NUT_IMPACT:
+ case GD_S_DIRT_BALL_IMPACT:
+ case GD_S_DIRT_LOOSE_IMPACT:
+ case GD_S_NITRO_PACK_IMPACT:
+ case GD_S_FALLING_WALL_IMPACT:
+ return ACTION_IMPACT;
+
+ case GD_S_NUT_CRACKING:
+ return ACTION_BREAKING;
+
+ case GD_S_EXPANDING_WALL:
+ case GD_S_WALL_REAPPEARING:
+ case GD_S_SLIME:
+ case GD_S_LAVA:
+ case GD_S_ACID_SPREADING:
+ return ACTION_GROWING;
+
+ case GD_S_DIAMOND_COLLECTING:
+ case GD_S_FLYING_DIAMOND_COLLECTING:
+ case GD_S_SKELETON_COLLECTING:
+ case GD_S_PNEUMATIC_COLLECTING:
+ case GD_S_BOMB_COLLECTING:
+ case GD_S_CLOCK_COLLECTING:
+ case GD_S_SWEET_COLLECTING:
+ case GD_S_KEY_COLLECTING:
+ case GD_S_DIAMOND_KEY_COLLECTING:
+ return ACTION_COLLECTING;
+
+ case GD_S_BOMB_PLACING:
+ case GD_S_REPLICATOR:
+ return ACTION_DROPPING;
+
+ case GD_S_BLADDER_MOVING:
+ return ACTION_MOVING;
+
+ case GD_S_BLADDER_SPENDER:
+ case GD_S_BLADDER_CONVERTING:
+ case GD_S_GRAVITY_CHANGING:
+ return ACTION_CHANGING;
+
+ case GD_S_BITER_EATING:
+ return ACTION_EATING;
+
+ case GD_S_DOOR_OPENING:
+ case GD_S_CRACKING:
+ return ACTION_OPENING;
+
+ case GD_S_DIRT_WALKING:
+ return ACTION_DIGGING;
+
+ case GD_S_EMPTY_WALKING:
+ 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_TELEPORTER:
+ return ACTION_PASSING;
+
+ case GD_S_EXPLODING:
+ case GD_S_BOMB_EXPLODING:
+ case GD_S_GHOST_EXPLODING:
+ case GD_S_VOODOO_EXPLODING:
+ case GD_S_NITRO_PACK_EXPLODING:
+ return ACTION_EXPLODING;
+
+ case GD_S_COVERING:
+ case GD_S_AMOEBA:
+ case GD_S_MAGIC_WALL:
+ case GD_S_PNEUMATIC_HAMMER:
+ case GD_S_WATER:
+ return ACTION_ACTIVE;
+
+ case GD_S_DIAMOND_FALLING_RANDOM:
+ case GD_S_DIAMOND_FALLING_1:
+ case GD_S_DIAMOND_FALLING_2:
+ case GD_S_DIAMOND_FALLING_3:
+ case GD_S_DIAMOND_FALLING_4:
+ case GD_S_DIAMOND_FALLING_5:
+ case GD_S_DIAMOND_FALLING_6:
+ case GD_S_DIAMOND_FALLING_7:
+ case GD_S_DIAMOND_FALLING_8:
+ case GD_S_DIAMOND_IMPACT_RANDOM:
+ case GD_S_DIAMOND_IMPACT_1:
+ case GD_S_DIAMOND_IMPACT_2:
+ case GD_S_DIAMOND_IMPACT_3:
+ case GD_S_DIAMOND_IMPACT_4:
+ case GD_S_DIAMOND_IMPACT_5:
+ case GD_S_DIAMOND_IMPACT_6:
+ case GD_S_DIAMOND_IMPACT_7:
+ case GD_S_DIAMOND_IMPACT_8:
+ case GD_S_FLYING_DIAMOND_FALLING_RANDOM:
+ case GD_S_FLYING_DIAMOND_FALLING_1:
+ case GD_S_FLYING_DIAMOND_FALLING_2:
+ case GD_S_FLYING_DIAMOND_FALLING_3:
+ case GD_S_FLYING_DIAMOND_FALLING_4:
+ case GD_S_FLYING_DIAMOND_FALLING_5:
+ case GD_S_FLYING_DIAMOND_FALLING_6:
+ case GD_S_FLYING_DIAMOND_FALLING_7:
+ case GD_S_FLYING_DIAMOND_FALLING_8:
+ case GD_S_FLYING_DIAMOND_IMPACT_RANDOM:
+ case GD_S_FLYING_DIAMOND_IMPACT_1:
+ case GD_S_FLYING_DIAMOND_IMPACT_2:
+ case GD_S_FLYING_DIAMOND_IMPACT_3:
+ case GD_S_FLYING_DIAMOND_IMPACT_4:
+ case GD_S_FLYING_DIAMOND_IMPACT_5:
+ case GD_S_FLYING_DIAMOND_IMPACT_6:
+ case GD_S_FLYING_DIAMOND_IMPACT_7:
+ case GD_S_FLYING_DIAMOND_IMPACT_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:
+ // trigger special post-processing (and force sound to be non-looping)
+ return ACTION_OTHER;
+
+ case GD_S_AMOEBA_MAGIC:
+ case GD_S_FINISHED:
+ // trigger special post-processing (and force sound to be looping)
+ 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 post-processing for some sounds
+ switch (sample)
+ {
+ case GD_S_DIAMOND_FALLING_RANDOM:
+ case GD_S_DIAMOND_FALLING_1:
+ case GD_S_DIAMOND_FALLING_2:
+ case GD_S_DIAMOND_FALLING_3:
+ case GD_S_DIAMOND_FALLING_4:
+ case GD_S_DIAMOND_FALLING_5:
+ case GD_S_DIAMOND_FALLING_6:
+ case GD_S_DIAMOND_FALLING_7:
+ case GD_S_DIAMOND_FALLING_8:
+ nr = (sample == GD_S_DIAMOND_FALLING_RANDOM ? GetSimpleRandom(8) :
+ sample - GD_S_DIAMOND_FALLING_1);
+ sound_effect = SND_BD_DIAMOND_FALLING_RANDOM_1 + nr;
+
+ if (getSoundInfoEntryFilename(sound_effect) == NULL)
+ sound_effect = SND_BD_DIAMOND_FALLING;
+ break;
+
+ case GD_S_DIAMOND_IMPACT_RANDOM:
+ case GD_S_DIAMOND_IMPACT_1:
+ case GD_S_DIAMOND_IMPACT_2:
+ case GD_S_DIAMOND_IMPACT_3:
+ case GD_S_DIAMOND_IMPACT_4:
+ case GD_S_DIAMOND_IMPACT_5:
+ case GD_S_DIAMOND_IMPACT_6:
+ case GD_S_DIAMOND_IMPACT_7:
+ case GD_S_DIAMOND_IMPACT_8:
+ nr = (sample == GD_S_DIAMOND_IMPACT_RANDOM ? GetSimpleRandom(8) :
+ sample - GD_S_DIAMOND_IMPACT_1);
+ sound_effect = SND_BD_DIAMOND_IMPACT_RANDOM_1 + nr;
+
+ if (getSoundInfoEntryFilename(sound_effect) == NULL)
+ sound_effect = SND_BD_DIAMOND_IMPACT;
+ break;
+
+ case GD_S_FLYING_DIAMOND_FALLING_RANDOM:
+ case GD_S_FLYING_DIAMOND_FALLING_1:
+ case GD_S_FLYING_DIAMOND_FALLING_2:
+ case GD_S_FLYING_DIAMOND_FALLING_3:
+ case GD_S_FLYING_DIAMOND_FALLING_4:
+ case GD_S_FLYING_DIAMOND_FALLING_5:
+ case GD_S_FLYING_DIAMOND_FALLING_6:
+ case GD_S_FLYING_DIAMOND_FALLING_7:
+ case GD_S_FLYING_DIAMOND_FALLING_8:
+ nr = (sample == GD_S_FLYING_DIAMOND_FALLING_RANDOM ? GetSimpleRandom(8) :
+ sample - GD_S_FLYING_DIAMOND_FALLING_1);
+ sound_effect = SND_BD_FLYING_DIAMOND_FALLING_RANDOM_1 + nr;
+
+ if (getSoundInfoEntryFilename(sound_effect) == NULL)
+ sound_effect = SND_BD_FLYING_DIAMOND_FALLING;
+ break;
+
+ case GD_S_FLYING_DIAMOND_IMPACT_RANDOM:
+ case GD_S_FLYING_DIAMOND_IMPACT_1:
+ case GD_S_FLYING_DIAMOND_IMPACT_2:
+ case GD_S_FLYING_DIAMOND_IMPACT_3:
+ case GD_S_FLYING_DIAMOND_IMPACT_4:
+ case GD_S_FLYING_DIAMOND_IMPACT_5:
+ case GD_S_FLYING_DIAMOND_IMPACT_6:
+ case GD_S_FLYING_DIAMOND_IMPACT_7:
+ case GD_S_FLYING_DIAMOND_IMPACT_8:
+ nr = (sample == GD_S_FLYING_DIAMOND_IMPACT_RANDOM ? GetSimpleRandom(8) :
+ sample - GD_S_FLYING_DIAMOND_IMPACT_1);
+ sound_effect = SND_BD_FLYING_DIAMOND_IMPACT_RANDOM_1 + nr;
+
+ if (getSoundInfoEntryFilename(sound_effect) == NULL)
+ sound_effect = SND_BD_FLYING_DIAMOND_IMPACT;
+ 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_BONUS_LIFE:
+ sound_effect = SND_GAME_HEALTH_BONUS;
+ break;
+
+ case GD_S_AMOEBA_MAGIC:
+ sound_effect = SND_BD_AMOEBA_OTHER;
+ break;
+
+ case GD_S_FINISHED:
+ sound_effect = SND_GAME_LEVELTIME_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_game(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;
+
+ // some sound actions are always looping in native BD game engine
+ if (sound_action == ACTION_DEFAULT)
+ is_loop_sound = TRUE;
+
+ // some sound actions are always non-looping in native BD game engine
+ if (sound_action == ACTION_FALLING ||
+ sound_action == ACTION_MOVING ||
+ 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_game(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_game(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);
}
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();
int request_mode = (has_started_game ? REQ_ASK : REQ_CONFIRM);
int door_state = DOOR_CLOSE_1;
- if (Request(message, request_mode | REQ_STAY_OPEN) && has_started_game)
+ boolean restart_wanted = (Request(message, request_mode | REQ_STAY_OPEN) && has_started_game);
+
+ // if no restart wanted, continue with next level for BD style intermission levels
+ if (!restart_wanted && !level_editor_test_game && level.bd_intermission)
+ {
+ boolean success = AdvanceToNextLevel();
+
+ restart_wanted = (success && setup.auto_play_next_level);
+ }
+
+ if (restart_wanted)
{
CloseDoor(door_state);
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;
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
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);
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));
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,
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,
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,
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;
};
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);
}
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)