added visible playfield size to tape structure (not used yet)
[rocksndiamonds.git] / src / game.c
index 5e4e151fe3134c7548cce810dff6eb1f72fe7648..768ba2e181da6890c0e58287750b3ae09dbcbca7 100644 (file)
@@ -2251,6 +2251,7 @@ static void UpdateGameControlValues(void)
                level.game_engine_type == GAME_ENGINE_TYPE_MM ?
                MM_HEALTH(game_mm.laser_overload_value) :
                game.health);
+  int sync_random_frame = INIT_GFX_RANDOM();   // random, but synchronized
 
   UpdatePlayfieldElementCount();
 
@@ -2325,6 +2326,63 @@ static void UpdateGameControlValues(void)
       stored_player[player_nr].num_white_keys;
   }
 
+  // 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;
+    struct GamePanelControlInfo *gpc = &game_panel_controls[nr];
+    struct TextPosInfo *pos = gpc->pos;
+
+    // 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 = gpc->value;
+      }
+      else
+      {
+       // 2nd try: display key at the next free position in the key panel
+       for (k = 0; k < STD_NUM_KEYS; k++)
+       {
+         nr_new = GAME_PANEL_KEY_1 + k;
+
+         if (game_panel_controls[nr_new].value == EL_EMPTY)
+         {
+           game_panel_controls[nr_new].value = gpc->value;
+
+           break;
+         }
+       }
+      }
+    }
+  }
+
   for (i = 0; i < NUM_PANEL_INVENTORY; i++)
   {
     game_panel_controls[GAME_PANEL_INVENTORY_FIRST_1 + i].value =
@@ -2478,11 +2536,13 @@ static void UpdateGameControlValues(void)
        int last_anim_random_frame = gfx.anim_random_frame;
        int element = gpc->value;
        int graphic = el2panelimg(element);
+       int init_gfx_random = (graphic_info[graphic].anim_global_sync ?
+                              sync_random_frame : INIT_GFX_RANDOM());
 
        if (gpc->value != gpc->last_value)
        {
          gpc->gfx_frame = 0;
-         gpc->gfx_random = INIT_GFX_RANDOM();
+         gpc->gfx_random = init_gfx_random;
        }
        else
        {
@@ -2490,7 +2550,7 @@ static void UpdateGameControlValues(void)
 
          if (ANIM_MODE(graphic) == ANIM_RANDOM &&
              IS_NEXT_FRAME(gpc->gfx_frame, graphic))
-           gpc->gfx_random = INIT_GFX_RANDOM();
+           gpc->gfx_random = init_gfx_random;
        }
 
        if (ANIM_MODE(graphic) == ANIM_RANDOM)
@@ -2499,8 +2559,7 @@ static void UpdateGameControlValues(void)
        if (ANIM_MODE(graphic) == ANIM_CE_SCORE)
          gpc->gfx_frame = element_info[element].collect_score;
 
-       gpc->frame = getGraphicAnimationFrame(el2panelimg(gpc->value),
-                                             gpc->gfx_frame);
+       gpc->frame = getGraphicAnimationFrame(graphic, gpc->gfx_frame);
 
        if (ANIM_MODE(graphic) == ANIM_RANDOM)
          gfx.anim_random_frame = last_anim_random_frame;
@@ -2512,11 +2571,13 @@ static void UpdateGameControlValues(void)
       {
        int last_anim_random_frame = gfx.anim_random_frame;
        int graphic = gpc->graphic;
+       int init_gfx_random = (graphic_info[graphic].anim_global_sync ?
+                              sync_random_frame : INIT_GFX_RANDOM());
 
        if (gpc->value != gpc->last_value)
        {
          gpc->gfx_frame = 0;
-         gpc->gfx_random = INIT_GFX_RANDOM();
+         gpc->gfx_random = init_gfx_random;
        }
        else
        {
@@ -2524,7 +2585,7 @@ static void UpdateGameControlValues(void)
 
          if (ANIM_MODE(graphic) == ANIM_RANDOM &&
              IS_NEXT_FRAME(gpc->gfx_frame, graphic))
-           gpc->gfx_random = INIT_GFX_RANDOM();
+           gpc->gfx_random = init_gfx_random;
        }
 
        if (ANIM_MODE(graphic) == ANIM_RANDOM)
@@ -2589,6 +2650,10 @@ static void DisplayGameControlValues(void)
     if (PANEL_DEACTIVATED(pos))
       continue;
 
+    if (pos->class == get_hash_from_key("extra_panel_items") &&
+       !setup.prefer_extra_panel_items)
+      continue;
+
     gpc->last_value = value;
     gpc->last_frame = frame;
 
@@ -3511,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
@@ -4382,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();
@@ -11200,6 +11271,15 @@ static void CheckSaveEngineSnapshot(struct PlayerInfo *player)
     if (!player->is_dropping)
       player->was_dropping = FALSE;
   }
+
+  static struct MouseActionInfo mouse_action_last = { 0 };
+  struct MouseActionInfo mouse_action = player->effective_mouse_action;
+  boolean new_released = (!mouse_action.button && mouse_action_last.button);
+
+  if (new_released)
+    CheckSaveEngineSnapshotToList();
+
+  mouse_action_last = mouse_action;
 }
 
 static void CheckSingleStepMode(struct PlayerInfo *player)
@@ -13988,6 +14068,10 @@ static int DigField(struct PlayerInfo *player,
     CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_DIGS_X,
                                        player->index_bit, dig_side);
 
+    // if digging triggered player relocation, finish digging tile
+    if (mode == DF_DIG && (player->jx != jx || player->jy != jy))
+      setFieldForSnapping(x, y, element, move_direction);
+
     if (mode == DF_SNAP)
     {
       if (level.block_snap_field)
@@ -14109,9 +14193,15 @@ static int DigField(struct PlayerInfo *player,
     PlayLevelSoundElementAction(x, y, element, ACTION_COLLECTING);
 
     if (is_player)
+    {
       CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_COLLECTS_X,
                                          player->index_bit, dig_side);
 
+      // if collecting triggered player relocation, finish collecting tile
+      if (mode == DF_DIG && (player->jx != jx || player->jy != jy))
+       setFieldForSnapping(x, y, element, move_direction);
+    }
+
     if (mode == DF_SNAP)
     {
       if (level.block_snap_field)
@@ -15233,6 +15323,9 @@ void RequestRestartGame(char *message)
   }
   else
   {
+    // needed in case of envelope request to close game panel
+    CloseDoor(DOOR_CLOSE_1);
+
     SetGameStatus(GAME_MODE_MAIN);
 
     DrawMainMenu();