increased maximum number of global animations (and parts) from 8 to 32
[rocksndiamonds.git] / src / anim.c
index b566bddcbc27132d458a1dbf28519f4b3aba6d78..7464637dd3dc9443eae91b2bcdeeb833d8c2dd41 100644 (file)
@@ -126,6 +126,8 @@ struct GlobalAnimMainControlInfo
 
   boolean has_base;    // animation has base/main/default animation part
 
+  int last_x, last_y;
+
   int init_delay_counter;
 
   int state;
@@ -340,6 +342,9 @@ static void InitToonControls()
 
   anim->has_base = FALSE;
 
+  anim->last_x = POS_OFFSCREEN;
+  anim->last_y = POS_OFFSCREEN;
+
   anim->init_delay_counter = 0;
 
   anim->state = ANIM_STATE_INACTIVE;
@@ -433,6 +438,9 @@ void InitGlobalAnimControls()
 
       anim->has_base = FALSE;
 
+      anim->last_x = POS_OFFSCREEN;
+      anim->last_y = POS_OFFSCREEN;
+
       anim->init_delay_counter = 0;
 
       anim->state = ANIM_STATE_INACTIVE;
@@ -926,27 +934,23 @@ static void StopGlobalAnimSoundAndMusic(struct GlobalAnimPartControlInfo *part)
   StopGlobalAnimMusic(part);
 }
 
-static boolean matchesAnimEventMask(int bits, int mask)
-{
-  return (bits & (mask & ANIM_EVENT_CLICK_ANIM_ALL) &&
-         bits & (mask & ANIM_EVENT_CLICK_PART_ALL));
-}
-
 static boolean isClickablePart(struct GlobalAnimPartControlInfo *part, int mask)
 {
   struct GraphicInfo *c = &part->control_info;
-
-  boolean clickable_self = FALSE;
-  boolean clickable_triggered = FALSE;
-
-  if (mask & ANIM_EVENT_CLICK_SELF)
-    clickable_self = (c->init_event & ANIM_EVENT_CLICK_SELF ||
-                     c->anim_event & ANIM_EVENT_CLICK_SELF);
-
-  clickable_triggered = (matchesAnimEventMask(c->init_event, mask) ||
-                        matchesAnimEventMask(c->anim_event, mask));
-
-  return (clickable_self || clickable_triggered);
+  int trigger_mask = ANIM_EVENT_ANIM_MASK | ANIM_EVENT_PART_MASK;
+  int mask_anim_only = mask & ANIM_EVENT_ANIM_MASK;
+
+  if (mask & ANIM_EVENT_ANY)
+    return (c->init_event & ANIM_EVENT_ANY ||
+           c->anim_event & ANIM_EVENT_ANY);
+  else if (mask & ANIM_EVENT_SELF)
+    return (c->init_event & ANIM_EVENT_SELF ||
+           c->anim_event & ANIM_EVENT_SELF);
+  else
+    return ((c->init_event & trigger_mask) == mask ||
+           (c->anim_event & trigger_mask) == mask ||
+           (c->init_event & trigger_mask) == mask_anim_only ||
+           (c->anim_event & trigger_mask) == mask_anim_only);
 }
 
 static boolean isClickedPart(struct GlobalAnimPartControlInfo *part,
@@ -981,6 +985,8 @@ static boolean isClickedPart(struct GlobalAnimPartControlInfo *part,
 
 int HandleGlobalAnim_Part(struct GlobalAnimPartControlInfo *part, int state)
 {
+  struct GlobalAnimControlInfo *ctrl = &global_anim_ctrl[part->mode_nr];
+  struct GlobalAnimMainControlInfo *anim = &ctrl->anim[part->anim_nr];
   struct GraphicInfo *g = &part->graphic_info;
   struct GraphicInfo *c = &part->control_info;
   boolean viewport_changed = SetGlobalAnimPart_Viewport(part);
@@ -1077,6 +1083,14 @@ int HandleGlobalAnim_Part(struct GlobalAnimPartControlInfo *part, int state)
     if (c->y != ARG_UNDEFINED_VALUE)
       part->y = c->y;
 
+    if (c->position == POS_LAST &&
+       anim->last_x > -g->width  && anim->last_x < part->viewport_width &&
+       anim->last_y > -g->height && anim->last_y < part->viewport_height)
+    {
+      part->x = anim->last_x;
+      part->y = anim->last_y;
+    }
+
     if (c->step_xoffset != ARG_UNDEFINED_VALUE)
       part->step_xoffset = c->step_xoffset;
     if (c->step_yoffset != ARG_UNDEFINED_VALUE)
@@ -1204,6 +1218,9 @@ int HandleGlobalAnim_Part(struct GlobalAnimPartControlInfo *part, int state)
   part->x += part->step_xoffset;
   part->y += part->step_yoffset;
 
+  anim->last_x = part->x;
+  anim->last_y = part->y;
+
   return ANIM_STATE_RUNNING;
 }
 
@@ -1452,25 +1469,28 @@ static boolean InitGlobalAnim_Clicked(int mx, int my, boolean clicked)
          continue;
        }
 
-       if (part->clickable &&
-           isClickedPart(part, mx, my, clicked))
+       if (!part->clickable)
+         continue;
+
+       if (isClickablePart(part, ANIM_EVENT_ANY))
+         any_part_clicked = part->clicked = TRUE;
+
+       if (isClickedPart(part, mx, my, clicked))
        {
 #if 0
          printf("::: %d.%d CLICKED\n", anim_nr, part_nr);
 #endif
 
-         if (isClickablePart(part, ANIM_EVENT_CLICK_SELF))
+         if (isClickablePart(part, ANIM_EVENT_SELF))
            any_part_clicked = part->clicked = TRUE;
 
          // check if this click is defined to trigger other animations
-         int old_anim_nr = part->old_anim_nr;
-         int old_part_nr = part->old_nr;
-         int mask = ANIM_EVENT_CLICK_ANIM_1 << old_anim_nr;
-
-         if (part->is_base)
-           mask |= ANIM_EVENT_CLICK_PART_ALL;
-         else
-           mask |= ANIM_EVENT_CLICK_PART_1 << old_part_nr;
+         int gic_anim_nr = part->old_anim_nr + 1;      // X as in "anim_X"
+         int gic_part_nr = part->old_nr + 1;           // Y as in "part_Y"
+         int mask = gic_anim_nr << ANIM_EVENT_ANIM_BIT;
+
+         if (!part->is_base)
+           mask |= gic_part_nr << ANIM_EVENT_PART_BIT;
 
          int anim2_nr;