fixed asking all network clients to "play again" after unsolved game end
[rocksndiamonds.git] / src / game.c
index 18d020bdf802d695ae9d10429b854a4613916456..f359a2cbdfb406c6bf018873c7b14c5901397dfc 100644 (file)
@@ -81,7 +81,7 @@
 #define EX_TYPE_DYNA           (1 << 4)
 #define EX_TYPE_SINGLE_TILE    (EX_TYPE_CENTER | EX_TYPE_BORDER)
 
-#define PANEL_OFF()            (local_player->LevelSolved_PanelOff)
+#define PANEL_OFF()            (game.panel.active == FALSE)
 #define        PANEL_DEACTIVATED(p)    ((p)->x < 0 || (p)->y < 0 || PANEL_OFF())
 #define PANEL_XPOS(p)          (DX + ALIGNED_TEXT_XPOS(p))
 #define PANEL_YPOS(p)          (DY + ALIGNED_TEXT_YPOS(p))
@@ -3525,7 +3525,6 @@ void InitGame(void)
 
     player->LevelSolved_GameWon = FALSE;
     player->LevelSolved_GameEnd = FALSE;
-    player->LevelSolved_PanelOff = FALSE;
     player->LevelSolved_SaveTape = FALSE;
     player->LevelSolved_SaveScore = FALSE;
 
@@ -3559,6 +3558,8 @@ void InitGame(void)
 
   AllPlayersGone = FALSE;
 
+  game.panel.active = TRUE;
+
   game.no_time_limit = (level.time == 0);
 
   game.yamyam_content_nr = 0;
@@ -4195,6 +4196,7 @@ void InitGame(void)
 
   game.restart_level = FALSE;
   game.restart_game_message = NULL;
+  game.request_active = FALSE;
 
   if (level.game_engine_type == GAME_ENGINE_TYPE_MM)
     InitGameActions_MM();
@@ -4653,7 +4655,7 @@ void GameWon(void)
     return;
   }
 
-  local_player->LevelSolved_PanelOff = TRUE;
+  game.panel.active = FALSE;
 
   if (game_over_delay_3 > 0)
   {
@@ -4667,6 +4669,8 @@ void GameWon(void)
 
 void GameEnd(void)
 {
+  /* used instead of "level_nr" (needed for network games) */
+  int last_level_nr = levelset.level_nr;
   int hi_pos;
 
   local_player->LevelSolved_GameEnd = TRUE;
@@ -4723,16 +4727,16 @@ void GameEnd(void)
     }
   }
 
-  /* used instead of last "level_nr" (for network games) */
-  hi_pos = NewHiScore(levelset.level_nr);
+  hi_pos = NewHiScore(last_level_nr);
 
   if (hi_pos >= 0 && !setup.skip_scores_after_game)
   {
     SetGameStatus(GAME_MODE_SCORES);
 
-    DrawHallOfFame(levelset.level_nr, hi_pos);
+    DrawHallOfFame(last_level_nr, hi_pos);
   }
   else if (setup.auto_play_next_level && setup.increment_levels &&
+          last_level_nr < leveldir_current->last_level &&
           !network_playing)
   {
     StartGameActions(network.enabled, setup.autorecord, level.random_seed);
@@ -8896,7 +8900,6 @@ static void Life(int ax, int ay)
   int *life_parameter = (element == EL_GAME_OF_LIFE ? level.game_of_life :
                         level.biomaze);
   boolean changed = FALSE;
-  boolean use_life_bugs = FALSE;
 
   if (IS_ANIMATED(graphic))
     DrawLevelGraphicAnimationIfNeeded(ax, ay, graphic);
@@ -8933,7 +8936,7 @@ static void Life(int ax, int ay)
       boolean is_player_cell = (element == EL_GAME_OF_LIFE && IS_PLAYER(x, y));
       boolean is_neighbour = FALSE;
 
-      if (use_life_bugs)
+      if (level.use_life_bugs)
        is_neighbour =
          (((Feld[x][y] == element || is_player_cell) && !Stop[x][y]) ||
           (IS_FREE(x, y)                             &&  Stop[x][y]));
@@ -8947,7 +8950,7 @@ static void Life(int ax, int ay)
 
     boolean is_free = FALSE;
 
-    if (use_life_bugs)
+    if (level.use_life_bugs)
       is_free = (IS_FREE(xx, yy));
     else
       is_free = (IS_FREE(xx, yy) && Last[xx][yy] == EL_EMPTY);
@@ -11080,11 +11083,8 @@ static void SetTapeActionFromMouseAction(byte *tape_action,
   tape_action[TAPE_ACTION_BUTTON] = mouse_action->button;
 }
 
-static void CheckLevelTime(void)
+static void CheckLevelSolved(void)
 {
-  int i;
-
-  /* !!! SAME CODE AS IN "GameActions()" -- FIX THIS !!! */
   if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
   {
     if (level.native_em_level->lev->home == 0) /* all players at home */
@@ -11132,6 +11132,11 @@ static void CheckLevelTime(void)
     if (game_mm.game_over)                             /* game lost */
       AllPlayersGone = TRUE;
   }
+}
+
+static void CheckLevelTime(void)
+{
+  int i;
 
   if (TimeFrames >= FRAMES_PER_SECOND)
   {
@@ -11296,54 +11301,7 @@ static void GameActionsExt(void)
   if (game.restart_level)
     StartGameActions(network.enabled, setup.autorecord, level.random_seed);
 
-  /* !!! SAME CODE AS IN "CheckLevelTime()" -- FIX THIS !!! */
-  if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
-  {
-    if (level.native_em_level->lev->home == 0) /* all players at home */
-    {
-      PlayerWins(local_player);
-
-      AllPlayersGone = TRUE;
-
-      level.native_em_level->lev->home = -1;
-    }
-
-    if (level.native_em_level->ply[0]->alive == 0 &&
-       level.native_em_level->ply[1]->alive == 0 &&
-       level.native_em_level->ply[2]->alive == 0 &&
-       level.native_em_level->ply[3]->alive == 0)      /* all dead */
-      AllPlayersGone = TRUE;
-  }
-  else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
-  {
-    if (game_sp.LevelSolved &&
-       !game_sp.GameOver)                              /* game won */
-    {
-      PlayerWins(local_player);
-
-      game_sp.GameOver = TRUE;
-
-      AllPlayersGone = TRUE;
-    }
-
-    if (game_sp.GameOver)                              /* game lost */
-      AllPlayersGone = TRUE;
-  }
-  else if (level.game_engine_type == GAME_ENGINE_TYPE_MM)
-  {
-    if (game_mm.level_solved &&
-       !game_mm.game_over)                             /* game won */
-    {
-      PlayerWins(local_player);
-
-      game_mm.game_over = TRUE;
-
-      AllPlayersGone = TRUE;
-    }
-
-    if (game_mm.game_over)                             /* game lost */
-      AllPlayersGone = TRUE;
-  }
+  CheckLevelSolved();
 
   if (local_player->LevelSolved && !local_player->LevelSolved_GameEnd)
     GameWon();
@@ -11388,7 +11346,8 @@ static void GameActionsExt(void)
     if (game_status != GAME_MODE_PLAYING)
       return;
 
-    if (!network_player_action_received)
+    /* check if network player actions still missing and game still running */
+    if (!network_player_action_received && !checkGameEnded())
       return;          /* failed to get network player actions in time */
 
     /* do not yet reset "network_player_action_received" (for tape.pausing) */
@@ -11428,7 +11387,7 @@ static void GameActionsExt(void)
       stored_player[i].effective_action = stored_player[i].action;
   }
 
-  if (network_playing)
+  if (network_playing && !checkGameEnded())
     SendToServer_MovePlayer(summarized_player_action);
 
   // summarize all actions at local players mapped input device position
@@ -11542,6 +11501,7 @@ static void GameActionsExt(void)
 
   BlitScreenToBitmap(backbuffer);
 
+  CheckLevelSolved();
   CheckLevelTime();
 
   AdvanceFrameAndPlayerCounters(-1);   /* advance counters for all players */
@@ -14978,7 +14938,10 @@ void RequestRestartGame(char *message)
 {
   game.restart_game_message = NULL;
 
-  if (Request(message, REQ_ASK | REQ_STAY_CLOSED))
+  boolean has_started_game = hasStartedNetworkGame();
+  int request_mode = (has_started_game ? REQ_ASK : REQ_CONFIRM);
+
+  if (Request(message, request_mode | REQ_STAY_CLOSED) && has_started_game)
   {
     StartGameActions(network.enabled, setup.autorecord, level.random_seed);
   }
@@ -14990,6 +14953,66 @@ void RequestRestartGame(char *message)
   }
 }
 
+void CheckGameOver(void)
+{
+  static boolean last_game_over = FALSE;
+  static int game_over_delay = 0;
+  int game_over_delay_value = 50;
+  boolean game_over = checkGameFailed();
+
+  /* do not handle game over if request dialog is already active */
+  if (game.request_active)
+    return;
+
+  if (!game_over)
+  {
+    last_game_over = FALSE;
+    game_over_delay = game_over_delay_value;
+
+    return;
+  }
+
+  if (game_over_delay > 0)
+  {
+    game_over_delay--;
+
+    return;
+  }
+
+  if (last_game_over != game_over)
+    game.restart_game_message = (hasStartedNetworkGame() ?
+                                "Game over! Play it again?" :
+                                "Game over!");
+
+  last_game_over = game_over;
+}
+
+boolean checkGameSolved(void)
+{
+  /* set for all game engines if level was solved */
+  return local_player->LevelSolved_GameEnd;
+}
+
+boolean checkGameFailed(void)
+{
+  if (!AllPlayersGone)
+    return FALSE;
+
+  if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
+    return (level.native_em_level->lev->home > 0);
+  else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
+    return (game_sp.GameOver && !game_sp.LevelSolved);
+  else if (level.game_engine_type == GAME_ENGINE_TYPE_MM)
+    return (game_mm.game_over && !game_mm.level_solved);
+  else                         /* GAME_ENGINE_TYPE_RND */
+    return (local_player->GameOver && !local_player->LevelSolved);
+}
+
+boolean checkGameEnded(void)
+{
+  return (checkGameSolved() || checkGameFailed());
+}
+
 
 /* ------------------------------------------------------------------------- */
 /* random generator functions                                                */