fixed single step mode for R'n'D game engine when used in team mode
[rocksndiamonds.git] / src / game.c
index c4819c1190a382a0d52d8a7962cc4dd34415275e..5968b1ded7e0abc96e391632bb64cae47c948050 100644 (file)
@@ -2326,24 +2326,44 @@ static void UpdateGameControlValues(void)
       stored_player[player_nr].num_white_keys;
   }
 
-  // try to display as many collected keys as possible in the default game panel
-  for (i = STD_NUM_KEYS; i < MAX_NUM_KEYS + 1; i++)    // EMC keys + white key
+  // re-arrange keys on game panel, if needed or if defined by style settings
+  for (i = 0; i < MAX_NUM_KEYS + 1; i++)       // all normal keys + white key
   {
     int nr = GAME_PANEL_KEY_1 + i;
-    int emc_key = get_key_element_from_nr(i);
-    int element = (i < MAX_NUM_KEYS ? emc_key : EL_DC_KEY_WHITE);
     struct GamePanelControlInfo *gpc = &game_panel_controls[nr];
     struct TextPosInfo *pos = gpc->pos;
 
-    // check if panel position is undefined for a certain EMC key or white key
-    if (gpc->value != EL_EMPTY && pos->x == -1 && pos->y == -1)
+    // skip check if key is not in the player's inventory
+    if (gpc->value == EL_EMPTY)
+      continue;
+
+    // check if keys should be arranged on panel from left to right
+    if (pos->style == STYLE_LEFTMOST_POSITION)
+    {
+      // check previous key positions (left from current key)
+      for (k = 0; k < i; k++)
+      {
+       int nr_new = GAME_PANEL_KEY_1 + k;
+
+       if (game_panel_controls[nr_new].value == EL_EMPTY)
+       {
+         game_panel_controls[nr_new].value = gpc->value;
+         gpc->value = EL_EMPTY;
+
+         break;
+       }
+      }
+    }
+
+    // check if "undefined" keys can be placed at some other position
+    if (pos->x == -1 && pos->y == -1)
     {
       int nr_new = GAME_PANEL_KEY_1 + i % STD_NUM_KEYS;
 
       // 1st try: display key at the same position as normal or EM keys
       if (game_panel_controls[nr_new].value == EL_EMPTY)
       {
-       game_panel_controls[nr_new].value = element;
+       game_panel_controls[nr_new].value = gpc->value;
       }
       else
       {
@@ -2354,7 +2374,7 @@ static void UpdateGameControlValues(void)
 
          if (game_panel_controls[nr_new].value == EL_EMPTY)
          {
-           game_panel_controls[nr_new].value = element;
+           game_panel_controls[nr_new].value = gpc->value;
 
            break;
          }
@@ -3556,11 +3576,15 @@ void InitGame(void)
   InitGameEngine();
   InitGameControlValues();
 
-  // initialize tape actions from game when recording tape
   if (tape.recording)
   {
+    // initialize tape actions from game when recording tape
     tape.use_key_actions   = game.use_key_actions;
     tape.use_mouse_actions = game.use_mouse_actions;
+
+    // initialize visible playfield size when recording tape (for team mode)
+    tape.scr_fieldx = SCR_FIELDX;
+    tape.scr_fieldy = SCR_FIELDY;
   }
 
   // don't play tapes over network
@@ -4427,7 +4451,9 @@ void InitGame(void)
 
   game.restart_level = FALSE;
   game.restart_game_message = NULL;
+
   game.request_active = FALSE;
+  game.request_active_or_moving = FALSE;
 
   if (level.game_engine_type == GAME_ENGINE_TYPE_MM)
     InitGameActions_MM();
@@ -11260,13 +11286,14 @@ static void CheckSingleStepMode(struct PlayerInfo *player)
 {
   if (tape.single_step && tape.recording && !tape.pausing)
   {
-    /* 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 &&
-       !player->is_pushing &&
-       !player->is_dropping_pressed &&
-       !player->effective_mouse_action.button)
-      TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
+    // 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)
+    // (reverse logic needed here in case single step mode used in team mode)
+    if (player->is_moving ||
+       player->is_pushing ||
+       player->is_dropping_pressed ||
+       player->effective_mouse_action.button)
+      game.enter_single_step_mode = FALSE;
   }
 
   CheckSaveEngineSnapshot(player);
@@ -11929,6 +11956,10 @@ void GameActions_RND(void)
     DrawGameDoorValues();
   }
 
+  // check single step mode (set flag and clear again if any player is active)
+  game.enter_single_step_mode =
+    (tape.single_step && tape.recording && !tape.pausing);
+
   for (i = 0; i < MAX_PLAYERS; i++)
   {
     int actual_player_action = stored_player[i].effective_action;
@@ -11953,6 +11984,10 @@ void GameActions_RND(void)
     ScrollPlayer(&stored_player[i], SCROLL_GO_ON);
   }
 
+  // single step pause mode may already have been toggled by "ScrollPlayer()"
+  if (game.enter_single_step_mode && !tape.pausing)
+    TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
+
   ScrollScreen(NULL, SCROLL_GO_ON);
 
   /* for backwards compatibility, the following code emulates a fixed bug that
@@ -12426,6 +12461,8 @@ void GameActions_RND(void)
 static boolean AllPlayersInSight(struct PlayerInfo *player, int x, int y)
 {
   int min_x = x, min_y = y, max_x = x, max_y = y;
+  int scr_fieldx = getScreenFieldSizeX();
+  int scr_fieldy = getScreenFieldSizeY();
   int i;
 
   for (i = 0; i < MAX_PLAYERS; i++)
@@ -12441,7 +12478,7 @@ static boolean AllPlayersInSight(struct PlayerInfo *player, int x, int y)
     max_y = MAX(max_y, jy);
   }
 
-  return (max_x - min_x < SCR_FIELDX && max_y - min_y < SCR_FIELDY);
+  return (max_x - min_x < scr_fieldx && max_y - min_y < scr_fieldy);
 }
 
 static boolean AllPlayersInVisibleScreen(void)