rnd-20100309-2-src
[rocksndiamonds.git] / src / game.c
index eb115cb3978c1e6e27da7a57d7a196f9b683b1b2..d19831759e264f2419d09ad36316986eefa617ae 100644 (file)
@@ -2221,17 +2221,25 @@ void UpdateGameControlValues()
              local_player->LevelSolved_CountingTime :
              level.game_engine_type == GAME_ENGINE_TYPE_EM ?
              level.native_em_level->lev->time :
+             level.game_engine_type == GAME_ENGINE_TYPE_SP ?
+             level.native_sp_level->game_sp->time_played :
              level.time == 0 ? TimePlayed : TimeLeft);
   int score = (local_player->LevelSolved ?
               local_player->LevelSolved_CountingScore :
               level.game_engine_type == GAME_ENGINE_TYPE_EM ?
               level.native_em_level->lev->score :
+              level.game_engine_type == GAME_ENGINE_TYPE_SP ?
+              level.native_sp_level->game_sp->score :
               local_player->score);
   int gems = (level.game_engine_type == GAME_ENGINE_TYPE_EM ?
              level.native_em_level->lev->required :
+             level.game_engine_type == GAME_ENGINE_TYPE_SP ?
+             level.native_sp_level->game_sp->infotrons_still_needed :
              local_player->gems_still_needed);
   int exit_closed = (level.game_engine_type == GAME_ENGINE_TYPE_EM ?
                     level.native_em_level->lev->required > 0 :
+                    level.game_engine_type == GAME_ENGINE_TYPE_SP ?
+                    level.native_sp_level->game_sp->infotrons_still_needed > 0 :
                     local_player->gems_still_needed > 0 ||
                     local_player->sokobanfields_still_needed > 0 ||
                     local_player->lights_still_needed > 0);
@@ -2253,6 +2261,10 @@ void UpdateGameControlValues()
   {
     for (i = 0; i < MAX_PLAYERS; i++)
     {
+      /* only one player in Supaplex game engine */
+      if (level.game_engine_type == GAME_ENGINE_TYPE_SP && i > 0)
+       break;
+
       for (k = 0; k < MAX_NUM_KEYS; k++)
       {
        if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
@@ -2269,6 +2281,9 @@ void UpdateGameControlValues()
       if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
        game_panel_controls[GAME_PANEL_INVENTORY_COUNT].value +=
          level.native_em_level->ply[i]->dynamite;
+      else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
+       game_panel_controls[GAME_PANEL_INVENTORY_COUNT].value +=
+         level.native_sp_level->game_sp->red_disk_count;
       else
        game_panel_controls[GAME_PANEL_INVENTORY_COUNT].value +=
          stored_player[i].inventory_size;
@@ -2301,6 +2316,9 @@ void UpdateGameControlValues()
     if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
       game_panel_controls[GAME_PANEL_INVENTORY_COUNT].value +=
        level.native_em_level->ply[player_nr]->dynamite;
+    else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
+      game_panel_controls[GAME_PANEL_INVENTORY_COUNT].value +=
+       level.native_sp_level->game_sp->red_disk_count;
     else
       game_panel_controls[GAME_PANEL_INVENTORY_COUNT].value +=
        stored_player[player_nr].inventory_size;
@@ -5772,10 +5790,19 @@ void RelocatePlayer(int jx, int jy, int el_player_raw)
   Feld[jx][jy] = el_player;
   InitPlayerField(jx, jy, el_player, TRUE);
 
+  /* "InitPlayerField()" above sets Feld[jx][jy] to EL_EMPTY, but it may be
+     possible that the relocation target field did not contain a player element,
+     but a walkable element, to which the new player was relocated -- in this
+     case, restore that (already initialized!) element on the player field */
   if (!ELEM_IS_PLAYER(element))        /* player may be set on walkable element */
   {
-    Feld[jx][jy] = element;
+    Feld[jx][jy] = element;    /* restore previously existing element */
+#if 0
+    /* !!! do not initialize already initialized element a second time !!! */
+    /* (this causes at least problems with "element creation" CE trigger for
+       already existing elements, and existing Sokoban fields counted twice) */
     InitField(jx, jy, FALSE);
+#endif
   }
 
   /* only visually relocate centered player */
@@ -11983,7 +12010,16 @@ static byte PlayerActions(struct PlayerInfo *player, byte player_action)
 
     if (tape.single_step && tape.recording && !tape.pausing)
     {
+#if 1
+      /* as it is called "single step mode", just return to pause mode when the
+        player stopped moving after one tile (or never starts moving at all) */
+      if (!player->is_moving)
+#else
+      /* this is buggy: there are quite some cases where the single step mode
+        does not return to pause mode (like pushing things that don't move
+        or simply by trying to run against a wall) */
       if (button1 || (dropped && !moved))
+#endif
       {
        TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
        SnapField(player, 0, 0);                /* stop snapping */
@@ -12020,6 +12056,7 @@ static void CheckLevelTime()
 {
   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 */
@@ -12039,14 +12076,17 @@ static void CheckLevelTime()
   }
   else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
   {
-    if (game_sp_info.LevelSolved)                      /* game won */
+    if (game_sp.LevelSolved &&
+       !game_sp.GameOver)                              /* game won */
     {
       PlayerWins(local_player);
 
+      game_sp.GameOver = TRUE;
+
       AllPlayersGone = TRUE;
     }
 
-    if (game_sp_info.GameOver)                         /* game lost */
+    if (game_sp.GameOver)                              /* game lost */
       AllPlayersGone = TRUE;
   }
 
@@ -12226,6 +12266,7 @@ void GameActions()
   if (game.restart_level)
     StartGameActions(options.network, 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 */
@@ -12243,6 +12284,21 @@ void GameActions()
        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;
+  }
 
   if (local_player->LevelSolved && !local_player->LevelSolved_GameEnd)
     GameWon();
@@ -15360,8 +15416,13 @@ static int DigField(struct PlayerInfo *player,
        PlayLevelSoundElementAction(nextx, nexty, EL_SOKOBAN_FIELD_EMPTY,
                                    ACTION_FILLING);
 
+#if 1
+      if (local_player->sokobanfields_still_needed == 0 &&
+         (game.emulation == EMU_SOKOBAN || level.auto_exit_sokoban))
+#else
       if (local_player->sokobanfields_still_needed == 0 &&
          game.emulation == EMU_SOKOBAN)
+#endif
       {
        PlayerWins(player);
 
@@ -16370,8 +16431,6 @@ unsigned int RND(int max)
 /* game engine snapshot handling functions                                   */
 /* ------------------------------------------------------------------------- */
 
-#define ARGS_ADDRESS_AND_SIZEOF(x)             (&(x)), (sizeof(x))
-
 struct EngineSnapshotInfo
 {
   /* runtime values for custom element collect score */
@@ -16381,32 +16440,14 @@ struct EngineSnapshotInfo
   int choice_pos[NUM_GROUP_ELEMENTS];
 
   /* runtime values for belt position animations */
-  int belt_graphic[4 * NUM_BELT_PARTS];
-  int belt_anim_mode[4 * NUM_BELT_PARTS];
-};
-
-struct EngineSnapshotNodeInfo
-{
-  void *buffer_orig;
-  void *buffer_copy;
-  int size;
+  int belt_graphic[4][NUM_BELT_PARTS];
+  int belt_anim_mode[4][NUM_BELT_PARTS];
 };
 
 static struct EngineSnapshotInfo engine_snapshot_rnd;
-static ListNode *engine_snapshot_list = NULL;
 static char *snapshot_level_identifier = NULL;
 static int snapshot_level_nr = -1;
 
-void FreeEngineSnapshot()
-{
-  while (engine_snapshot_list != NULL)
-    deleteNodeFromList(&engine_snapshot_list, engine_snapshot_list->key,
-                      checked_free);
-
-  setString(&snapshot_level_identifier, NULL);
-  snapshot_level_nr = -1;
-}
-
 static void SaveEngineSnapshotValues_RND()
 {
   static int belt_base_active_element[4] =
@@ -16440,8 +16481,8 @@ static void SaveEngineSnapshotValues_RND()
       int graphic = el2img(element);
       int anim_mode = graphic_info[graphic].anim_mode;
 
-      engine_snapshot_rnd.belt_graphic[i * 4 + j] = graphic;
-      engine_snapshot_rnd.belt_anim_mode[i * 4 + j] = anim_mode;
+      engine_snapshot_rnd.belt_graphic[i][j] = graphic;
+      engine_snapshot_rnd.belt_anim_mode[i][j] = anim_mode;
     }
   }
 }
@@ -16469,8 +16510,8 @@ static void LoadEngineSnapshotValues_RND()
   {
     for (j = 0; j < NUM_BELT_PARTS; j++)
     {
-      int graphic = engine_snapshot_rnd.belt_graphic[i * 4 + j];
-      int anim_mode = engine_snapshot_rnd.belt_anim_mode[i * 4 + j];
+      int graphic = engine_snapshot_rnd.belt_graphic[i][j];
+      int anim_mode = engine_snapshot_rnd.belt_anim_mode[i][j];
 
       graphic_info[graphic].anim_mode = anim_mode;
     }
@@ -16492,36 +16533,26 @@ static void LoadEngineSnapshotValues_RND()
   }
 }
 
-static void SaveEngineSnapshotBuffer(void *buffer, int size)
-{
-  struct EngineSnapshotNodeInfo *bi =
-    checked_calloc(sizeof(struct EngineSnapshotNodeInfo));
-
-  bi->buffer_orig = buffer;
-  bi->buffer_copy = checked_malloc(size);
-  bi->size = size;
-
-  memcpy(bi->buffer_copy, buffer, size);
-
-  addNodeToList(&engine_snapshot_list, NULL, bi);
-}
-
 void SaveEngineSnapshot()
 {
-  FreeEngineSnapshot();                /* free previous snapshot, if needed */
-
-  if (level_editor_test_game)  /* do not save snapshots from editor */
+  /* do not save snapshots from editor */
+  if (level_editor_test_game)
     return;
 
+  /* free previous snapshot buffers, if needed */
+  FreeEngineSnapshotBuffers();
+
   /* copy some special values to a structure better suited for the snapshot */
 
   SaveEngineSnapshotValues_RND();
   SaveEngineSnapshotValues_EM();
+  SaveEngineSnapshotValues_SP();
 
   /* save values stored in special snapshot structure */
 
   SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(engine_snapshot_rnd));
   SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(engine_snapshot_em));
+  SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(engine_snapshot_sp));
 
   /* save further RND engine values */
 
@@ -16595,7 +16626,7 @@ void SaveEngineSnapshot()
   snapshot_level_nr = level_nr;
 
 #if 0
-  ListNode *node = engine_snapshot_list;
+  ListNode *node = engine_snapshot_list_rnd;
   int num_bytes = 0;
 
   while (node != NULL)
@@ -16609,29 +16640,17 @@ void SaveEngineSnapshot()
 #endif
 }
 
-static void LoadEngineSnapshotBuffer(struct EngineSnapshotNodeInfo *bi)
-{
-  memcpy(bi->buffer_orig, bi->buffer_copy, bi->size);
-}
-
 void LoadEngineSnapshot()
 {
-  ListNode *node = engine_snapshot_list;
+  /* restore generically stored snapshot buffers */
 
-  if (engine_snapshot_list == NULL)
-    return;
-
-  while (node != NULL)
-  {
-    LoadEngineSnapshotBuffer((struct EngineSnapshotNodeInfo *)node->content);
-
-    node = node->next;
-  }
+  LoadEngineSnapshotBuffers();
 
   /* restore special values from snapshot structure */
 
   LoadEngineSnapshotValues_RND();
   LoadEngineSnapshotValues_EM();
+  LoadEngineSnapshotValues_SP();
 }
 
 boolean CheckEngineSnapshot()