X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Fgame.c;h=506def33ce0682ae91f3903b2802715300dcba56;hb=8e65ad775c169be345f846f9a3cb1be4bddbd4ce;hp=47f3611731f7bf4bff3741f45681d2b1fb37b73d;hpb=c3f4524693a17a8d75c7d25da24d4003b234d114;p=rocksndiamonds.git diff --git a/src/game.c b/src/game.c index 47f36117..506def33 100644 --- a/src/game.c +++ b/src/game.c @@ -89,7 +89,7 @@ // game panel display and control definitions #define GAME_PANEL_LEVEL_NUMBER 0 #define GAME_PANEL_GEMS 1 -#define GAME_PANEL_GEMS_TOTAL 2 +#define GAME_PANEL_GEMS_NEEDED 2 #define GAME_PANEL_GEMS_COLLECTED 3 #define GAME_PANEL_GEMS_SCORE 4 #define GAME_PANEL_INVENTORY_COUNT 5 @@ -246,8 +246,8 @@ static struct GamePanelControlInfo game_panel_controls[] = TYPE_INTEGER, }, { - GAME_PANEL_GEMS_TOTAL, - &game.panel.gems_total, + GAME_PANEL_GEMS_NEEDED, + &game.panel.gems_needed, TYPE_INTEGER, }, { @@ -1835,6 +1835,29 @@ static void InitPlayerField(int x, int y, int element, boolean init_game) } } +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]; @@ -2291,10 +2314,10 @@ static void UpdateGameControlValues(void) level.game_engine_type == GAME_ENGINE_TYPE_MM ? game_mm.kettles_still_needed : game.gems_still_needed); - int gems_total = level.gems_needed; + int gems_needed = level.gems_needed; int gems_collected = (level.game_engine_type == GAME_ENGINE_TYPE_BD ? game_bd.game->cave->diamonds_collected : - gems_total - gems); + gems_needed - gems); int gems_score = (level.game_engine_type == GAME_ENGINE_TYPE_BD ? game_bd.game->cave->diamond_value : level.score[SC_EMERALD]); @@ -2325,7 +2348,7 @@ static void UpdateGameControlValues(void) // 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_TOTAL].value = gems_total; + 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; @@ -2722,7 +2745,7 @@ static void DisplayGameControlValues(void) 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; @@ -2814,7 +2837,7 @@ static void DisplayGameControlValues(void) 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) @@ -3951,8 +3974,6 @@ void InitGame(void) game.explosions_delayed = TRUE; - game.envelope_active = FALSE; - // special case: set custom artwork setting to initial value game.use_masked_elements = game.use_masked_elements_initial; @@ -4007,6 +4028,8 @@ void InitGame(void) 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])) @@ -4597,6 +4620,8 @@ void InitGame(void) game.restart_level = FALSE; game.request_active = FALSE; + game.envelope_active = FALSE; + game.any_door_active = FALSE; if (level.game_engine_type == GAME_ENGINE_TYPE_MM) InitGameActions_MM(); @@ -4881,6 +4906,31 @@ static void LevelSolved(void) 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; @@ -5111,8 +5161,21 @@ void GameEnd(void) // used instead of "level_nr" (needed for network games) int last_level_nr = levelset.level_nr; boolean tape_saved = FALSE; + boolean game_over = checkGameFailed(); - 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) + + // do not handle game end if game over and automatically asking for game restart + if (game_over && setup.ask_on_game_over) + return; + + // do not handle game end if request dialog is already active + if (checkRequestActive()) + return; + + if (game.LevelSolved) + game.LevelSolved_GameEnd = TRUE; if (game.LevelSolved_SaveTape && !score_info_tape_play) { @@ -5139,7 +5202,7 @@ void GameEnd(void) return; } - if (!game.LevelSolved_SaveScore) + if (!game.GamePlayed || (!game.LevelSolved_SaveScore && !level.bd_intermission)) { SetGameStatus(GAME_MODE_MAIN); @@ -5156,27 +5219,13 @@ void GameEnd(void) } // 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; - - LoadLevel(level_nr); + // increment and load next level (if possible and not configured otherwise) + AdvanceToNextLevel(); - 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); @@ -15537,56 +15586,81 @@ static int getSoundAction_BD(int sample) { switch (sample) { - case GD_S_STONE: - case GD_S_NUT: - case GD_S_DIRT_BALL: - case GD_S_NITRO: - case GD_S_FALLING_WALL: + 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_CRACK: + case GD_S_NUT_CRACKING: return ACTION_BREAKING; case GD_S_EXPANDING_WALL: - case GD_S_WALL_REAPPEAR: + case GD_S_WALL_REAPPEARING: case GD_S_SLIME: case GD_S_LAVA: - case GD_S_ACID_SPREAD: + case GD_S_ACID_SPREADING: return ACTION_GROWING; - case GD_S_DIAMOND_COLLECT: - case GD_S_SKELETON_COLLECT: - case GD_S_PNEUMATIC_COLLECT: - case GD_S_BOMB_COLLECT: - case GD_S_CLOCK_COLLECT: - case GD_S_SWEET_COLLECT: - case GD_S_KEY_COLLECT: - case GD_S_DIAMOND_KEY_COLLECT: + 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_PLACE: + case GD_S_BOMB_PLACING: case GD_S_REPLICATOR: return ACTION_DROPPING; - case GD_S_BLADDER_MOVE: + case GD_S_BLADDER_MOVING: return ACTION_MOVING; case GD_S_BLADDER_SPENDER: - case GD_S_BLADDER_CONVERT: - case GD_S_GRAVITY_CHANGE: + case GD_S_BLADDER_CONVERTING: + case GD_S_GRAVITY_CHANGING: return ACTION_CHANGING; - case GD_S_BITER_EAT: + case GD_S_BITER_EATING: return ACTION_EATING; - case GD_S_DOOR_OPEN: - case GD_S_CRACK: + case GD_S_DOOR_OPENING: + case GD_S_CRACKING: return ACTION_OPENING; - case GD_S_WALK_EARTH: + case GD_S_DIRT_WALKING: return ACTION_DIGGING; - case GD_S_WALK_EMPTY: + case GD_S_EMPTY_WALKING: return ACTION_WALKING; case GD_S_SWITCH_BITER: @@ -15598,36 +15672,59 @@ static int getSoundAction_BD(int sample) case GD_S_STIRRING: return ACTION_ACTIVATING; - case GD_S_BOX_PUSH: - return ACTION_PUSHING; - case GD_S_TELEPORTER: return ACTION_PASSING; - case GD_S_EXPLOSION: - case GD_S_BOMB_EXPLOSION: - case GD_S_GHOST_EXPLOSION: - case GD_S_VOODOO_EXPLOSION: - case GD_S_NITRO_EXPLOSION: + 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_COVER: + case GD_S_COVERING: case GD_S_AMOEBA: - case GD_S_AMOEBA_MAGIC: case GD_S_MAGIC_WALL: case GD_S_PNEUMATIC_HAMMER: case GD_S_WATER: return ACTION_ACTIVE; - case GD_S_DIAMOND_RANDOM: - case GD_S_DIAMOND_1: - case GD_S_DIAMOND_2: - case GD_S_DIAMOND_3: - case GD_S_DIAMOND_4: - case GD_S_DIAMOND_5: - case GD_S_DIAMOND_6: - case GD_S_DIAMOND_7: - case GD_S_DIAMOND_8: + 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: @@ -15640,10 +15737,12 @@ static int getSoundAction_BD(int sample) case GD_S_TIMEOUT_9: case GD_S_TIMEOUT_10: case GD_S_BONUS_LIFE: - // kludge to prevent playing as loop sound + // 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: @@ -15662,24 +15761,75 @@ static int getSoundEffect_BD(int element_bd, int sample) sound_action != ACTION_DEFAULT) return sound_effect; - // special sounds + // special post-processing for some sounds switch (sample) { - case GD_S_DIAMOND_RANDOM: - nr = GetSimpleRandom(8); - sound_effect = SND_BD_DIAMOND_IMPACT_RANDOM_1 + nr; + 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_1: - case GD_S_DIAMOND_2: - case GD_S_DIAMOND_3: - case GD_S_DIAMOND_4: - case GD_S_DIAMOND_5: - case GD_S_DIAMOND_6: - case GD_S_DIAMOND_7: - case GD_S_DIAMOND_8: - nr = sample - GD_S_DIAMOND_1; + 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: @@ -15700,14 +15850,18 @@ static int getSoundEffect_BD(int element_bd, int sample) sound_effect = SND_GAME_RUNNING_OUT_OF_TIME; break; - case GD_S_FINISHED: - sound_effect = SND_GAME_LEVELTIME_BONUS; - 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; @@ -15718,7 +15872,7 @@ static int getSoundEffect_BD(int element_bd, int sample) void PlayLevelSound_BD(int xx, int yy, int element_bd, int sample) { - int element = (element_bd > -1 ? map_element_BD_to_RND(element_bd) : 0); + 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); @@ -15726,7 +15880,14 @@ void PlayLevelSound_BD(int xx, int yy, int element_bd, int sample) int x = xx - offset; int y = yy - offset; - if (sound_action == ACTION_OTHER) + // 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) @@ -15735,7 +15896,7 @@ void PlayLevelSound_BD(int xx, int yy, int element_bd, int sample) void StopSound_BD(int element_bd, int sample) { - int element = (element_bd > -1 ? map_element_BD_to_RND(element_bd) : 0); + 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) @@ -15744,7 +15905,7 @@ void StopSound_BD(int element_bd, int sample) boolean isSoundPlaying_BD(int element_bd, int sample) { - int element = (element_bd > -1 ? map_element_BD_to_RND(element_bd) : 0); + 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) @@ -16137,7 +16298,17 @@ static void RequestRestartGame(void) 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); @@ -16181,7 +16352,7 @@ boolean CheckRestartGame(void) } // do not ask to play again if request dialog is already active - if (game.request_active) + if (checkRequestActive()) return FALSE; // do not ask to play again if request dialog already handled @@ -16250,6 +16421,11 @@ boolean checkGameEnded(void) return (checkGameSolved() || checkGameFailed()); } +boolean checkRequestActive(void) +{ + return (game.request_active || game.envelope_active || game.any_door_active); +} + // ---------------------------------------------------------------------------- // random generator functions