fixed bug with global animation at wrong playfield position for one frame
[rocksndiamonds.git] / src / anim.c
index acc71733a218b1f85752b0d5be103d277298be90..ee2e1ede3fa881b979cabb5aa548acd5a617ba64 100644 (file)
@@ -310,6 +310,12 @@ int getAnimationFrame(int num_frames, int delay, int mode, int start_frame,
     else
       frame = gfx.anim_random_frame % num_frames;
   }
+  else if (mode & ANIM_LEVEL_NR)       // play frames by level number
+  {
+    int level_pos = level_nr - leveldir_current->first_level;
+
+    frame = level_pos % num_frames;
+  }
   else if (mode & (ANIM_CE_VALUE | ANIM_CE_SCORE | ANIM_CE_DELAY))
   {
     frame = sync_frame % num_frames;
@@ -1338,6 +1344,28 @@ static boolean clickConsumed(struct GlobalAnimPartControlInfo *part)
   return ((part->control_info.style & STYLE_PASSTHROUGH) ? FALSE : TRUE);
 }
 
+static void SetGlobalAnimPartTileXY(struct GlobalAnimPartControlInfo *part)
+{
+  // calculate playfield position (with scrolling) for related CE tile
+  // (do not use FX/FY, which are incorrect during envelope requests)
+  int FX0 = 2 * TILEX_VAR;     // same as FX during DRAW_TO_FIELDBUFFER
+  int FY0 = 2 * TILEY_VAR;     // same as FY during DRAW_TO_FIELDBUFFER
+  int fx = getFieldbufferOffsetX_RND(ScreenMovDir, ScreenGfxPos);
+  int fy = getFieldbufferOffsetY_RND(ScreenMovDir, ScreenGfxPos);
+  int sx = FX0 + SCREENX(part->tile_x) * TILEX_VAR;
+  int sy = FY0 + SCREENY(part->tile_y) * TILEY_VAR;
+  int cx = SX - REAL_SX;
+  int cy = SY - REAL_SY;
+  int x = sx - fx + cx;
+  int y = sy - fy + cy;
+
+  part->tile_xoffset += part->step_xoffset;
+  part->tile_yoffset += part->step_yoffset;
+
+  part->x = x + part->tile_xoffset;
+  part->y = y + part->tile_yoffset;
+}
+
 static void InitGlobalAnim_Triggered(struct GlobalAnimPartControlInfo *part,
                                     boolean *click_consumed,
                                     boolean *any_event_action,
@@ -1433,16 +1461,17 @@ static void InitGlobalAnim_Triggered_ByCustomElement(int nr, int page,
 
        if (c->position == POS_CE)
        {
-         // may contain negative tile offset that is treated as "off-screen"
-         part2->x = 0;
-         part2->y = 0;
-
          // store CE tile and offset position to handle scrolling
          part2->tile_x = x;
          part2->tile_y = y;
          part2->tile_xoffset = c->x;
          part2->tile_yoffset = c->y;
 
+         // set resulting animation position relative to CE tile position
+         // (but only for ".init_event", not ".anim_event" type events)
+         if (part2->init_event_state)
+           SetGlobalAnimPartTileXY(part2);
+
          // restart animation (by using current sync frame)
          part2->initial_anim_sync_frame = anim_sync_frame;
        }
@@ -1769,24 +1798,7 @@ static int HandleGlobalAnim_Part(struct GlobalAnimPartControlInfo *part,
 
   if (c->position == POS_CE)
   {
-    // calculate playfield position (with scrolling) for related CE tile
-    // (do not use FX/FY, which are incorrect during envelope requests)
-    int FX0 = 2 * TILEX_VAR;   // same as FX during DRAW_TO_FIELDBUFFER
-    int FY0 = 2 * TILEY_VAR;   // same as FY during DRAW_TO_FIELDBUFFER
-    int fx = getFieldbufferOffsetX_RND(ScreenMovDir, ScreenGfxPos);
-    int fy = getFieldbufferOffsetY_RND(ScreenMovDir, ScreenGfxPos);
-    int sx = FX0 + SCREENX(part->tile_x) * TILEX_VAR;
-    int sy = FY0 + SCREENY(part->tile_y) * TILEY_VAR;
-    int cx = SX - REAL_SX;
-    int cy = SY - REAL_SY;
-    int x = sx - fx + cx;
-    int y = sy - fy + cy;
-
-    part->tile_xoffset += part->step_xoffset;
-    part->tile_yoffset += part->step_yoffset;
-
-    part->x = x + part->tile_xoffset;
-    part->y = y + part->tile_yoffset;
+    SetGlobalAnimPartTileXY(part);
   }
   else
   {