+
+void InitGameEngine_BD(void)
+{
+ game_bd.level_solved = FALSE;
+ game_bd.game_over = FALSE;
+ game_bd.cover_screen = FALSE;
+
+ gd_caveset_last_selected = native_bd_level.cave_nr;
+ gd_caveset_last_selected_level = native_bd_level.level_nr;
+
+ if (game_bd.game != NULL)
+ gd_game_free(game_bd.game);
+
+ game_bd.game = gd_game_new(native_bd_level.cave_nr, native_bd_level.level_nr);
+
+ game_bd.game->itercycle = 0;
+ game_bd.game->itermax = 8; // default; dynamically changed at runtime
+ game_bd.game->itermax_last = game_bd.game->itermax;
+ game_bd.game->itermax2[0] = game_bd.game->itermax;
+ game_bd.game->itermax2[1] = game_bd.game->itermax;
+
+ game_bd.player_moving = FALSE;
+ game_bd.player_snapping = FALSE;
+
+ // default: start with completely covered playfield
+ int next_state = GAME_INT_START_UNCOVER + 1;
+
+ // when skipping uncovering, start with uncovered playfield
+ if (setup.bd_skip_uncovering)
+ next_state = GAME_INT_LOAD_CAVE + 1;
+
+ // first iteration loads and prepares the cave (may change colors)
+ play_game_func(game_bd.game, 0);
+
+ // prepare tile bitmap with level-specific colors, if available
+ PrepareGameTileBitmap_BD();
+
+ // fast-forward game engine to selected state (covered or uncovered)
+ while (game_bd.game->state_counter < next_state)
+ play_game_func(game_bd.game, 0);
+
+ // when skipping uncovering, continue with uncovered playfield
+ if (setup.bd_skip_uncovering)
+ game_bd.game->state_counter = GAME_INT_UNCOVER_ALL + 1;
+ else if (isLevelEditorFastStart())
+ game_bd.game->state_counter = GAME_INT_UNCOVER_ALL - 8;
+
+ if (setup.bd_skip_uncovering || isLevelEditorFastStart())
+ gd_scroll(game_bd.game, TRUE, TRUE);
+
+ ClearRectangle(gd_screen_bitmap, 0, 0, SXSIZE, SYSIZE);
+
+ RedrawPlayfield_BD(TRUE);
+
+ UpdateGameDoorValues_BD();
+}
+
+void GameActions_BD(byte action[MAX_PLAYERS])
+{
+ GdCave *cave = game_bd.game->cave;
+ boolean player_found = FALSE;
+ int player_x = 0;
+ int player_y = 0;
+ int x, y;
+
+ if (cave->getp)
+ {
+ for (y = 0; y < cave->h && !player_found; y++)
+ {
+ for (x = 0; x < cave->w && !player_found; x++)
+ {
+ int element = *cave->getp(cave, x, y);
+
+ if (element == O_PLAYER ||
+ element == O_PLAYER_BOMB ||
+ element == O_PLAYER_STIRRING ||
+ element == O_PLAYER_PNEUMATIC_LEFT ||
+ element == O_PLAYER_PNEUMATIC_RIGHT)
+ {
+ player_x = x;
+ player_y = y;
+
+ player_found = TRUE;
+ }
+ }
+ }
+ }
+
+ UpdateEngineValues(get_scroll_x(),
+ get_scroll_y(),
+ player_x,
+ player_y);
+
+ if (setup.bd_skip_hatching && !game_bd.game->cave->hatched &&
+ game_bd.game->state_counter == GAME_INT_CAVE_RUNNING)
+ {
+ // fast-forward game engine until player hatched
+ while (!game_bd.game->cave->hatched)
+ {
+ play_game_func(game_bd.game, 0);
+
+ // also record or replay tape action during fast-forward
+ action = TapeCorrectAction_BD(action);
+ }
+ }
+
+ play_game_func(game_bd.game, action[0]);
+
+ // scroll without iterating engine if player out of sight (mainly due to wrap-around)
+ // (this is needed to prevent broken tapes in case of viewport or tile size changes)
+ while (game_bd.game->out_of_window)
+ {
+ RedrawPlayfield_BD(TRUE);
+
+ BlitScreenToBitmap_BD(backbuffer);
+
+ BackToFront();
+
+ play_game_func(game_bd.game, action[0]);
+ }
+
+ boolean single_step_mode_paused =
+ CheckSingleStepMode_BD(check_iteration_reached(game_bd.game),
+ game_bd.player_moving,
+ game_bd.player_snapping);
+
+ // draw final movement animation frame before going to single step pause mode
+ if (single_step_mode_paused)
+ game_bd.game->itercycle = game_bd.game->itermax - 1;
+
+ RedrawPlayfield_BD(FALSE);
+
+ UpdateGameDoorValues_BD();
+}
+
+
+// ============================================================================
+// graphics functions
+// ============================================================================
+
+// check if native BD graphics engine requested in custom graphics configuration
+boolean use_native_bd_graphics_engine(void)
+{
+ return game.use_native_bd_graphics_engine;
+}
+
+// check if smooth game element movements selected in setup menu
+boolean use_bd_smooth_movements(void)
+{
+ return ((setup.bd_smooth_movements == STATE_TRUE) ||
+ (setup.bd_smooth_movements == STATE_AUTO && !use_native_bd_graphics_engine()));
+}
+
+// check if player pushing graphics selected in setup menu
+boolean use_bd_pushing_graphics(void)
+{
+ return ((setup.bd_pushing_graphics == STATE_TRUE) ||
+ (setup.bd_pushing_graphics == STATE_AUTO && !use_native_bd_graphics_engine()));
+}
+
+// check if player up/down graphics selected in setup menu
+boolean use_bd_up_down_graphics(void)
+{
+ return ((setup.bd_up_down_graphics == STATE_TRUE) ||
+ (setup.bd_up_down_graphics == STATE_AUTO && !use_native_bd_graphics_engine()));
+}
+
+// check if element falling sounds selected in setup menu
+boolean use_bd_falling_sounds(void)
+{
+ return ((setup.bd_falling_sounds == STATE_TRUE) ||
+ (setup.bd_falling_sounds == STATE_AUTO && game.use_native_bd_sound_engine));
+}
+
+boolean hasColorTemplate_BD(void)
+{
+ return gd_bitmap_has_c64_colors(graphic_info_bd_color_template.bitmap);
+}
+
+Bitmap **GetTitleScreenBitmaps_BD(void)
+{
+ Bitmap **title_screen_bitmaps = gd_get_title_screen_bitmaps();
+
+ if (title_screen_bitmaps == NULL || title_screen_bitmaps[0] == NULL)
+ return NULL;
+
+ return title_screen_bitmaps;
+}
+
+void CoverScreen_BD(void)
+{
+ game_bd.cover_screen = FALSE;
+
+ if (setup.bd_skip_uncovering)
+ return;
+
+ game_bd.game->state_counter = GAME_INT_COVER_START;
+
+ // play game engine (with normal speed) until cave covered
+ while (game_bd.game->state_counter < GAME_INT_COVER_ALL + 1)
+ {
+ play_game_func(game_bd.game, 0);
+
+ RedrawPlayfield_BD(TRUE);
+
+ BlitScreenToBitmap_BD(backbuffer);
+
+ BackToFront();
+ }
+
+ // stop uncovering loop sound when not using native sound engine
+ FadeSounds();
+}
+
+void BlitScreenToBitmap_BD(Bitmap *target_bitmap)
+{
+ GdCave *cave = native_bd_level.cave;
+ int xsize = SXSIZE;
+ int ysize = SYSIZE;
+ int full_xsize = (cave->x2 - cave->x1 + 1) * TILESIZE_VAR;
+ int full_ysize = (cave->y2 - cave->y1 + 1) * TILESIZE_VAR;
+ int sx = SX + (full_xsize < xsize ? (xsize - full_xsize) / 2 : 0);
+ int sy = SY + (full_ysize < ysize ? (ysize - full_ysize) / 2 : 0);
+ int sxsize = (full_xsize < xsize ? full_xsize : xsize);
+ int sysize = (full_ysize < ysize ? full_ysize : ysize);
+
+ BlitBitmap(gd_screen_bitmap, target_bitmap, 0, 0, sxsize, sysize, sx, sy);
+}
+
+void RedrawPlayfield_BD(boolean force_redraw)
+{
+ gd_drawcave(gd_screen_bitmap, game_bd.game, force_redraw);
+}
+
+
+// ============================================================================
+// snapshot functions
+// ============================================================================
+
+void SaveEngineSnapshotValues_BD(void)
+{
+ GdGame *game = game_bd.game;
+ GdCave *cave = game_bd.game->cave;
+ int x, y;
+
+ engine_snapshot_bd.game = *game;
+
+ for (y = 0; y < cave->h; y++)
+ {
+ for (x = 0; x < cave->w; x++)
+ {
+ engine_snapshot_bd.element_buffer[x][y] = game->element_buffer[y][x];
+ engine_snapshot_bd.last_element_buffer[x][y] = game->last_element_buffer[y][x];
+ engine_snapshot_bd.dir_buffer_from[x][y] = game->dir_buffer_from[y][x];
+ engine_snapshot_bd.dir_buffer_to[x][y] = game->dir_buffer_to[y][x];
+ engine_snapshot_bd.gfx_buffer[x][y] = game->gfx_buffer[y][x];
+ }
+ }
+
+ engine_snapshot_bd.cave = *cave;
+
+ for (y = 0; y < cave->h; y++)
+ {
+ for (x = 0; x < cave->w; x++)
+ {
+ engine_snapshot_bd.map[x][y] = cave->map[y][x];
+
+ if (cave->hammered_walls_reappear)
+ engine_snapshot_bd.hammered_reappear[x][y] = cave->hammered_reappear[y][x];
+ }
+ }
+}
+
+void LoadEngineSnapshotValues_BD(void)
+{
+ GdGame *game = game_bd.game;
+ GdCave *cave = game_bd.game->cave;
+ int x, y;
+
+ // copy pointers
+ engine_snapshot_bd.game.cave = game->cave;
+ engine_snapshot_bd.game.original_cave = game->original_cave;
+
+ engine_snapshot_bd.game.element_buffer = game->element_buffer;
+ engine_snapshot_bd.game.last_element_buffer = game->last_element_buffer;
+ engine_snapshot_bd.game.dir_buffer_from = game->dir_buffer_from;
+ engine_snapshot_bd.game.dir_buffer_to = game->dir_buffer_to;
+ engine_snapshot_bd.game.gfx_buffer = game->gfx_buffer;
+
+ *game = engine_snapshot_bd.game;
+
+ for (y = 0; y < cave->h; y++)
+ {
+ for (x = 0; x < cave->w; x++)
+ {
+ game->element_buffer[y][x] = engine_snapshot_bd.element_buffer[x][y];
+ game->last_element_buffer[y][x] = engine_snapshot_bd.last_element_buffer[x][y];
+ game->dir_buffer_from[y][x] = engine_snapshot_bd.dir_buffer_from[x][y];
+ game->dir_buffer_to[y][x] = engine_snapshot_bd.dir_buffer_to[x][y];
+ game->gfx_buffer[y][x] = engine_snapshot_bd.gfx_buffer[x][y];
+ }
+ }
+
+ // copy pointers
+ engine_snapshot_bd.cave.story = cave->story;
+ engine_snapshot_bd.cave.remark = cave->remark;
+ engine_snapshot_bd.cave.tags = cave->tags;
+ engine_snapshot_bd.cave.map = cave->map;
+ engine_snapshot_bd.cave.objects = cave->objects;
+ engine_snapshot_bd.cave.replays = cave->replays;
+ engine_snapshot_bd.cave.random = cave->random;
+ engine_snapshot_bd.cave.objects_order = cave->objects_order;
+ engine_snapshot_bd.cave.hammered_reappear = cave->hammered_reappear;
+
+ *cave = engine_snapshot_bd.cave;
+
+ for (y = 0; y < cave->h; y++)
+ {
+ for (x = 0; x < cave->w; x++)
+ {
+ cave->map[y][x] = engine_snapshot_bd.map[x][y];
+
+ if (cave->hammered_walls_reappear)
+ cave->hammered_reappear[y][x] = engine_snapshot_bd.hammered_reappear[x][y];
+ }
+ }
+
+ gd_scroll(game_bd.game, TRUE, TRUE);
+}