added support for custom elements triggering global animations
[rocksndiamonds.git] / src / files.c
index ee42c99071149d56b57ac3293f64ed5b28032cfa..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
@@ -12345,6 +12406,45 @@ static void InitMenuDesignSettings_SpecialPostProcessing_AfterGraphics(void)
   }
 }
 
+static void InitMenuDesignSettings_PreviewPlayers_Ext(SetupFileHash *hash,
+                                                      boolean initialize)
+{
+  // special case: check if network and preview player positions are redefined,
+  // to compare this later against the main menu level preview being redefined
+  struct TokenIntPtrInfo menu_config_players[] =
+  {
+    { "main.network_players.x",        &menu.main.network_players.redefined    },
+    { "main.network_players.y",        &menu.main.network_players.redefined    },
+    { "main.preview_players.x",        &menu.main.preview_players.redefined    },
+    { "main.preview_players.y",        &menu.main.preview_players.redefined    },
+    { "preview.x",             &preview.redefined                      },
+    { "preview.y",             &preview.redefined                      }
+  };
+  int i;
+
+  if (initialize)
+  {
+    for (i = 0; i < ARRAY_SIZE(menu_config_players); i++)
+      *menu_config_players[i].value = FALSE;
+  }
+  else
+  {
+    for (i = 0; i < ARRAY_SIZE(menu_config_players); i++)
+      if (getHashEntry(hash, menu_config_players[i].token) != NULL)
+        *menu_config_players[i].value = TRUE;
+  }
+}
+
+static void InitMenuDesignSettings_PreviewPlayers(void)
+{
+  InitMenuDesignSettings_PreviewPlayers_Ext(NULL, TRUE);
+}
+
+static void InitMenuDesignSettings_PreviewPlayers_FromHash(SetupFileHash *hash)
+{
+  InitMenuDesignSettings_PreviewPlayers_Ext(hash, FALSE);
+}
+
 static void LoadMenuDesignSettingsFromFilename(char *filename)
 {
   static struct TitleFadingInfo tfi;
@@ -12686,28 +12786,12 @@ static void LoadMenuDesignSettingsFromFilename(char *filename)
     }
   }
 
-  // special case: check if network and preview player positions are redefined,
-  // to compare this later against the main menu level preview being redefined
-  struct TokenIntPtrInfo menu_config_players[] =
-  {
-    { "main.network_players.x",        &menu.main.network_players.redefined    },
-    { "main.network_players.y",        &menu.main.network_players.redefined    },
-    { "main.preview_players.x",        &menu.main.preview_players.redefined    },
-    { "main.preview_players.y",        &menu.main.preview_players.redefined    },
-    { "preview.x",             &preview.redefined                      },
-    { "preview.y",             &preview.redefined                      }
-  };
-
-  for (i = 0; i < ARRAY_SIZE(menu_config_players); i++)
-    *menu_config_players[i].value = FALSE;
-
-  for (i = 0; i < ARRAY_SIZE(menu_config_players); i++)
-    if (getHashEntry(setup_file_hash, menu_config_players[i].token) != NULL)
-      *menu_config_players[i].value = TRUE;
-
   // read (and overwrite with) values that may be specified in config file
   InitMenuDesignSettings_FromHash(setup_file_hash, TRUE);
 
+  // special case: check if network and preview player positions are redefined
+  InitMenuDesignSettings_PreviewPlayers_FromHash(setup_file_hash);
+
   freeSetupFileHash(setup_file_hash);
 }
 
@@ -12717,6 +12801,7 @@ void LoadMenuDesignSettings(void)
 
   InitMenuDesignSettings_Static();
   InitMenuDesignSettings_SpecialPreProcessing();
+  InitMenuDesignSettings_PreviewPlayers();
 
   if (!GFX_OVERRIDE_ARTWORK(ARTWORK_TYPE_GRAPHICS))
   {
@@ -12839,11 +12924,13 @@ static struct MusicFileInfo *get_music_file_info_ext(char *basename, int music,
     { "artist_header", &tmp_music_file_info.artist_header      },
     { "album_header",  &tmp_music_file_info.album_header       },
     { "year_header",   &tmp_music_file_info.year_header        },
+    { "played_header", &tmp_music_file_info.played_header      },
 
     { "title",         &tmp_music_file_info.title              },
     { "artist",                &tmp_music_file_info.artist             },
     { "album",         &tmp_music_file_info.album              },
     { "year",          &tmp_music_file_info.year               },
+    { "played",                &tmp_music_file_info.played             },
 
     { NULL,            NULL                                    },
   };
@@ -12937,24 +13024,14 @@ static boolean sound_info_listed(struct MusicFileInfo *list, char *basename)
   return music_info_listed_ext(list, basename, TRUE);
 }
 
-static boolean checkLevelSetHasMusic_NoConf(void)
-{
-  int i;
-
-  for (i = leveldir_current->first_level;
-       i <= leveldir_current->last_level; i++)
-    if (levelset.music[i] == MUS_UNDEFINED)
-      return TRUE;
-
-  return FALSE;
-}
-
 void LoadMusicInfo(void)
 {
+  int num_music_noconf = getMusicListSize_NoConf();
   int num_music = getMusicListSize();
   int num_sounds = getSoundListSize();
   struct FileInfo *music, *sound;
   struct MusicFileInfo *next, **new;
+
   int i;
 
   while (music_file_info != NULL)
@@ -12967,11 +13044,13 @@ void LoadMusicInfo(void)
     checked_free(music_file_info->artist_header);
     checked_free(music_file_info->album_header);
     checked_free(music_file_info->year_header);
+    checked_free(music_file_info->played_header);
 
     checked_free(music_file_info->title);
     checked_free(music_file_info->artist);
     checked_free(music_file_info->album);
     checked_free(music_file_info->year);
+    checked_free(music_file_info->played);
 
     free(music_file_info);
 
@@ -12980,7 +13059,44 @@ void LoadMusicInfo(void)
 
   new = &music_file_info;
 
-  // get music file info for all configured music files
+  // get (configured or unconfigured) music file info for all levels
+  for (i = leveldir_current->first_level;
+       i <= leveldir_current->last_level; i++)
+  {
+    int music_nr;
+
+    if (levelset.music[i] != MUS_UNDEFINED)
+    {
+      // get music file info for configured level music
+      music_nr = levelset.music[i];
+    }
+    else if (num_music_noconf > 0)
+    {
+      // get music file info for unconfigured level music
+      int level_pos = i - leveldir_current->first_level;
+
+      music_nr = MAP_NOCONF_MUSIC(level_pos % num_music_noconf);
+    }
+    else
+    {
+      continue;
+    }
+
+    char *basename = getMusicInfoEntryFilename(music_nr);
+
+    if (basename == NULL)
+      continue;
+
+    if (!music_info_listed(music_file_info, basename))
+    {
+      *new = get_music_file_info(basename, music_nr);
+
+      if (*new != NULL)
+       new = &(*new)->next;
+    }
+  }
+
+  // get music file info for all remaining configured music files
   for (i = 0; i < num_music; i++)
   {
     music = getMusicListEntry(i);
@@ -13004,30 +13120,6 @@ void LoadMusicInfo(void)
     }
   }
 
-  // if some levels have no game music configured, use unconfigured music
-  if (checkLevelSetHasMusic_NoConf())
-  {
-    int num_music_noconf = getMusicListSize_NoConf();
-
-    // get music file info for all unconfigured music files
-    for (i = 0; i < num_music_noconf; i++)
-    {
-      int music_nr_noconf = MAP_NOCONF_MUSIC(i);
-      char *basename = getMusicInfoEntryFilename(music_nr_noconf);
-
-      if (basename == NULL)
-       continue;
-
-      if (!music_info_listed(music_file_info, basename))
-      {
-       *new = get_music_file_info(basename, music_nr_noconf);
-
-       if (*new != NULL)
-         new = &(*new)->next;
-      }
-    }
-  }
-
   // get sound file info for all configured sound files
   for (i = 0; i < num_sounds; i++)
   {