removed explicitly setting draw order for pointer-style animations
[rocksndiamonds.git] / src / anim.c
index 7ecdf8fdc04d9aeadd06f7bbb6c0ef639016623b..a23d6e581de1c2f23c1b780d91e1f771c92f1247 100644 (file)
@@ -137,6 +137,9 @@ struct GlobalAnimPartControlInfo
   int anim_delay_counter;
   int post_delay_counter;
 
+  int fade_delay_counter;
+  int fade_alpha;
+
   boolean init_event_state;
   boolean anim_event_state;
 
@@ -312,7 +315,7 @@ int getAnimationFrame(int num_frames, int delay, int mode, int start_frame,
   }
   else if (mode & ANIM_LEVEL_NR)       // play frames by level number
   {
-    int level_pos = level_nr - leveldir_current->first_level;
+    int level_pos = level_nr - gfx.anim_first_level;
 
     frame = level_pos % num_frames;
   }
@@ -357,10 +360,8 @@ static int compareGlobalAnimPartControlInfo(const void *obj1, const void *obj2)
     (struct GlobalAnimPartControlInfo *)obj2;
   int compare_result;
 
-  if (o1->control_info.draw_order != o2->control_info.draw_order)
-    compare_result = o1->control_info.draw_order - o2->control_info.draw_order;
-  else
-    compare_result = o1->nr - o2->nr;
+  // do not sort animations parts by draw order (as it would be confusing)
+  compare_result = o1->nr - o2->nr;
 
   return compare_result;
 }
@@ -395,8 +396,8 @@ static boolean isPausedOnPlayfieldOrDoor(struct GlobalAnimPartControlInfo *part)
   if (!part->class_playfield_or_door)
     return FALSE;
 
-  // only pause animations when engine is paused or request dialog is open(ing)
-  if (!tape.pausing && !game.request_active_or_moving)
+  // only pause animations when engine is paused or request dialog is active
+  if (!tape.pausing && !game.request_active)
     return FALSE;
 
   return TRUE;
@@ -601,19 +602,10 @@ static void InitGlobalAnimControls(void)
          anim->has_base = TRUE;
        }
 
-       // apply special settings for pointer-style animations
-       if (part->control_info.class == get_hash_from_key("pointer"))
-       {
-         // force animation to be on top (must set anim and part control)
-         if (anim->control_info.draw_order == 0)
-           anim->control_info.draw_order = 1000000;
-         if (part->control_info.draw_order == 0)
-           part->control_info.draw_order = 1000000;
-
-         // force animation to pass-through clicks (must set part control)
-         if (part->control_info.style == STYLE_DEFAULT)
-           part->control_info.style |= STYLE_PASSTHROUGH;
-       }
+       // force pointer-style animations to pass-through clicks
+       if (part->control_info.class == get_hash_from_key("pointer") &&
+           part->control_info.style == STYLE_DEFAULT)
+         part->control_info.style |= STYLE_PASSTHROUGH;
       }
 
       if (anim->num_parts > 0 || anim->has_base)
@@ -735,6 +727,7 @@ static void BlitGlobalAnimation(struct GlobalAnimPartControlInfo *part,
   Bitmap *fade_bitmap =
     (drawing_target == DRAW_TO_FADE_SOURCE ? gfx.fade_bitmap_source :
      drawing_target == DRAW_TO_FADE_TARGET ? gfx.fade_bitmap_target : NULL);
+  int alpha = (c->fade_mode & FADE_MODE_FADE ? part->fade_alpha : g->alpha);
   int x, y;
 
   for (y = 0; y < c->stacked_yfactor; y++)
@@ -781,6 +774,8 @@ static void BlitGlobalAnimation(struct GlobalAnimPartControlInfo *part,
       dst_x += part->viewport_x;
       dst_y += part->viewport_y;
 
+      SetBitmapAlphaNextBlit(src_bitmap, alpha);
+
       if (drawing_target == DRAW_TO_SCREEN)
        blit_screen(src_bitmap, src_x, src_y, width, height,
                    dst_x, dst_y);
@@ -1535,6 +1530,7 @@ static int HandleGlobalAnim_Part(struct GlobalAnimPartControlInfo *part,
   struct GraphicInfo *g = &part->graphic_info;
   struct GraphicInfo *c = &part->control_info;
   boolean viewport_changed = SetGlobalAnimPart_Viewport(part);
+  int alpha = (g->alpha != -1 ? g->alpha : SDL_ALPHA_OPAQUE);
 
   // if game is paused, also pause playfield and door animations
   if (isPausedOnPlayfieldOrDoor(part))
@@ -1571,6 +1567,18 @@ static int HandleGlobalAnim_Part(struct GlobalAnimPartControlInfo *part,
     if (part->anim_random_frame == -1)
       part->anim_random_frame = GetSimpleRandom(g->anim_frames);
 
+    if (c->fade_mode & FADE_MODE_FADE)
+    {
+      // when fading in screen, first frame is 100 % transparent or opaque
+      part->fade_delay_counter = c->fade_delay + 1;
+      part->fade_alpha = (c->fade_mode == FADE_MODE_FADE_IN ? 0 : alpha);
+    }
+    else
+    {
+      part->fade_delay_counter = 0;
+      part->fade_alpha = -1;
+    }
+
     if (c->direction & MV_HORIZONTAL)
     {
       int pos_bottom = part->viewport_height - g->height;
@@ -1784,6 +1792,14 @@ static int HandleGlobalAnim_Part(struct GlobalAnimPartControlInfo *part,
     return ANIM_STATE_WAITING;
   }
 
+  if (part->fade_delay_counter > 0)
+  {
+    part->fade_delay_counter--;
+    part->fade_alpha = alpha * (c->fade_mode == FADE_MODE_FADE_IN ?
+                               c->fade_delay - part->fade_delay_counter :
+                               part->fade_delay_counter) / c->fade_delay;
+  }
+
   // special case to prevent expiring loop sounds when playing
   PlayGlobalAnimSoundIfLoop(part);
 
@@ -1934,9 +1950,13 @@ static void HandleGlobalAnim_Main(struct GlobalAnimMainControlInfo *anim,
   for (i = 0; i < num_parts; i++)
     anim->part[i].state = ANIM_STATE_INACTIVE;
 
-  // ... then set current animation parts to "running"
+  // ... then set current animation part to "running" ...
   part->state = ANIM_STATE_RUNNING;
 
+  // ... unless it is waiting for an initial event
+  if (part->init_event_state)
+    part->state = ANIM_STATE_WAITING;
+
   anim->state = HandleGlobalAnim_Part(part, anim->state);
 
   if (anim->state & ANIM_STATE_RESTART)
@@ -2108,6 +2128,11 @@ static boolean InitGlobalAnim_Clicked(int mx, int my, int clicked_event)
       {
        struct GlobalAnimPartControlInfo *part = &anim->part[part_nr];
 
+       // if request dialog is active, only handle pointer-style animations
+       if (game.request_active &&
+           part->control_info.class != get_hash_from_key("pointer"))
+         continue;
+
        if (clicked_event == ANIM_CLICKED_RESET)
        {
          part->clicked = FALSE;