changed counting down time with the same step size (instead of 1 or 10)
[rocksndiamonds.git] / src / game.c
index de844f4298ca0351fcaceab4ce88082c9c8402c7..572373e51248d7bd86bbf28a0a4b9d75e03b4d59 100644 (file)
@@ -1002,6 +1002,8 @@ static struct GamePanelControlInfo game_panel_controls[] =
 #define IS_PASSABLE_FROM(e, d)         (IS_PASSABLE(e)   && ACCESS_FROM(e, d))
 #define IS_ACCESSIBLE_FROM(e, d)       (IS_ACCESSIBLE(e) && ACCESS_FROM(e, d))
 
+#define MM_HEALTH(x)           (MIN(MAX(0, MAX_HEALTH - (x)), MAX_HEALTH))
+
 /* game button identifiers */
 #define GAME_CTRL_ID_STOP              0
 #define GAME_CTRL_ID_PAUSE             1
@@ -2205,8 +2207,11 @@ void UpdateGameControlValues()
                     local_player->gems_still_needed > 0 ||
                     local_player->sokobanfields_still_needed > 0 ||
                     local_player->lights_still_needed > 0);
-  int health = (level.game_engine_type == GAME_ENGINE_TYPE_MM ?
-               MIN(MAX(0, 100 - game_mm.laser_overload_value), 100) : 100);
+  int health = (local_player->LevelSolved ?
+               local_player->LevelSolved_CountingHealth :
+               level.game_engine_type == GAME_ENGINE_TYPE_MM ?
+               MM_HEALTH(game_mm.laser_overload_value) :
+               local_player->health);
 
   UpdatePlayfieldElementCount();
 
@@ -3334,9 +3339,16 @@ void InitGame()
     player->mouse_action.ly = 0;
     player->mouse_action.button = 0;
 
+    player->effective_mouse_action.lx = 0;
+    player->effective_mouse_action.ly = 0;
+    player->effective_mouse_action.button = 0;
+
     player->score = 0;
     player->score_final = 0;
 
+    player->health = MAX_HEALTH;
+    player->health_final = MAX_HEALTH;
+
     player->gems_still_needed = level.gems_needed;
     player->sokobanfields_still_needed = 0;
     player->lights_still_needed = 0;
@@ -3472,8 +3484,10 @@ void InitGame()
     player->LevelSolved_PanelOff = FALSE;
     player->LevelSolved_SaveTape = FALSE;
     player->LevelSolved_SaveScore = FALSE;
+
     player->LevelSolved_CountingTime = 0;
     player->LevelSolved_CountingScore = 0;
+    player->LevelSolved_CountingHealth = 0;
 
     map_player_action[i] = i;
   }
@@ -4446,20 +4460,28 @@ static void PlayerWins(struct PlayerInfo *player)
                         level.game_engine_type == GAME_ENGINE_TYPE_MM ?
                         game_mm.score :
                         player->score);
+  player->health_final = (level.game_engine_type == GAME_ENGINE_TYPE_MM ?
+                         MM_HEALTH(game_mm.laser_overload_value) :
+                         player->health);
 
   player->LevelSolved_CountingTime = (game.no_time_limit ? TimePlayed :
                                      TimeLeft);
   player->LevelSolved_CountingScore = player->score_final;
+  player->LevelSolved_CountingHealth = player->health_final;
 }
 
 void GameWon()
 {
+  static int time_count_steps;
   static int time, time_final;
   static int score, score_final;
+  static int health, health_final;
   static int game_over_delay_1 = 0;
   static int game_over_delay_2 = 0;
+  static int game_over_delay_3 = 0;
   int game_over_delay_value_1 = 50;
-  int game_over_delay_value_2 = 50;
+  int game_over_delay_value_2 = 25;
+  int game_over_delay_value_3 = 50;
 
   if (!local_player->LevelSolved_GameWon)
   {
@@ -4485,24 +4507,42 @@ void GameWon()
 
     TapeStop();
 
-    game_over_delay_1 = game_over_delay_value_1;
-    game_over_delay_2 = game_over_delay_value_2;
+    game_over_delay_1 = 0;
+    game_over_delay_2 = 0;
+    game_over_delay_3 = game_over_delay_value_3;
 
     time = time_final = (game.no_time_limit ? TimePlayed : TimeLeft);
     score = score_final = local_player->score_final;
+    health = health_final = local_player->health_final;
 
-    if (TimeLeft > 0)
+    if (level.score[SC_TIME_BONUS] > 0)
     {
-      time_final = 0;
-      score_final += TimeLeft * level.score[SC_TIME_BONUS];
-    }
-    else if (game.no_time_limit && TimePlayed < 999)
-    {
-      time_final = 999;
-      score_final += (999 - TimePlayed) * level.score[SC_TIME_BONUS];
-    }
+      if (TimeLeft > 0)
+      {
+       time_final = 0;
+       score_final += TimeLeft * level.score[SC_TIME_BONUS];
+      }
+      else if (game.no_time_limit && TimePlayed < 999)
+      {
+       time_final = 999;
+       score_final += (999 - TimePlayed) * level.score[SC_TIME_BONUS];
+      }
+
+      time_count_steps = MAX(1, ABS(time_final - time) / 100);
 
-    local_player->score_final = score_final;
+      game_over_delay_1 = game_over_delay_value_1;
+
+      if (level.game_engine_type == GAME_ENGINE_TYPE_MM)
+      {
+       health_final = 0;
+       score_final += health * level.score[SC_TIME_BONUS];
+
+       game_over_delay_2 = game_over_delay_value_2;
+      }
+
+      local_player->score_final = score_final;
+      local_player->health_final = health_final;
+    }
 
     if (level_editor_test_game)
     {
@@ -4574,7 +4614,9 @@ void GameWon()
   {
     int time_to_go = ABS(time_final - time);
     int time_count_dir = (time < time_final ? +1 : -1);
-    int time_count_steps = (time_to_go > 100 && time_to_go % 10 == 0 ? 10 : 1);
+
+    if (time_to_go < time_count_steps)
+      time_count_steps = 1;
 
     time  += time_count_steps * time_count_dir;
     score += time_count_steps * level.score[SC_TIME_BONUS];
@@ -4597,8 +4639,6 @@ void GameWon()
     return;
   }
 
-  local_player->LevelSolved_PanelOff = TRUE;
-
   if (game_over_delay_2 > 0)
   {
     game_over_delay_2--;
@@ -4606,6 +4646,40 @@ void GameWon()
     return;
   }
 
+  if (health != health_final)
+  {
+    int health_count_dir = (health < health_final ? +1 : -1);
+
+    health += health_count_dir;
+    score  += level.score[SC_TIME_BONUS];
+
+    local_player->LevelSolved_CountingHealth = health;
+    local_player->LevelSolved_CountingScore = score;
+
+    game_panel_controls[GAME_PANEL_HEALTH].value = health;
+    game_panel_controls[GAME_PANEL_SCORE].value = score;
+
+    DisplayGameControlValues();
+
+    if (health == health_final)
+      StopSound(SND_GAME_LEVELTIME_BONUS);
+    else if (setup.sound_loops)
+      PlaySoundLoop(SND_GAME_LEVELTIME_BONUS);
+    else
+      PlaySound(SND_GAME_LEVELTIME_BONUS);
+
+    return;
+  }
+
+  local_player->LevelSolved_PanelOff = TRUE;
+
+  if (game_over_delay_3 > 0)
+  {
+    game_over_delay_3--;
+
+    return;
+  }
+
   GameEnd();
 }
 
@@ -10977,6 +11051,9 @@ static byte PlayerActions(struct PlayerInfo *player, byte player_action)
 static void SetMouseActionFromTapeAction(struct MouseActionInfo *mouse_action,
                                         byte *tape_action)
 {
+  if (!tape.use_mouse)
+    return;
+
   mouse_action->lx     = tape_action[TAPE_ACTION_LX];
   mouse_action->ly     = tape_action[TAPE_ACTION_LY];
   mouse_action->button = tape_action[TAPE_ACTION_BUTTON];
@@ -10985,6 +11062,9 @@ static void SetMouseActionFromTapeAction(struct MouseActionInfo *mouse_action,
 static void SetTapeActionFromMouseAction(byte *tape_action,
                                         struct MouseActionInfo *mouse_action)
 {
+  if (!tape.use_mouse)
+    return;
+
   tape_action[TAPE_ACTION_LX]     = mouse_action->lx;
   tape_action[TAPE_ACTION_LY]     = mouse_action->ly;
   tape_action[TAPE_ACTION_BUTTON] = mouse_action->button;
@@ -11317,8 +11397,10 @@ void GameActionsExt()
   /* when playing tape, read previously recorded player input from tape data */
   recorded_player_action = (tape.playing ? TapePlayAction() : NULL);
 
+  local_player->effective_mouse_action = local_player->mouse_action;
+
   if (recorded_player_action != NULL)
-    SetMouseActionFromTapeAction(&local_player->mouse_action,
+    SetMouseActionFromTapeAction(&local_player->effective_mouse_action,
                                 recorded_player_action);
 
   /* TapePlayAction() may return NULL when toggling to "pause before death" */
@@ -11377,7 +11459,8 @@ void GameActionsExt()
       tape.player_participates[i] = TRUE;
   }
 
-  SetTapeActionFromMouseAction(tape_action, &local_player->mouse_action);
+  SetTapeActionFromMouseAction(tape_action,
+                              &local_player->effective_mouse_action);
 
   /* only record actions from input devices, but not programmed actions */
   if (tape.recording)
@@ -11537,7 +11620,7 @@ void GameActions_MM_Main()
 {
   boolean warp_mode = (tape.playing && tape.warp_forward && !tape.pausing);
 
-  GameActions_MM(local_player->mouse_action, warp_mode);
+  GameActions_MM(local_player->effective_mouse_action, warp_mode);
 }
 
 void GameActions_RND_Main()
@@ -14703,6 +14786,9 @@ void PlayLevelSound_MM(int xx, int yy, int element_mm, int action_mm)
   int x = xx - offset;
   int y = yy - offset;
 
+  if (!IS_MM_ELEMENT(element))
+    element = EL_MM_DEFAULT;
+
   PlayLevelSoundElementAction(x, y, element, action);
 }