rnd-20031208-1-src
[rocksndiamonds.git] / src / files.c
index f445f8ddd0f99294746c902594a20377b0bfecb4..b7d62ce76da659b01723a6b5ae4397b95566d63c 100644 (file)
@@ -1032,7 +1032,7 @@ static void LoadLevel_InitElements(struct LevelInfo *level, char *filename)
       int element = EL_CUSTOM_START + i;
 
       /* order of checking and copying events to be mapped is important */
-      for (j = CE_BY_OTHER_ACTION; j >= CE_BY_PLAYER; j--)
+      for (j = CE_BY_OTHER_ACTION; j >= CE_BY_PLAYER_OBSOLETE; j--)
       {
        if (HAS_CHANGE_EVENT(element, j - 2))
        {
@@ -1042,7 +1042,7 @@ static void LoadLevel_InitElements(struct LevelInfo *level, char *filename)
       }
 
       /* order of checking and copying events to be mapped is important */
-      for (j = CE_OTHER_GETS_COLLECTED; j >= CE_COLLISION; j--)
+      for (j = CE_OTHER_GETS_COLLECTED; j >= CE_COLLISION_ACTIVE; j--)
       {
        if (HAS_CHANGE_EVENT(element, j - 1))
        {
@@ -1058,11 +1058,11 @@ static void LoadLevel_InitElements(struct LevelInfo *level, char *filename)
   {
     int element = EL_CUSTOM_START + i;
 
-    if (HAS_CHANGE_EVENT(element, CE_BY_PLAYER) ||
-       HAS_CHANGE_EVENT(element, CE_BY_COLLISION))
+    if (HAS_CHANGE_EVENT(element, CE_BY_PLAYER_OBSOLETE) ||
+       HAS_CHANGE_EVENT(element, CE_BY_COLLISION_OBSOLETE))
     {
-      SET_CHANGE_EVENT(element, CE_BY_PLAYER, FALSE);
-      SET_CHANGE_EVENT(element, CE_BY_COLLISION, FALSE);
+      SET_CHANGE_EVENT(element, CE_BY_PLAYER_OBSOLETE, FALSE);
+      SET_CHANGE_EVENT(element, CE_BY_COLLISION_OBSOLETE, FALSE);
 
       SET_CHANGE_EVENT(element, CE_BY_DIRECT_ACTION, TRUE);
     }
@@ -2011,6 +2011,13 @@ void LoadTape(int level_nr)
   LoadTapeFromFilename(filename);
 }
 
+void LoadSolutionTape(int level_nr)
+{
+  char *filename = getSolutionTapeFilename(level_nr);
+
+  LoadTapeFromFilename(filename);
+}
+
 static void SaveTape_VERS(FILE *file, struct TapeInfo *tape)
 {
   putFileVersion(file, tape->file_version);
@@ -2762,23 +2769,6 @@ void LoadSpecialMenuDesignSettings()
   freeSetupFileHash(setup_file_hash);
 }
 
-static char *itoa(unsigned int i)
-{
-  static char *a = NULL;
-
-  if (a != NULL)
-    free(a);
-
-  if (i > 2147483647)  /* yes, this is a kludge */
-    i = 2147483647;
-
-  a = checked_malloc(10 + 1);
-
-  sprintf(a, "%d", i);
-
-  return a;
-}
-
 void LoadUserDefinedEditorElementList(int **elements, int *num_elements)
 {
   char *filename = getEditorSetupFilename();
@@ -2793,7 +2783,7 @@ void LoadUserDefinedEditorElementList(int **elements, int *num_elements)
   element_hash = newSetupFileHash();
 
   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
-    setHashEntry(element_hash, element_info[i].token_name, itoa(i));
+    setHashEntry(element_hash, element_info[i].token_name, i_to_a(i));
 
   /* determined size may be larger than needed (due to unknown elements) */
   *num_elements = 0;
@@ -2846,12 +2836,12 @@ void LoadUserDefinedEditorElementList(int **elements, int *num_elements)
 #endif
 }
 
-static struct MusicFileInfo *get_music_file_info(char *basename)
+static struct MusicFileInfo *get_music_file_info_ext(char *basename, int music,
+                                                    boolean is_sound)
 {
   SetupFileHash *setup_file_hash = NULL;
   struct MusicFileInfo tmp_music_file_info, *new_music_file_info;
-  char *filename_music = getCustomMusicFilename(basename);
-  char *filename_prefix, *filename_info;
+  char *filename_music, *filename_prefix, *filename_info;
   struct
   {
     char *token;
@@ -2859,15 +2849,23 @@ static struct MusicFileInfo *get_music_file_info(char *basename)
   }
   token_to_value_ptr[] =
   {
-    { "context",       &tmp_music_file_info.context    },
-    { "title",         &tmp_music_file_info.title      },
-    { "artist",                &tmp_music_file_info.artist     },
-    { "album",         &tmp_music_file_info.album      },
-    { "year",          &tmp_music_file_info.year       },
-    { NULL,            NULL                            },
+    { "title_header",  &tmp_music_file_info.title_header       },
+    { "artist_header", &tmp_music_file_info.artist_header      },
+    { "album_header",  &tmp_music_file_info.album_header       },
+    { "year_header",   &tmp_music_file_info.year_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               },
+
+    { NULL,            NULL                                    },
   };
   int i;
 
+  filename_music = (is_sound ? getCustomSoundFilename(basename) :
+                   getCustomMusicFilename(basename));
+
   if (filename_music == NULL)
     return NULL;
 
@@ -2911,26 +2909,65 @@ static struct MusicFileInfo *get_music_file_info(char *basename)
 
   /* ---------- music file info found ---------- */
 
+  memset(&tmp_music_file_info, 0, sizeof(struct MusicFileInfo));
+
   for (i = 0; token_to_value_ptr[i].token != NULL; i++)
   {
     char *value = getHashEntry(setup_file_hash, token_to_value_ptr[i].token);
 
-    *token_to_value_ptr[i].value_ptr = getStringCopy(value);  /* may be NULL */
+    *token_to_value_ptr[i].value_ptr =
+      getStringCopy(value != NULL ? value : UNKNOWN_NAME);
   }
 
-  new_music_file_info = checked_calloc(sizeof(struct MusicFileInfo));
+  tmp_music_file_info.basename = basename;
+  tmp_music_file_info.music = music;
+  tmp_music_file_info.is_sound = is_sound;
+
+  new_music_file_info = checked_malloc(sizeof(struct MusicFileInfo));
   *new_music_file_info = tmp_music_file_info;
 
   return new_music_file_info;
 }
 
+static struct MusicFileInfo *get_music_file_info(char *basename, int music)
+{
+  return get_music_file_info_ext(basename, music, FALSE);
+}
+
+static struct MusicFileInfo *get_sound_file_info(char *basename, int sound)
+{
+  return get_music_file_info_ext(basename, sound, TRUE);
+}
+
+static boolean music_info_listed_ext(struct MusicFileInfo *list,
+                                    char *basename, boolean is_sound)
+{
+  for (; list != NULL; list = list->next)
+    if (list->is_sound == is_sound && strcmp(list->basename, basename) == 0)
+      return TRUE;
+
+  return FALSE;
+}
+
+static boolean music_info_listed(struct MusicFileInfo *list, char *basename)
+{
+  return music_info_listed_ext(list, basename, FALSE);
+}
+
+static boolean sound_info_listed(struct MusicFileInfo *list, char *basename)
+{
+  return music_info_listed_ext(list, basename, TRUE);
+}
+
 void LoadMusicInfo()
 {
   char *music_directory = getCustomMusicDirectory();
   int num_music = getMusicListSize();
+  int num_music_noconf = 0;
+  int num_sounds = getSoundListSize();
   DIR *dir;
   struct dirent *dir_entry;
-  struct FileInfo *music;
+  struct FileInfo *music, *sound;
   struct MusicFileInfo *next, **new;
   int i;
 
@@ -2938,8 +2975,15 @@ void LoadMusicInfo()
   {
     next = music_file_info->next;
 
-    if (music_file_info->context)
-      free(music_file_info->context);
+    if (music_file_info->title_header)
+      free(music_file_info->title_header);
+    if (music_file_info->artist_header)
+      free(music_file_info->artist_header);
+    if (music_file_info->album_header)
+      free(music_file_info->album_header);
+    if (music_file_info->year_header)
+      free(music_file_info->year_header);
+
     if (music_file_info->title)
       free(music_file_info->title);
     if (music_file_info->artist)
@@ -2956,20 +3000,38 @@ void LoadMusicInfo()
 
   new = &music_file_info;
 
+#if 0
+  printf("::: num_music == %d\n", num_music);
+#endif
+
   for (i = 0; i < num_music; i++)
   {
     music = getMusicListEntry(i);
 
+#if 0
+    printf("::: %d [%08x]\n", i, music->filename);
+#endif
+
+    if (music->filename == NULL)
+      continue;
+
     if (strcmp(music->filename, UNDEFINED_FILENAME) == 0)
       continue;
 
+    /* a configured file may be not recognized as music */
+    if (!FileIsMusic(music->filename))
+      continue;
+
 #if 0
-    printf("::: -> '%s'\n", music->filename);
+    printf("::: -> '%s' (configured)\n", music->filename);
 #endif
 
-    *new = get_music_file_info(music->filename);
-    if (*new != NULL)
-      new = &(*new)->next;
+    if (!music_info_listed(music_file_info, music->filename))
+    {
+      *new = get_music_file_info(music->filename, i);
+      if (*new != NULL)
+       new = &(*new)->next;
+    }
   }
 
   if ((dir = opendir(music_directory)) == NULL)
@@ -2988,6 +3050,9 @@ void LoadMusicInfo()
     {
       music = getMusicListEntry(i);
 
+      if (music->filename == NULL)
+       continue;
+
       if (strcmp(basename, music->filename) == 0)
       {
        music_already_used = TRUE;
@@ -2998,20 +3063,51 @@ void LoadMusicInfo()
     if (music_already_used)
       continue;
 
-    if (!FileIsSound(basename) && !FileIsMusic(basename))
+    if (!FileIsMusic(basename))
       continue;
 
 #if 0
-    printf("::: -> '%s'\n", basename);
+    printf("::: -> '%s' (found in directory)\n", basename);
 #endif
 
-    *new = get_music_file_info(basename);
-    if (*new != NULL)
-      new = &(*new)->next;
+    if (!music_info_listed(music_file_info, basename))
+    {
+      *new = get_music_file_info(basename, MAP_NOCONF_MUSIC(num_music_noconf));
+      if (*new != NULL)
+       new = &(*new)->next;
+    }
+
+    num_music_noconf++;
   }
 
   closedir(dir);
 
+  for (i = 0; i < num_sounds; i++)
+  {
+    sound = getSoundListEntry(i);
+
+    if (sound->filename == NULL)
+      continue;
+
+    if (strcmp(sound->filename, UNDEFINED_FILENAME) == 0)
+      continue;
+
+    /* a configured file may be not recognized as sound */
+    if (!FileIsSound(sound->filename))
+      continue;
+
+#if 0
+    printf("::: -> '%s' (configured)\n", sound->filename);
+#endif
+
+    if (!sound_info_listed(music_file_info, sound->filename))
+    {
+      *new = get_sound_file_info(sound->filename, i);
+      if (*new != NULL)
+       new = &(*new)->next;
+    }
+  }
+
 #if 0
   /* TEST-ONLY */
   for (next = music_file_info; next != NULL; next = next->next)
@@ -3057,13 +3153,16 @@ void print_unknown_token_end(int token_nr)
 void LoadHelpAnimInfo()
 {
   char *filename = getHelpAnimFilename();
-  SetupFileList *setup_file_list, *list;
+  SetupFileList *setup_file_list = NULL, *list;
   SetupFileHash *element_hash, *action_hash, *direction_hash;
   int num_list_entries = 0;
   int num_unknown_tokens = 0;
   int i;
 
-  if ((setup_file_list = loadSetupFileList(filename)) == NULL)
+  if (fileExists(filename))
+    setup_file_list = loadSetupFileList(filename);
+
+  if (setup_file_list == NULL)
   {
     /* use reliable default values from static configuration */
     SetupFileList *insert_ptr;
@@ -3083,16 +3182,16 @@ void LoadHelpAnimInfo()
   direction_hash = newSetupFileHash();
 
   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
-    setHashEntry(element_hash, element_info[i].token_name, itoa(i));
+    setHashEntry(element_hash, element_info[i].token_name, i_to_a(i));
 
   for (i = 0; i < NUM_ACTIONS; i++)
     setHashEntry(action_hash, element_action_info[i].suffix,
-                itoa(element_action_info[i].value));
+                i_to_a(element_action_info[i].value));
 
   /* do not store direction index (bit) here, but direction value! */
   for (i = 0; i < NUM_DIRECTIONS; i++)
     setHashEntry(direction_hash, element_direction_info[i].suffix,
-                itoa(1 << element_direction_info[i].value));
+                i_to_a(1 << element_direction_info[i].value));
 
   for (list = setup_file_list; list != NULL; list = list->next)
   {
@@ -3107,35 +3206,44 @@ void LoadHelpAnimInfo()
       continue;
     }
 
-    element_token = list->token;
-    element_value = getHashEntry(element_hash, element_token);
+    /* first try to break element into element/action/direction parts;
+       if this does not work, also accept combined "element[.act][.dir]"
+       elements (like "dynamite.active"), which are unique elements */
 
-    if (element_value != NULL)
+    if (strchr(list->token, '.') == NULL)      /* token contains no '.' */
     {
-      /* element found */
-      add_helpanim_entry(atoi(element_value), -1, -1, delay,&num_list_entries);
+      element_value = getHashEntry(element_hash, list->token);
+      if (element_value != NULL)       /* element found */
+       add_helpanim_entry(atoi(element_value), -1, -1, delay,
+                          &num_list_entries);
+      else
+      {
+       /* no further suffixes found -- this is not an element */
+       print_unknown_token(filename, list->token, num_unknown_tokens++);
+      }
 
       continue;
     }
 
-    if (strchr(element_token, '.') == NULL)
-    {
-      /* no further suffixes found -- this is not an element */
-      print_unknown_token(filename, list->token, num_unknown_tokens++);
+    /* token has format "<prefix>.<something>" */
 
-      continue;
-    }
+    action_token = strchr(list->token, '.');   /* suffix may be action ... */
+    direction_token = action_token;            /* ... or direction */
 
-    action_token = strchr(element_token, '.');
-    element_token = getStringCopy(element_token);
+    element_token = getStringCopy(list->token);
     *strchr(element_token, '.') = '\0';
 
     element_value = getHashEntry(element_hash, element_token);
 
-    if (element_value == NULL)
+    if (element_value == NULL)         /* this is no element */
     {
-      /* this is not an element */
-      print_unknown_token(filename, list->token, num_unknown_tokens++);
+      element_value = getHashEntry(element_hash, list->token);
+      if (element_value != NULL)       /* combined element found */
+       add_helpanim_entry(atoi(element_value), -1, -1, delay,
+                          &num_list_entries);
+      else
+       print_unknown_token(filename, list->token, num_unknown_tokens++);
+
       free(element_token);
 
       continue;
@@ -3143,24 +3251,23 @@ void LoadHelpAnimInfo()
 
     action_value = getHashEntry(action_hash, action_token);
 
-    if (action_value != NULL)
+    if (action_value != NULL)          /* action found */
     {
-      /* action found */
       add_helpanim_entry(atoi(element_value), atoi(action_value), -1, delay,
                    &num_list_entries);
+
       free(element_token);
 
       continue;
     }
 
-    direction_token = action_token;
     direction_value = getHashEntry(direction_hash, direction_token);
 
-    if (direction_value != NULL)
+    if (direction_value != NULL)       /* direction found */
     {
-      /* direction found */
       add_helpanim_entry(atoi(element_value), -1, atoi(direction_value), delay,
                         &num_list_entries);
+
       free(element_token);
 
       continue;
@@ -3168,23 +3275,38 @@ void LoadHelpAnimInfo()
 
     if (strchr(action_token + 1, '.') == NULL)
     {
-      /* no further suffixes found -- this is not an action or direction */
-      print_unknown_token(filename, list->token, num_unknown_tokens++);
+      /* no further suffixes found -- this is not an action nor direction */
+
+      element_value = getHashEntry(element_hash, list->token);
+      if (element_value != NULL)       /* combined element found */
+       add_helpanim_entry(atoi(element_value), -1, -1, delay,
+                          &num_list_entries);
+      else
+       print_unknown_token(filename, list->token, num_unknown_tokens++);
+
       free(element_token);
 
       continue;
     }
 
+    /* token has format "<prefix>.<suffix>.<something>" */
+
     direction_token = strchr(action_token + 1, '.');
+
     action_token = getStringCopy(action_token);
     *strchr(action_token + 1, '.') = '\0';
 
     action_value = getHashEntry(action_hash, action_token);
 
-    if (action_value == NULL)
+    if (action_value == NULL)          /* this is no action */
     {
-      /* this is not an action */
-      print_unknown_token(filename, list->token, num_unknown_tokens++);
+      element_value = getHashEntry(element_hash, list->token);
+      if (element_value != NULL)       /* combined element found */
+       add_helpanim_entry(atoi(element_value), -1, -1, delay,
+                          &num_list_entries);
+      else
+       print_unknown_token(filename, list->token, num_unknown_tokens++);
+
       free(element_token);
       free(action_token);
 
@@ -3193,18 +3315,25 @@ void LoadHelpAnimInfo()
 
     direction_value = getHashEntry(direction_hash, direction_token);
 
-    if (direction_value != NULL)
+    if (direction_value != NULL)       /* direction found */
     {
-      /* direction found */
       add_helpanim_entry(atoi(element_value), atoi(action_value),
                         atoi(direction_value), delay, &num_list_entries);
+
       free(element_token);
       free(action_token);
 
       continue;
     }
 
-    print_unknown_token(filename, list->token, num_unknown_tokens++);
+    /* this is no direction */
+
+    element_value = getHashEntry(element_hash, list->token);
+    if (element_value != NULL)         /* combined element found */
+      add_helpanim_entry(atoi(element_value), -1, -1, delay,
+                        &num_list_entries);
+    else
+      print_unknown_token(filename, list->token, num_unknown_tokens++);
 
     free(element_token);
     free(action_token);
@@ -3212,7 +3341,8 @@ void LoadHelpAnimInfo()
 
   print_unknown_token_end(num_unknown_tokens);
 
-  add_helpanim_entry(HELPANIM_LIST_END, -1, -1, -1, &num_list_entries);
+  add_helpanim_entry(HELPANIM_LIST_NEXT, -1, -1, -1, &num_list_entries);
+  add_helpanim_entry(HELPANIM_LIST_END,  -1, -1, -1, &num_list_entries);
 
   freeSetupFileList(setup_file_list);
   freeSetupFileHash(element_hash);
@@ -3236,9 +3366,15 @@ void LoadHelpTextInfo()
   int i;
 
   if (helptext_info != NULL)
+  {
     freeSetupFileHash(helptext_info);
+    helptext_info = NULL;
+  }
+
+  if (fileExists(filename))
+    helptext_info = loadSetupFileHash(filename);
 
-  if ((helptext_info = loadSetupFileHash(filename)) == NULL)
+  if (helptext_info == NULL)
   {
     /* use reliable default values from static configuration */
     helptext_info = newSetupFileHash();