added functions to check if game is over (and solved or not) (not used yet)
[rocksndiamonds.git] / src / game.c
index 03dca6bb761c5c4767a3c5236aeab6beac9f9742..5bfa71db14d69900b035c2d31a0e60df472027bd 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;
@@ -3595,7 +3596,7 @@ void InitGame(void)
 
   SCAN_PLAYFIELD(x, y)
   {
-    Feld[x][y] = level.field[x][y];
+    Feld[x][y] = Last[x][y] = level.field[x][y];
     MovPos[x][y] = MovDir[x][y] = MovDelay[x][y] = 0;
     ChangeDelay[x][y] = 0;
     ChangePage[x][y] = -1;
@@ -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();
@@ -4556,8 +4558,8 @@ void GameWon(void)
 
          Feld[ExitX][ExitY] =
            (element == EL_EXIT_OPEN            ? EL_EXIT_CLOSING :
-            element == EL_EM_EXIT_OPEN ? EL_EM_EXIT_CLOSING :
-            element == EL_SP_EXIT_OPEN ? EL_SP_EXIT_CLOSING:
+            element == EL_EM_EXIT_OPEN         ? EL_EM_EXIT_CLOSING :
+            element == EL_SP_EXIT_OPEN         ? EL_SP_EXIT_CLOSING:
             element == EL_STEEL_EXIT_OPEN      ? EL_STEEL_EXIT_CLOSING:
             EL_EM_STEEL_EXIT_CLOSING);
 
@@ -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);
@@ -8916,7 +8920,8 @@ static void Life(int ax, int ay)
   for (y1 = -1; y1 < 2; y1++) for (x1 = -1; x1 < 2; x1++)
   {
     int xx = ax+x1, yy = ay+y1;
-    int nachbarn = 0;
+    int old_element = Feld[xx][yy];
+    int num_neighbours = 0;
 
     if (!IN_LEV_FIELD(xx, yy))
       continue;
@@ -8928,33 +8933,48 @@ static void Life(int ax, int ay)
       if (!IN_LEV_FIELD(x, y) || (x == xx && y == yy))
        continue;
 
-      if (((Feld[x][y] == element ||
-           (element == EL_GAME_OF_LIFE && IS_PLAYER(x, y))) &&
-          !Stop[x][y]) ||
-         (IS_FREE(x, y) && Stop[x][y]))
-       nachbarn++;
+      boolean is_player_cell = (element == EL_GAME_OF_LIFE && IS_PLAYER(x, y));
+      boolean is_neighbour = FALSE;
+
+      if (level.use_life_bugs)
+       is_neighbour =
+         (((Feld[x][y] == element || is_player_cell) && !Stop[x][y]) ||
+          (IS_FREE(x, y)                             &&  Stop[x][y]));
+      else
+       is_neighbour =
+         (Last[x][y] == element || is_player_cell);
+
+      if (is_neighbour)
+       num_neighbours++;
     }
 
+    boolean is_free = FALSE;
+
+    if (level.use_life_bugs)
+      is_free = (IS_FREE(xx, yy));
+    else
+      is_free = (IS_FREE(xx, yy) && Last[xx][yy] == EL_EMPTY);
+
     if (xx == ax && yy == ay)          /* field in the middle */
     {
-      if (nachbarn < life_parameter[0] ||
-         nachbarn > life_parameter[1])
+      if (num_neighbours < life_parameter[0] ||
+         num_neighbours > life_parameter[1])
       {
        Feld[xx][yy] = EL_EMPTY;
-       if (!Stop[xx][yy])
+       if (Feld[xx][yy] != old_element)
          TEST_DrawLevelField(xx, yy);
        Stop[xx][yy] = TRUE;
        changed = TRUE;
       }
     }
-    else if (IS_FREE(xx, yy) || CAN_GROW_INTO(Feld[xx][yy]))
+    else if (is_free || CAN_GROW_INTO(Feld[xx][yy]))
     {                                  /* free border field */
-      if (nachbarn >= life_parameter[2] &&
-         nachbarn <= life_parameter[3])
+      if (num_neighbours >= life_parameter[2] &&
+         num_neighbours <= life_parameter[3])
       {
        Feld[xx][yy] = element;
        MovDelay[xx][yy] = (element == EL_GAME_OF_LIFE ? 0 : life_time-1);
-       if (!Stop[xx][yy])
+       if (Feld[xx][yy] != old_element)
          TEST_DrawLevelField(xx, yy);
        Stop[xx][yy] = TRUE;
        changed = TRUE;
@@ -11063,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 */
@@ -11115,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)
   {
@@ -11279,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();
@@ -11525,6 +11500,7 @@ static void GameActionsExt(void)
 
   BlitScreenToBitmap(backbuffer);
 
+  CheckLevelSolved();
   CheckLevelTime();
 
   AdvanceFrameAndPlayerCounters(-1);   /* advance counters for all players */
@@ -11732,6 +11708,8 @@ void GameActions_RND(void)
 
   SCAN_PLAYFIELD(x, y)
   {
+    Last[x][y] = Feld[x][y];
+
     ChangeCount[x][y] = 0;
     ChangeEvent[x][y] = -1;
 
@@ -14971,6 +14949,32 @@ void RequestRestartGame(char *message)
   }
 }
 
+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                                                */