cleanup of unnecessarily convoluted function call
[rocksndiamonds.git] / src / game_bd / main_bd.c
index ccb04e23a3f211bebf515d870a31c23aadc57c25..4404d0ab06d3765ffd1afb71ae93d1f3cdc04c36 100644 (file)
@@ -40,7 +40,7 @@ void bd_open_all(void)
 
   gd_caveset_clear();
 
-  gd_init_keystate();
+  gd_init_play_area();
 
   gd_sound_init();
 }
@@ -69,6 +69,11 @@ void setLevelInfoToDefaults_BD_Ext(int width, int height)
   {
     cave->w = width;
     cave->h = height;
+
+    cave->x1 = 0;
+    cave->y1 = 0;
+    cave->x2 = cave->w - 1;
+    cave->y2 = cave->h - 1;
   }
 
   gd_flatten_cave(cave, 0);
@@ -90,6 +95,30 @@ void setLevelInfoToDefaults_BD(void)
   setLevelInfoToDefaults_BD_Ext(0, 0);
 }
 
+static List *getNativeLevelReplay_BD_Ext(List *item, boolean only_successful_replays)
+{
+  // look for replay that was recorded for the current difficulty level
+  while (item != NULL &&
+        (item->data == NULL ||
+         (((GdReplay *)item->data)->success == FALSE && only_successful_replays) ||
+         ((GdReplay *)item->data)->level != native_bd_level.level_nr))
+    item = item->next;
+
+  return item;
+}
+
+static List *getNativeLevelReplay_BD(List *replays)
+{
+  // 1st try: look for successful replay
+  List *item = getNativeLevelReplay_BD_Ext(replays, TRUE);
+
+  if (item != NULL)
+    return item;
+
+  // 2nd try: look for any replay
+  return getNativeLevelReplay_BD_Ext(replays, FALSE);
+}
+
 boolean LoadNativeLevel_BD(char *filename, int level_pos, boolean level_info_only)
 {
   static char *filename_loaded = NULL;
@@ -132,16 +161,9 @@ boolean LoadNativeLevel_BD(char *filename, int level_pos, boolean level_info_onl
   // check if this cave has any replays
   if (native_bd_level.cave->replays != NULL)
   {
-    GList *item = native_bd_level.cave->replays;
+    List *item = getNativeLevelReplay_BD(native_bd_level.cave->replays);
 
-    // try to find replay that was recorded for this difficulty level
-    while (item != NULL &&
-          (item->data == NULL ||
-           ((GdReplay *)item->data)->success == FALSE ||
-           ((GdReplay *)item->data)->level != native_bd_level.level_nr))
-      item = item->next;
-
-    // matching replay found
+    // check if any matching replay was found
     if (item != NULL)
       native_bd_level.replay = (GdReplay *)item->data;
   }
@@ -149,6 +171,24 @@ boolean LoadNativeLevel_BD(char *filename, int level_pos, boolean level_info_onl
   return TRUE;
 }
 
+boolean SaveNativeLevel_BD(char *filename)
+{
+  GdCave *cave = gd_cave_new_from_cave(native_bd_level.cave);
+
+  gd_caveset_clear();
+  gd_caveset = list_append(gd_caveset, cave);
+
+  return gd_caveset_save_to_file(filename);
+}
+
+void DumpLevelset_BD(void)
+{
+  int num_levels_per_cave = (gd_caveset_has_levels() ? 5 : 1);
+
+  Print("Number of levels:   %d\n", num_levels_per_cave * gd_caveset_count());
+  Print("First level number: %d\n", 1);
+}
+
 
 // ============================================================================
 // game engine functions
@@ -188,12 +228,93 @@ boolean checkGameRunning_BD(void)
   return (game_bd.game != NULL && game_bd.game->state_counter == GAME_INT_CAVE_RUNNING);
 }
 
+boolean checkGamePlaying_BD(void)
+{
+  return (game_bd.game != NULL && game_bd.game->state_counter == GAME_INT_CAVE_RUNNING &&
+         game_bd.game->cave != NULL && game_bd.game->cave->hatched);
+}
+
+boolean checkBonusTime_BD(void)
+{
+  return (game_bd.game != NULL && game_bd.game->state_counter == GAME_INT_CHECK_BONUS_TIME);
+}
+
+int getFramesPerSecond_BD(void)
+{
+  if (game_bd.game != NULL && game_bd.game->cave != NULL && game_bd.game->cave->pal_timing)
+    return FRAMES_PER_SECOND_NTSC;
+
+  return FRAMES_PER_SECOND_PAL;
+}
+
+int getTimeLeft_BD(void)
+{
+  if (game_bd.game != NULL && game_bd.game->cave != NULL)
+    return gd_cave_time_show(game_bd.game->cave, game_bd.game->cave->time);
+
+  return 0;
+}
+
+void SetTimeFrames_BD(int frames_played)
+{
+  // needed to store final time after solving game (before counting down remaining time)
+  if (game_bd.game->state_counter == GAME_INT_CAVE_RUNNING)
+    game_bd.frames_played = frames_played;
+
+}
+
+static void UpdateGameDoorValues_BD(void)
+{
+  GdCave *cave = game_bd.game->cave;
+  int time_left = gd_cave_time_show(cave, cave->time);
+  int gems_still_needed = MAX(0, (cave->diamonds_needed - cave->diamonds_collected));
+
+  game_bd.time_left = time_left;
+  game_bd.gems_still_needed = gems_still_needed;
+  game_bd.score = game_bd.game->player_score;
+
+  if (game.LevelSolved)
+  {
+    // update time and score in panel while counting bonus time
+    game.LevelSolved_CountingTime  = game_bd.time_left;
+    game.LevelSolved_CountingScore = game_bd.score;
+  }
+}
+
+static void PrepareGameTileBitmap_BD(void)
+{
+  struct GraphicInfo_BD *g_template = &graphic_info_bd_color_template;
+  struct GraphicInfo_BD *g_default  = &graphic_info_bd_object[O_STONE][0];
+
+  // prepare bitmap using cave ready for playing (may have changed colors)
+  gd_prepare_tile_bitmap(game_bd.game->cave, g_template->bitmap, 1);
+
+  // set reference bitmap which should be replaced with prepared bitmap
+  gd_set_tile_bitmap_reference(g_default->bitmap);
+}
+
+void PreparePreviewTileBitmap_BD(Bitmap *bitmap, int scale_down_factor)
+{
+  // prepare bitmap using cave from file (with originally defined colors)
+  gd_prepare_tile_bitmap(native_bd_level.cave, bitmap, scale_down_factor);
+}
+
+void SetPreviewTileBitmapReference_BD(Bitmap *bitmap)
+{
+  gd_set_tile_bitmap_reference(bitmap);
+}
+
+Bitmap *GetPreviewTileBitmap_BD(Bitmap *bitmap)
+{
+  return gd_get_tile_bitmap(bitmap);
+}
+
 unsigned int InitEngineRandom_BD(int seed)
 {
   if (seed == NEW_RANDOMIZE)
   {
     // get randomly selected seed to render the cave
-    seed = g_random_int_range(0, GD_CAVE_SEED_MAX);
+    seed = gd_random_int_range(0, GD_CAVE_SEED_MAX);
   }
 
   game_bd.random_seed = seed;
@@ -201,11 +322,194 @@ unsigned int InitEngineRandom_BD(int seed)
   return (unsigned int)seed;
 }
 
+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;
@@ -233,10 +537,11 @@ void CoverScreen_BD(void)
 
 void BlitScreenToBitmap_BD(Bitmap *target_bitmap)
 {
+  GdCave *cave = native_bd_level.cave;
   int xsize = SXSIZE;
   int ysize = SYSIZE;
-  int full_xsize = native_bd_level.cave->w * TILESIZE_VAR;
-  int full_ysize = native_bd_level.cave->h * TILESIZE_VAR;
+  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);
@@ -249,3 +554,99 @@ 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);
+}