added support for custom elements triggering global animations
authorHolger Schemel <info@artsoft.org>
Sat, 29 Jul 2023 23:50:39 +0000 (01:50 +0200)
committerHolger Schemel <info@artsoft.org>
Sun, 3 Sep 2023 20:59:57 +0000 (22:59 +0200)
For the global animation options ".init_event" or "anim_event" in file
"graphicsinfo.conf", the new value "ce_change:custom_xxx" can be used
to trigger (initiate or continue) the corresponding global animation
whenever custom element "custom_xxx" changes.

src/anim.c
src/anim.h
src/files.c
src/game.c
src/libgame/system.h
src/main.h

index 39f7e6469280c5a8da51dbc1bf13a0d0aaf92aaf..bbc38dc45903bde745711a925b9ad3bc3983333e 100644 (file)
@@ -631,6 +631,59 @@ static void InitGlobalAnimControls(void)
   anim_classes_last = ANIM_CLASS_NONE;
 }
 
+static void SetGlobalAnimEventsForCustomElements(int list_pos)
+{
+  int num_events = GetGlobalAnimEventValueCount(list_pos);
+  int i;
+
+  for (i = 0; i < num_events; i++)
+  {
+    int event = GetGlobalAnimEventValue(list_pos, i);
+
+    if (event & ANIM_EVENT_CE_CHANGE)
+    {
+      int nr = (event >> ANIM_EVENT_CE_BIT) & 0xff;
+
+      if (nr >= 0 && nr < NUM_CUSTOM_ELEMENTS)
+       element_info[EL_CUSTOM_START + nr].has_anim_event = TRUE;
+    }
+  }
+}
+
+void InitGlobalAnimEventsForCustomElements(void)
+{
+  int m, a, p;
+  int control;
+
+  // custom element events for global animations only relevant while playing
+  m = GAME_MODE_PLAYING;
+
+  for (a = 0; a < NUM_GLOBAL_ANIMS; a++)
+  {
+    int ctrl_id = GLOBAL_ANIM_ID_CONTROL_FIRST + a;
+
+    control = global_anim_info[ctrl_id].graphic[GLOBAL_ANIM_ID_PART_BASE][m];
+
+    // if no base animation parameters defined, use default values
+    if (control == IMG_UNDEFINED)
+      control = IMG_INTERNAL_GLOBAL_ANIM_DEFAULT;
+
+    SetGlobalAnimEventsForCustomElements(graphic_info[control].init_event);
+    SetGlobalAnimEventsForCustomElements(graphic_info[control].anim_event);
+
+    for (p = 0; p < NUM_GLOBAL_ANIM_PARTS_ALL; p++)
+    {
+      control = global_anim_info[ctrl_id].graphic[p][m];
+
+      if (control == IMG_UNDEFINED)
+       continue;
+
+      SetGlobalAnimEventsForCustomElements(graphic_info[control].init_event);
+      SetGlobalAnimEventsForCustomElements(graphic_info[control].anim_event);
+    }
+  }
+}
+
 void InitGlobalAnimations(void)
 {
   InitGlobalAnimControls();
@@ -1145,6 +1198,8 @@ static boolean checkGlobalAnimEvent(int anim_event, int mask)
     return (anim_event & ANIM_EVENT_SELF);
   else if (mask & ANIM_EVENT_UNCLICK_ANY)
     return (anim_event & ANIM_EVENT_UNCLICK_ANY);
+  else if (mask & ANIM_EVENT_CE_CHANGE)
+    return (anim_event == mask);
   else
     return (anim_event == mask ||
            anim_event == mask_anim_only);
@@ -1303,6 +1358,39 @@ static void InitGlobalAnim_Triggered(struct GlobalAnimPartControlInfo *part,
   }
 }
 
+static void InitGlobalAnim_Triggered_ByCustomElement(int nr)
+{
+  struct GlobalAnimControlInfo *ctrl = &global_anim_ctrl[GAME_MODE_PLAYING];
+
+  int event_value = ANIM_EVENT_CE_CHANGE;
+  int mask = event_value | (nr << ANIM_EVENT_CE_BIT);
+  int anim2_nr;
+
+  for (anim2_nr = 0; anim2_nr < ctrl->num_anims; anim2_nr++)
+  {
+    struct GlobalAnimMainControlInfo *anim2 = &ctrl->anim[anim2_nr];
+    int part2_nr;
+
+    for (part2_nr = 0; part2_nr < anim2->num_parts_all; part2_nr++)
+    {
+      struct GlobalAnimPartControlInfo *part2 = &anim2->part[part2_nr];
+
+      if (!(part2->state & ANIM_STATE_RUNNING))
+       continue;
+
+      if (isClickablePart(part2, mask))
+      {
+       part2->triggered = TRUE;
+
+#if 0
+       Debug("anim:InitGlobalAnim_Triggered_ByCustomElement",
+             "%d.%d TRIGGERED BY CE %d", anim2_nr, part2_nr, nr + 1);
+#endif
+      }
+    }
+  }
+}
+
 static void HandleGlobalAnimDelay(struct GlobalAnimPartControlInfo *part,
                                  int delay_type, char *info_text)
 {
@@ -2051,3 +2139,11 @@ int getGlobalAnimSyncFrame(void)
 {
   return anim_sync_frame;
 }
+
+void HandleGlobalAnimEventByElementChange(int element)
+{
+  if (!IS_CUSTOM_ELEMENT(element))
+    return;
+
+  InitGlobalAnim_Triggered_ByCustomElement(element - EL_CUSTOM_START);
+}
index d16d92370c32bfb9462adddd39394688651ff4d6..bf9561fde35c37c6e98f01640415d217b8f9332a 100644 (file)
 
 int getAnimationFrame(int, int, int, int, int);
 
+void InitGlobalAnimEventsForCustomElements(void);
 void InitGlobalAnimations(void);
 void DrawGlobalAnimations(int, int);
 
 void RestartGlobalAnimsByStatus(int);
 
 boolean HandleGlobalAnimClicks(int, int, int, boolean);
+void HandleGlobalAnimEventByElementChange(int);
 
 int getGlobalAnimSyncFrame(void);
 
index 58d3e1b77ef4619415c98f96cfffc3b66d667dd0..42208ce6ec4b99dd9e9499d8cbb64a9923ca29e0 100644 (file)
@@ -11546,6 +11546,57 @@ static boolean string_has_parameter(char *s, char *s_contained)
   return string_has_parameter(substring, s_contained);
 }
 
+static int get_anim_parameter_value_ce(char *s)
+{
+  char *s_ptr = s;
+  char *pattern = "ce_change:custom_";
+  int pattern_len = strlen(pattern);
+  char *matching_char = strstr(s_ptr, pattern);
+  int result = ANIM_EVENT_NONE;
+
+  if (matching_char == NULL)
+    return ANIM_EVENT_NONE;
+
+  result = ANIM_EVENT_CE_CHANGE;
+
+  s_ptr = matching_char + pattern_len;
+
+  // check for custom element number ("custom_X" or "custom_XX" or "custom_XXX")
+  if (*s_ptr >= '0' && *s_ptr <= '9')
+  {
+    int gic_ce_nr = (*s_ptr++ - '0');
+
+    if (*s_ptr >= '0' && *s_ptr <= '9')
+    {
+      gic_ce_nr = 10 * gic_ce_nr + (*s_ptr++ - '0');
+
+      if (*s_ptr >= '0' && *s_ptr <= '9')
+       gic_ce_nr = 10 * gic_ce_nr + (*s_ptr++ - '0');
+    }
+
+    if (gic_ce_nr < 1 || gic_ce_nr > NUM_CUSTOM_ELEMENTS)
+      return ANIM_EVENT_NONE;
+
+    // store internal CE number (0 to 255, not "custom_1" to "custom_256")
+    gic_ce_nr--;
+
+    result |= gic_ce_nr << ANIM_EVENT_CE_BIT;
+  }
+  else
+  {
+    // invalid custom element number specified
+
+    return ANIM_EVENT_NONE;
+  }
+
+  // discard result if next character is neither delimiter nor whitespace
+  if (!(*s_ptr == ',' || *s_ptr == '\0' ||
+       *s_ptr == ' ' || *s_ptr == '\t'))
+    return ANIM_EVENT_NONE;
+
+  return result;
+}
+
 static int get_anim_parameter_value(char *s)
 {
   int event_value[] =
@@ -11571,6 +11622,11 @@ static int get_anim_parameter_value(char *s)
   int result = ANIM_EVENT_NONE;
   int i;
 
+  result = get_anim_parameter_value_ce(s);
+
+  if (result != ANIM_EVENT_NONE)
+    return result;
+
   for (i = 0; i < ARRAY_SIZE(event_value); i++)
   {
     matching_char = strstr(s_ptr, pattern_1[i]);
@@ -11657,8 +11713,13 @@ static int get_anim_parameter_values(char *s)
 
   // if animation event found, add it to global animation event list
   if (event_value != ANIM_EVENT_NONE)
+  {
     list_pos = AddGlobalAnimEventValue(list_pos, event_value);
 
+    // continue with next part of the string, starting with next comma
+    s = strchr(s + 1, ',');
+  }
+
   while (s != NULL)
   {
     // add optional "click:anim_X" or "click:anim_X.part_X" parameter
index c3b2ef7efa08938c50f2d43ddb4091eb2815a70c..0d1830340a376487b5c2b7d6cd972b537a7060d7 100644 (file)
@@ -3195,6 +3195,17 @@ static void InitGameEngine(void)
     SET_PROPERTY(ch_delay->element, EP_CAN_CHANGE_OR_HAS_ACTION, TRUE);
   }
 
+  // ---------- initialize if element can trigger global animations -----------
+
+  for (i = 0; i < MAX_NUM_ELEMENTS; i++)
+  {
+    struct ElementInfo *ei = &element_info[i];
+
+    ei->has_anim_event = FALSE;
+  }
+
+  InitGlobalAnimEventsForCustomElements();
+
   // ---------- initialize internal run-time variables ------------------------
 
   for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
@@ -10704,6 +10715,9 @@ static boolean ChangeElement(int x, int y, int element, int page)
 
   ChangeCount[x][y]++;         // count number of changes in the same frame
 
+  if (ei->has_anim_event)
+    HandleGlobalAnimEventByElementChange(element);
+
   if (change->explode)
   {
     Bang(x, y);
index 44ac3e3448626e95065285ae524203ae6ab0a396..1c6cb88d39b2875508b79e336910a83b13c51e9c 100644 (file)
 #define ANIM_EVENT_END         (1 << 5)
 #define ANIM_EVENT_POST                (1 << 6)
 #define ANIM_EVENT_UNCLICK_ANY (1 << 7)
+#define ANIM_EVENT_CE_CHANGE   (1 << 8)
 
-// event mask:  bits 0-7
-// anim number: bits 8-15
-// part number: bits 16-23
-#define ANIM_EVENT_ANIM_BIT    8
-#define ANIM_EVENT_PART_BIT    16
+// event mask:  bits 0-15
+// CE number:   bits 16-23
+// anim number: bits 16-23
+// part number: bits 24-31
+#define ANIM_EVENT_CE_BIT      16
+#define ANIM_EVENT_ANIM_BIT    16
+#define ANIM_EVENT_PART_BIT    24
 
+#define ANIM_EVENT_CE_MASK     (0xff << ANIM_EVENT_CE_BIT)
 #define ANIM_EVENT_ANIM_MASK   (0xff << ANIM_EVENT_ANIM_BIT)
 #define ANIM_EVENT_PART_MASK   (0xff << ANIM_EVENT_PART_BIT)
 
index dc4ea9ace501012d47b92aaf669ec47fa15ee25c..a32e32a6a283acfbfd9d25fcc2e76e67b0810ff4 100644 (file)
@@ -3591,6 +3591,8 @@ struct ElementInfo
 
   struct ElementGroupInfo *group;      // pointer to element group info
 
+  boolean has_anim_event;      // element can trigger global animation
+
   // ---------- internal values used at runtime when playing ----------
 
   boolean has_change_event[NUM_CHANGE_EVENTS];