minor code formatting change
[rocksndiamonds.git] / src / game.c
index fa1682053736b0e197c2e9b5b910dcef4dc90217..3a9a773661e15b791d594d1ea7d7e48c17a67989 100644 (file)
@@ -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,
   },
   {
@@ -2291,10 +2291,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 +2325,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 +2722,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 +2814,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)
@@ -4503,7 +4503,11 @@ void InitGame(void)
     scroll_y = game.forced_scroll_y;
 
   // !!! FIX THIS (START) !!!
-  if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
+  if (level.game_engine_type == GAME_ENGINE_TYPE_BD)
+  {
+    InitGameEngine_BD();
+  }
+  else if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
   {
     InitGameEngine_EM();
   }
@@ -4968,7 +4972,8 @@ void GameWon(void)
     }
 
     // if not counting score after game, immediately update game panel values
-    if (level_editor_test_game || !setup.count_score_after_game)
+    if (level_editor_test_game || !setup.count_score_after_game ||
+       level.game_engine_type == GAME_ENGINE_TYPE_BD)
     {
       time = time_final;
       score = score_final;
@@ -11704,6 +11709,10 @@ static void CheckLevelSolved(void)
 
 static void PlayTimeoutSound(int seconds_left)
 {
+  // will be played directly by BD engine (for classic bonus time sounds)
+  if (level.game_engine_type == GAME_ENGINE_TYPE_BD && checkBonusTime_BD())
+    return;
+
   // try to use individual "running out of time" sound for each second left
   int sound = SND_GAME_RUNNING_OUT_OF_TIME_0 - seconds_left;
 
@@ -11750,9 +11759,24 @@ static void CheckLevelTime_StepCounter(void)
 
 static void CheckLevelTime(void)
 {
+  int frames_per_second = FRAMES_PER_SECOND;
   int i;
 
-  if (TimeFrames >= FRAMES_PER_SECOND)
+  if (level.game_engine_type == GAME_ENGINE_TYPE_BD)
+  {
+    // level time may be running slower in native BD engine
+    frames_per_second = getFramesPerSecond_BD();
+
+    // if native engine time changed, force main engine time change
+    if (getTimeLeft_BD() < TimeLeft)
+      TimeFrames = frames_per_second;
+
+    // if last second running, wait for native engine time to exactly reach zero
+    if (getTimeLeft_BD() == 1 && TimeLeft == 1)
+      TimeFrames = frames_per_second - 1;
+  }
+
+  if (TimeFrames >= frames_per_second)
   {
     TimeFrames = 0;
 
@@ -11787,11 +11811,20 @@ static void CheckLevelTime(void)
 
        if (!TimeLeft && game.time_limit)
        {
-         if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
+         if (level.game_engine_type == GAME_ENGINE_TYPE_BD)
+         {
+           if (game_bd.game->cave->player_state == GD_PL_LIVING)
+             game_bd.game->cave->player_state = GD_PL_TIMEOUT;
+         }
+         else if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
+         {
            game_em.lev->killed_out_of_time = TRUE;
+         }
          else
+         {
            for (i = 0; i < MAX_PLAYERS; i++)
              KillPlayer(&stored_player[i]);
+         }
        }
       }
       else if (game.no_level_time_limit && !game.all_players_gone)
@@ -11822,10 +11855,20 @@ void AdvanceFrameAndPlayerCounters(int player_nr)
 {
   int i;
 
+  // handle game and tape time differently for native BD game engine
+
+  // tape time is running in native BD engine even if player is not hatched yet
+  if (!checkGameRunning())
+    return;
+
   // advance frame counters (global frame counter and tape time frame counter)
   FrameCounter++;
   TapeTimeFrames++;
 
+  // level time is running in native BD engine after player is being hatched
+  if (!checkGamePlaying())
+    return;
+
   // advance time frame counter (used to control available time to solve level)
   TimeFrames++;
 
@@ -12176,7 +12219,11 @@ static void GameActionsExt(void)
     game.snapshot.last_action[i] = stored_player[i].effective_action;
   }
 
-  if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
+  if (level.game_engine_type == GAME_ENGINE_TYPE_BD)
+  {
+    GameActions_BD_Main();
+  }
+  else if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
   {
     GameActions_EM_Main();
   }
@@ -12243,6 +12290,17 @@ void GameActions(void)
   GameActions_CheckSaveEngineSnapshot();
 }
 
+void GameActions_BD_Main(void)
+{
+  byte effective_action[MAX_PLAYERS];
+  int i;
+
+  for (i = 0; i < MAX_PLAYERS; i++)
+    effective_action[i] = stored_player[i].effective_action;
+
+  GameActions_BD(effective_action);
+}
+
 void GameActions_EM_Main(void)
 {
   byte effective_action[MAX_PLAYERS];
@@ -15479,56 +15537,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:
@@ -15540,36 +15623,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:
@@ -15582,10 +15688,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:
@@ -15604,24 +15712,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:
@@ -15642,14 +15801,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;
@@ -15668,7 +15831,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)
@@ -16156,6 +16326,17 @@ boolean checkGameRunning(void)
   return TRUE;
 }
 
+boolean checkGamePlaying(void)
+{
+  if (game_status != GAME_MODE_PLAYING)
+    return FALSE;
+
+  if (level.game_engine_type == GAME_ENGINE_TYPE_BD && !checkGamePlaying_BD())
+    return FALSE;
+
+  return TRUE;
+}
+
 boolean checkGameSolved(void)
 {
   // set for all game engines if level was solved