X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Fgame_bd%2Fmain_bd.c;h=06ecfd0458fa7cea799a9fe044236b56122a75b9;hb=refs%2Fheads%2Fmaster-next-major-release;hp=efaa78f40a127a40b5ceb76d7f24c0a1441af0ec;hpb=6e1c81b564b748d54aadb2a79235c8fbe3483677;p=rocksndiamonds.git diff --git a/src/game_bd/main_bd.c b/src/game_bd/main_bd.c index efaa78f4..4404d0ab 100644 --- a/src/game_bd/main_bd.c +++ b/src/game_bd/main_bd.c @@ -18,43 +18,42 @@ struct EngineSnapshotInfo_BD engine_snapshot_bd; // ============================================================================ -// level file functions +// initialization functions // ============================================================================ -int map_action_RND_to_BD(int action) +void InitGfxBuffers_BD(void) { - GdDirection player_move = gd_direction_from_keypress(action & JOY_UP, - action & JOY_DOWN, - action & JOY_LEFT, - action & JOY_RIGHT); - boolean player_fire = (action & (JOY_BUTTON_1 | JOY_BUTTON_2)); + ReCreateBitmap(&gd_screen_bitmap, SXSIZE, SYSIZE); - return (player_move | (player_fire ? GD_REPLAY_FIRE_MASK : 0)); + set_cell_size(TILESIZE_VAR); + set_play_area(SXSIZE, SYSIZE); } -int map_action_BD_to_RND(int action) +void bd_open_all(void) { - GdDirection player_move = action & GD_REPLAY_MOVE_MASK; - boolean player_fire = action & GD_REPLAY_FIRE_MASK; + InitGraphicInfo_BD(); - int action_move = (player_move == GD_MV_UP ? JOY_UP : - player_move == GD_MV_UP_RIGHT ? JOY_UP | JOY_RIGHT : - player_move == GD_MV_RIGHT ? JOY_RIGHT : - player_move == GD_MV_DOWN_RIGHT ? JOY_DOWN | JOY_RIGHT : - player_move == GD_MV_DOWN ? JOY_DOWN : - player_move == GD_MV_DOWN_LEFT ? JOY_DOWN | JOY_LEFT : - player_move == GD_MV_LEFT ? JOY_LEFT : - player_move == GD_MV_UP_LEFT ? JOY_UP | JOY_LEFT : JOY_NO_ACTION); - int action_fire = (player_fire ? JOY_BUTTON_1 : JOY_NO_ACTION); + gd_cave_init(); + gd_cave_db_init(); - return (action_move | action_fire); + gd_c64_import_init_tables(); + + gd_caveset_clear(); + + gd_init_play_area(); + + gd_sound_init(); } -boolean checkGameRunning_BD(void) +void bd_close_all(void) { - return (game_bd.game != NULL && game_bd.game->state_counter == GAME_INT_CAVE_RUNNING); } + +// ============================================================================ +// level file functions +// ============================================================================ + void setLevelInfoToDefaults_BD_Ext(int width, int height) { GdCave *cave = native_bd_level.cave; @@ -70,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); @@ -91,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; @@ -133,19 +161,492 @@ 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; } 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 +// ============================================================================ + +int map_action_RND_to_BD(int action) +{ + GdDirection player_move = gd_direction_from_keypress(action & JOY_UP, + action & JOY_DOWN, + action & JOY_LEFT, + action & JOY_RIGHT); + boolean player_fire = (action & (JOY_BUTTON_1 | JOY_BUTTON_2)); + + return (player_move | (player_fire ? GD_REPLAY_FIRE_MASK : 0)); +} + +int map_action_BD_to_RND(int action) +{ + GdDirection player_move = action & GD_REPLAY_MOVE_MASK; + boolean player_fire = action & GD_REPLAY_FIRE_MASK; + + int action_move = (player_move == GD_MV_UP ? JOY_UP : + player_move == GD_MV_UP_RIGHT ? JOY_UP | JOY_RIGHT : + player_move == GD_MV_RIGHT ? JOY_RIGHT : + player_move == GD_MV_DOWN_RIGHT ? JOY_DOWN | JOY_RIGHT : + player_move == GD_MV_DOWN ? JOY_DOWN : + player_move == GD_MV_DOWN_LEFT ? JOY_DOWN | JOY_LEFT : + player_move == GD_MV_LEFT ? JOY_LEFT : + player_move == GD_MV_UP_LEFT ? JOY_UP | JOY_LEFT : JOY_NO_ACTION); + int action_fire = (player_fire ? JOY_BUTTON_1 : JOY_NO_ACTION); + + return (action_move | action_fire); +} + +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 = gd_random_int_range(0, GD_CAVE_SEED_MAX); + } + + game_bd.random_seed = 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; + + 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); +}