1 // ============================================================================
2 // Rocks'n'Diamonds - McDuffin Strikes Back!
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2024 by Artsoft Entertainment
7 // https://www.artsoft.org/
8 // ----------------------------------------------------------------------------
10 // ============================================================================
15 struct GameInfo_BD game_bd;
16 struct LevelInfo_BD native_bd_level;
17 struct EngineSnapshotInfo_BD engine_snapshot_bd;
20 // ============================================================================
21 // initialization functions
22 // ============================================================================
24 void InitGfxBuffers_BD(void)
26 ReCreateBitmap(&gd_screen_bitmap, SXSIZE, SYSIZE);
28 set_cell_size(TILESIZE_VAR);
29 set_play_area(SXSIZE, SYSIZE);
32 void bd_open_all(void)
39 gd_c64_import_init_tables();
48 void bd_close_all(void)
53 // ============================================================================
54 // level file functions
55 // ============================================================================
57 void setLevelInfoToDefaults_BD_Ext(int width, int height)
59 GdCave *cave = native_bd_level.cave;
64 // get empty cave, using default values
67 // set cave size, if defined
68 if (width > 0 && height > 0)
75 cave->x2 = cave->w - 1;
76 cave->y2 = cave->h - 1;
79 gd_flatten_cave(cave, 0);
81 cave->selectable = TRUE;
82 cave->intermission = FALSE;
84 native_bd_level.cave = cave;
85 native_bd_level.replay = NULL;
87 native_bd_level.cave_nr = 0;
88 native_bd_level.level_nr = 0;
90 native_bd_level.loaded_from_caveset = FALSE;
93 void setLevelInfoToDefaults_BD(void)
95 setLevelInfoToDefaults_BD_Ext(0, 0);
98 boolean LoadNativeLevel_BD(char *filename, int level_pos, boolean level_info_only)
100 static char *filename_loaded = NULL;
102 if (filename_loaded == NULL || !strEqual(filename, filename_loaded))
104 if (!gd_caveset_load_from_file(filename))
106 if (!level_info_only)
107 Warn("cannot load BD cave set from file '%s'", filename);
112 setString(&filename_loaded, filename);
115 if (level_pos < 0 || level_pos >= 5 * gd_caveset_count())
117 Warn("invalid level position %d in BD cave set", level_pos);
122 native_bd_level.cave_nr = level_pos % gd_caveset_count();
123 native_bd_level.level_nr = level_pos / gd_caveset_count();
125 if (native_bd_level.cave != NULL)
126 gd_cave_free(native_bd_level.cave);
128 // get selected cave, prepared for playing
129 native_bd_level.cave = gd_get_prepared_cave_from_caveset(native_bd_level.cave_nr,
130 native_bd_level.level_nr);
132 // set better initial cave speed (to set better native replay tape length)
133 set_initial_cave_speed(native_bd_level.cave);
135 native_bd_level.loaded_from_caveset = TRUE;
137 // check if this cave has any replays
138 if (native_bd_level.cave->replays != NULL)
140 GList *item = native_bd_level.cave->replays;
142 // try to find replay that was recorded for this difficulty level
143 while (item != NULL &&
144 (item->data == NULL ||
145 ((GdReplay *)item->data)->success == FALSE ||
146 ((GdReplay *)item->data)->level != native_bd_level.level_nr))
149 // matching replay found
151 native_bd_level.replay = (GdReplay *)item->data;
158 // ============================================================================
159 // game engine functions
160 // ============================================================================
162 int map_action_RND_to_BD(int action)
164 GdDirection player_move = gd_direction_from_keypress(action & JOY_UP,
168 boolean player_fire = (action & (JOY_BUTTON_1 | JOY_BUTTON_2));
170 return (player_move | (player_fire ? GD_REPLAY_FIRE_MASK : 0));
173 int map_action_BD_to_RND(int action)
175 GdDirection player_move = action & GD_REPLAY_MOVE_MASK;
176 boolean player_fire = action & GD_REPLAY_FIRE_MASK;
178 int action_move = (player_move == GD_MV_UP ? JOY_UP :
179 player_move == GD_MV_UP_RIGHT ? JOY_UP | JOY_RIGHT :
180 player_move == GD_MV_RIGHT ? JOY_RIGHT :
181 player_move == GD_MV_DOWN_RIGHT ? JOY_DOWN | JOY_RIGHT :
182 player_move == GD_MV_DOWN ? JOY_DOWN :
183 player_move == GD_MV_DOWN_LEFT ? JOY_DOWN | JOY_LEFT :
184 player_move == GD_MV_LEFT ? JOY_LEFT :
185 player_move == GD_MV_UP_LEFT ? JOY_UP | JOY_LEFT : JOY_NO_ACTION);
186 int action_fire = (player_fire ? JOY_BUTTON_1 : JOY_NO_ACTION);
188 return (action_move | action_fire);
191 boolean checkGameRunning_BD(void)
193 return (game_bd.game != NULL && game_bd.game->state_counter == GAME_INT_CAVE_RUNNING);
196 boolean checkGamePlaying_BD(void)
198 return (game_bd.game != NULL && game_bd.game->state_counter == GAME_INT_CAVE_RUNNING &&
199 game_bd.game->cave != NULL && game_bd.game->cave->hatched);
202 boolean checkBonusTime_BD(void)
204 return (game_bd.game != NULL && game_bd.game->state_counter == GAME_INT_CHECK_BONUS_TIME);
207 int getFramesPerSecond_BD(void)
209 if (game_bd.game != NULL && game_bd.game->cave != NULL && game_bd.game->cave->pal_timing)
210 return FRAMES_PER_SECOND_NTSC;
212 return FRAMES_PER_SECOND_PAL;
215 int getTimeLeft_BD(void)
217 if (game_bd.game != NULL && game_bd.game->cave != NULL)
218 return gd_cave_time_show(game_bd.game->cave, game_bd.game->cave->time);
223 static void UpdateGameDoorValues_BD(void)
225 GdCave *cave = game_bd.game->cave;
226 int time_secs = gd_cave_time_show(cave, cave->time);
227 int gems_still_needed = MAX(0, (cave->diamonds_needed - cave->diamonds_collected));
229 game_bd.time_played = time_secs;
230 game_bd.gems_still_needed = gems_still_needed;
231 game_bd.score = game_bd.game->player_score;
233 if (game.LevelSolved)
235 // update time and score in panel while counting bonus time
236 game.LevelSolved_CountingTime = game_bd.time_played;
237 game.LevelSolved_CountingScore = game_bd.score;
241 unsigned int InitEngineRandom_BD(int seed)
243 if (seed == NEW_RANDOMIZE)
245 // get randomly selected seed to render the cave
246 seed = g_random_int_range(0, GD_CAVE_SEED_MAX);
249 game_bd.random_seed = seed;
251 return (unsigned int)seed;
254 void InitGameEngine_BD(void)
256 game_bd.level_solved = FALSE;
257 game_bd.game_over = FALSE;
258 game_bd.cover_screen = FALSE;
260 game_bd.time_played = 0;
261 game_bd.gems_still_needed = 0;
264 gd_caveset_last_selected = native_bd_level.cave_nr;
265 gd_caveset_last_selected_level = native_bd_level.level_nr;
267 if (game_bd.game != NULL)
268 gd_game_free(game_bd.game);
270 game_bd.game = gd_game_new(native_bd_level.cave_nr, native_bd_level.level_nr);
272 // default: start with completely covered playfield
273 int next_state = GAME_INT_START_UNCOVER + 1;
275 // when skipping uncovering, start with uncovered playfield
276 if (setup.bd_skip_uncovering)
277 next_state = GAME_INT_LOAD_CAVE + 1;
279 // fast-forward game engine until cave loaded (covered or uncovered)
280 while (game_bd.game->state_counter < next_state)
281 play_game_func(game_bd.game, 0);
283 // when skipping uncovering, continue with uncovered playfield
284 if (setup.bd_skip_uncovering)
285 game_bd.game->state_counter = GAME_INT_UNCOVER_ALL + 1;
287 if (setup.bd_skip_uncovering)
288 gd_scroll(game_bd.game, TRUE, TRUE);
290 ClearRectangle(gd_screen_bitmap, 0, 0, SXSIZE, SYSIZE);
292 RedrawPlayfield_BD(TRUE);
294 UpdateGameDoorValues_BD();
297 void GameActions_BD(byte action[MAX_PLAYERS])
299 GdCave *cave = game_bd.game->cave;
300 boolean player_found = FALSE;
307 for (y = 0; y < cave->h && !player_found; y++)
309 for (x = 0; x < cave->w && !player_found; x++)
311 int element = *cave->getp(cave, x, y);
313 if (element == O_PLAYER ||
314 element == O_PLAYER_BOMB ||
315 element == O_PLAYER_STIRRING ||
316 element == O_PLAYER_PNEUMATIC_LEFT ||
317 element == O_PLAYER_PNEUMATIC_RIGHT)
328 UpdateEngineValues(get_scroll_x(),
333 if (setup.bd_skip_hatching && !game_bd.game->cave->hatched &&
334 game_bd.game->state_counter == GAME_INT_CAVE_RUNNING)
336 // fast-forward game engine until player hatched
337 while (!game_bd.game->cave->hatched)
339 play_game_func(game_bd.game, 0);
341 // also record or replay tape action during fast-forward
342 action = TapeCorrectAction_BD(action);
346 play_game_func(game_bd.game, action[0]);
348 RedrawPlayfield_BD(FALSE);
350 UpdateGameDoorValues_BD();
354 // ============================================================================
355 // graphics functions
356 // ============================================================================
358 void CoverScreen_BD(void)
360 game_bd.cover_screen = FALSE;
362 if (setup.bd_skip_uncovering)
365 game_bd.game->state_counter = GAME_INT_COVER_START;
367 // play game engine (with normal speed) until cave covered
368 while (game_bd.game->state_counter < GAME_INT_COVER_ALL + 1)
370 play_game_func(game_bd.game, 0);
372 RedrawPlayfield_BD(TRUE);
374 BlitScreenToBitmap_BD(backbuffer);
379 // stop uncovering loop sound when not using native sound engine
383 void BlitScreenToBitmap_BD(Bitmap *target_bitmap)
385 GdCave *cave = native_bd_level.cave;
388 int full_xsize = (cave->x2 - cave->x1 + 1) * TILESIZE_VAR;
389 int full_ysize = (cave->y2 - cave->y1 + 1) * TILESIZE_VAR;
390 int sx = SX + (full_xsize < xsize ? (xsize - full_xsize) / 2 : 0);
391 int sy = SY + (full_ysize < ysize ? (ysize - full_ysize) / 2 : 0);
392 int sxsize = (full_xsize < xsize ? full_xsize : xsize);
393 int sysize = (full_ysize < ysize ? full_ysize : ysize);
395 BlitBitmap(gd_screen_bitmap, target_bitmap, 0, 0, sxsize, sysize, sx, sy);
398 void RedrawPlayfield_BD(boolean force_redraw)
400 gd_drawcave(gd_screen_bitmap, game_bd.game, force_redraw);