added program config file support for run-time special edition support
authorHolger Schemel <info@artsoft.org>
Mon, 13 Apr 2015 23:50:33 +0000 (01:50 +0200)
committerHolger Schemel <info@artsoft.org>
Tue, 14 Apr 2015 18:08:31 +0000 (20:08 +0200)
14 files changed:
ChangeLog
src/config.c
src/config.h
src/files.c
src/files.h
src/init.c
src/libgame/misc.c
src/libgame/setup.c
src/libgame/setup.h
src/libgame/system.c
src/libgame/system.h
src/main.c
src/main.h
src/screens.c

index 0a7168dc2e23d8bdaf881e1fce73acf98ff9f7e1..9c67528f4129d25a08a97cc17367ae1d0ebd55f1 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,52 @@
+2015-04-14
+       * added run-time "special edition" support;
+         this change is especially targeted to the "R'n'D jue" special edition
+         of R'n'D, which changed some defaults at compile-time in previous
+         versions, like:
+         - using a different default artwork set (with fallback artwork for
+           classic artwork not existing in the special edition),
+         - using a different default level set,
+         - using a different program name and user data directory,
+         - starting with different default setup values and
+         - using custom artwork even at a very early stage of startup
+           (like initial fonts and initial loading/busy animation);
+         these changes can now all be accomplished at run-time by using a new
+         program-specific configuration file in the same location and with the
+         same name as the game binary (minus a potential binary file extension
+         ".exe", plus a configuration file extension ".conf", so a binary file
+         "rnd_jue.exe" would be complemented by a new file "rnd_jue.conf" in
+         the same directory);
+         this config file can contain all options found in "setup.conf" plus
+         the following new, internal "special edition" default settings:
+         - program_title (like "R'n'D jue")
+         - program_author (like "Juergen Bonhagen")
+         - program_email (like "jue@artsoft.org")
+         - program_website (like "http://jue.artsoft.org/")
+         - program_copyright (like "(c) 2015 by jue")
+         - program_company (like "A game by jue")
+         - default_graphics_set (like "jue0")
+         - default_sounds_set (like "jue0")
+         - default_music_set (like "jue0")
+         - fallback_graphics_file (like "fallback.png")
+         - fallback_sounds_file (like "fallback.wav")
+         - fallback_music_file (like "fallback.wav")
+         - default_level_series (like "jue_start")
+         - choose_from_top_leveldir ("true" or "false")
+         where the "default" artwork set definitions are used to specify new
+         default artwork that replaces the "classic" artwork sets, while the
+         "fallback" settings specify artwork files used for all artwork files
+         that would exist in the classic artwork sets, but are not defined or
+         cannot be found in the new default artwork set; the program title is
+         used for things like window title, title screens and user data folder
+         name, and the entry point for choosing a level set can be changed
+         from the current level set location to the topmost level tree node
+
+2015-04-07
+       * added sound definitions for pressing and releasing main menu buttons
+
+2015-03-31
+       * fixed slow tape quick-loading due to unneeded tape area update
+
 2015-03-30
        * replaced stop/play buttons in game panel with save/load buttons
 
index da6d1a9613da12434bbf0f727ba29f52c22d3a7e..3b75f709207583ab77737813336b30282ff315ec 100644 (file)
@@ -20,6 +20,11 @@ char *getCompileDateString()
   return COMPILE_DATE_STRING;
 }
 
+char *getProgramTitleString()
+{
+  return program.program_title;
+}
+
 char *getProgramVersionString()
 {
   static char program_version_string[32];
@@ -37,11 +42,11 @@ char *getProgramInitString()
 
   if (program_init_string == NULL)
   {
-    program_init_string = checked_malloc(strlen(PROGRAM_TITLE_STRING) + 1 +
+    program_init_string = checked_malloc(strlen(getProgramTitleString()) + 1 +
                                         strlen(getProgramVersionString()) + 1);
 
     sprintf(program_init_string, "%s %s",
-           PROGRAM_TITLE_STRING, getProgramVersionString());
+           getProgramTitleString(), getProgramVersionString());
   }
 
   return program_init_string;
index 48641ab12f74a603f9b3d3813d30120ec6aa9c8a..f632036017a270e5d3e081394a729344b8ed9e03 100644 (file)
@@ -15,8 +15,7 @@
 #include "main.h"
 
 char *getCompileDateString(void);
-char *getProgramReleaseVersionString(void);
-char *getProgramFullVersionString(void);
+char *getProgramTitleString(void);
 char *getProgramVersionString(void);
 char *getProgramInitString(void);
 char *getWindowTitleString(void);
index 4dab81954d6e630fb6686dba0294531ad7efe0dc..62bab2023a81ae4acb279af213678824a6d0dec6 100644 (file)
@@ -8021,6 +8021,24 @@ void SaveScore(int nr)
 
 #define NUM_SYSTEM_SETUP_TOKENS                        3
 
+/* internal setup */
+#define SETUP_TOKEN_INT_PROGRAM_TITLE          0
+#define SETUP_TOKEN_INT_PROGRAM_AUTHOR         1
+#define SETUP_TOKEN_INT_PROGRAM_EMAIL          2
+#define SETUP_TOKEN_INT_PROGRAM_WEBSITE                3
+#define SETUP_TOKEN_INT_PROGRAM_COPYRIGHT      4
+#define SETUP_TOKEN_INT_PROGRAM_COMPANY                5
+#define SETUP_TOKEN_INT_DEFAULT_GRAPHICS_SET   6
+#define SETUP_TOKEN_INT_DEFAULT_SOUNDS_SET     7
+#define SETUP_TOKEN_INT_DEFAULT_MUSIC_SET      8
+#define SETUP_TOKEN_INT_FALLBACK_GRAPHICS_FILE 9
+#define SETUP_TOKEN_INT_FALLBACK_SOUNDS_FILE   10
+#define SETUP_TOKEN_INT_FALLBACK_MUSIC_FILE    11
+#define SETUP_TOKEN_INT_DEFAULT_LEVEL_SERIES   12
+#define SETUP_TOKEN_INT_CHOOSE_FROM_TOP_LEVELDIR 13
+
+#define NUM_INTERNAL_SETUP_TOKENS              14
+
 /* options setup */
 #define SETUP_TOKEN_OPTIONS_VERBOSE            0
 
@@ -8033,6 +8051,7 @@ static struct SetupEditorCascadeInfo seci;
 static struct SetupShortcutInfo ssi;
 static struct SetupInputInfo sii;
 static struct SetupSystemInfo syi;
+static struct SetupInternalInfo sxi;
 static struct OptionInfo soi;
 
 static struct TokenInfo global_setup_tokens[] =
@@ -8168,11 +8187,29 @@ static struct TokenInfo player_setup_tokens[] =
 
 static struct TokenInfo system_setup_tokens[] =
 {
-  { TYPE_STRING,  &syi.sdl_videodriver,        "system.sdl_videodriver"        },
-  { TYPE_STRING,  &syi.sdl_audiodriver,        "system.sdl_audiodriver"        },
+  { TYPE_STRING,  &syi.sdl_videodriver,    "system.sdl_videodriver"    },
+  { TYPE_STRING,  &syi.sdl_audiodriver,           "system.sdl_audiodriver"     },
   { TYPE_INTEGER, &syi.audio_fragment_size,"system.audio_fragment_size"        },
 };
 
+static struct TokenInfo internal_setup_tokens[] =
+{
+  { TYPE_STRING, &sxi.program_title,           "program_title"         },
+  { TYPE_STRING, &sxi.program_author,          "program_author"        },
+  { TYPE_STRING, &sxi.program_email,           "program_email"         },
+  { TYPE_STRING, &sxi.program_website,         "program_website"       },
+  { TYPE_STRING, &sxi.program_copyright,       "program_copyright"     },
+  { TYPE_STRING, &sxi.program_company,         "program_company"       },
+  { TYPE_STRING, &sxi.default_graphics_set,    "default_graphics_set"  },
+  { TYPE_STRING, &sxi.default_sounds_set,      "default_sounds_set"    },
+  { TYPE_STRING, &sxi.default_music_set,       "default_music_set"     },
+  { TYPE_STRING, &sxi.fallback_graphics_file,  "fallback_graphics_file"},
+  { TYPE_STRING, &sxi.fallback_sounds_file,    "fallback_sounds_file"  },
+  { TYPE_STRING, &sxi.fallback_music_file,     "fallback_music_file"   },
+  { TYPE_STRING, &sxi.default_level_series,    "default_level_series"  },
+  { TYPE_STRING, &sxi.choose_from_top_leveldir,        "choose_from_top_leveldir" },
+};
+
 static struct TokenInfo options_setup_tokens[] =
 {
   { TYPE_BOOLEAN, &soi.verbose,                "options.verbose"               },
@@ -8229,9 +8266,10 @@ static void setSetupInfoToDefaults(struct SetupInfo *si)
   si->sp_show_border_elements = FALSE;
   si->small_game_graphics = FALSE;
 
-  si->graphics_set = getStringCopy(GFX_DEFAULT_SUBDIR);
-  si->sounds_set = getStringCopy(SND_DEFAULT_SUBDIR);
-  si->music_set = getStringCopy(MUS_DEFAULT_SUBDIR);
+  si->graphics_set = getStringCopy(GFX_CLASSIC_SUBDIR);
+  si->sounds_set   = getStringCopy(SND_CLASSIC_SUBDIR);
+  si->music_set    = getStringCopy(MUS_CLASSIC_SUBDIR);
+
   si->override_level_graphics = FALSE;
   si->override_level_sounds = FALSE;
   si->override_level_music = FALSE;
@@ -8312,16 +8350,25 @@ static void setSetupInfoToDefaults(struct SetupInfo *si)
   si->system.sdl_audiodriver = getStringCopy(ARG_DEFAULT);
   si->system.audio_fragment_size = DEFAULT_AUDIO_FRAGMENT_SIZE;
 
-  si->options.verbose = FALSE;
+  si->internal.program_title     = getStringCopy(PROGRAM_TITLE_STRING);
+  si->internal.program_author    = getStringCopy(PROGRAM_AUTHOR_STRING);
+  si->internal.program_email     = getStringCopy(PROGRAM_EMAIL_STRING);
+  si->internal.program_website   = getStringCopy(PROGRAM_WEBSITE_STRING);
+  si->internal.program_copyright = getStringCopy(PROGRAM_COPYRIGHT_STRING);
+  si->internal.program_company   = getStringCopy(PROGRAM_COMPANY_STRING);
 
-#if defined(CREATE_SPECIAL_EDITION_RND_JUE)
-  si->toons = FALSE;
-  si->handicap = FALSE;
-  si->fullscreen = TRUE;
-  si->override_level_graphics = AUTO;
-  si->override_level_sounds = AUTO;
-  si->override_level_music = AUTO;
-#endif
+  si->internal.default_graphics_set = getStringCopy(GFX_CLASSIC_SUBDIR);
+  si->internal.default_sounds_set   = getStringCopy(SND_CLASSIC_SUBDIR);
+  si->internal.default_music_set    = getStringCopy(MUS_CLASSIC_SUBDIR);
+
+  si->internal.fallback_graphics_file = getStringCopy(UNDEFINED_FILENAME);
+  si->internal.fallback_sounds_file   = getStringCopy(UNDEFINED_FILENAME);
+  si->internal.fallback_music_file    = getStringCopy(UNDEFINED_FILENAME);
+
+  si->internal.default_level_series = getStringCopy(UNDEFINED_LEVELSET);
+  si->internal.choose_from_top_leveldir = FALSE;
+
+  si->options.verbose = FALSE;
 
 #if defined(PLATFORM_ANDROID)
   si->fullscreen = TRUE;
@@ -8402,6 +8449,13 @@ static void decodeSetupFileHash(SetupFileHash *setup_file_hash)
                 getHashEntry(setup_file_hash, system_setup_tokens[i].text));
   setup.system = syi;
 
+  /* internal setup */
+  sxi = setup.internal;
+  for (i = 0; i < NUM_INTERNAL_SETUP_TOKENS; i++)
+    setSetupInfo(internal_setup_tokens, i,
+                getHashEntry(setup_file_hash, internal_setup_tokens[i].text));
+  setup.internal = sxi;
+
   /* options setup */
   soi = setup.options;
   for (i = 0; i < NUM_OPTIONS_SETUP_TOKENS; i++)
@@ -8426,42 +8480,62 @@ static void decodeSetupFileHash_EditorCascade(SetupFileHash *setup_file_hash)
   setup.editor_cascade = seci;
 }
 
-void LoadSetup()
+void LoadSetupFromFilename(char *filename)
 {
-  char *filename = getSetupFilename();
-  SetupFileHash *setup_file_hash = NULL;
-
-  /* always start with reliable default values */
-  setSetupInfoToDefaults(&setup);
-
-  setup_file_hash = loadSetupFileHash(filename);
+  SetupFileHash *setup_file_hash = loadSetupFileHash(filename);
 
   if (setup_file_hash)
   {
-    char *player_name_new;
-
     decodeSetupFileHash(setup_file_hash);
 
     freeSetupFileHash(setup_file_hash);
+  }
+  else
+  {
+    Error(ERR_WARN, "using default setup values");
+  }
+}
 
-    /* needed to work around problems with fixed length strings */
-    player_name_new = get_corrected_login_name(setup.player_name);
-    free(setup.player_name);
-    setup.player_name = player_name_new;
+static void LoadSetup_SpecialPostProcessing()
+{
+  char *player_name_new;
 
-    /* "scroll_delay: on(3) / off(0)" was replaced by scroll delay value */
-    if (setup.scroll_delay == FALSE)
-    {
-      setup.scroll_delay_value = MIN_SCROLL_DELAY;
-      setup.scroll_delay = TRUE;                       /* now always "on" */
-    }
+  /* needed to work around problems with fixed length strings */
+  player_name_new = get_corrected_login_name(setup.player_name);
+  free(setup.player_name);
+  setup.player_name = player_name_new;
 
-    /* make sure that scroll delay value stays inside valid range */
-    setup.scroll_delay_value =
-      MIN(MAX(MIN_SCROLL_DELAY, setup.scroll_delay_value), MAX_SCROLL_DELAY);
+  /* "scroll_delay: on(3) / off(0)" was replaced by scroll delay value */
+  if (setup.scroll_delay == FALSE)
+  {
+    setup.scroll_delay_value = MIN_SCROLL_DELAY;
+    setup.scroll_delay = TRUE;                 /* now always "on" */
   }
-  else
-    Error(ERR_WARN, "using default setup values");
+
+  /* make sure that scroll delay value stays inside valid range */
+  setup.scroll_delay_value =
+    MIN(MAX(MIN_SCROLL_DELAY, setup.scroll_delay_value), MAX_SCROLL_DELAY);
+}
+
+void LoadSetup()
+{
+  char *filename;
+
+  /* always start with reliable default values */
+  setSetupInfoToDefaults(&setup);
+
+  /* try to load setup values from default setup file */
+  filename = getDefaultSetupFilename();
+
+  if (fileExists(filename))
+    LoadSetupFromFilename(filename);
+
+  /* try to load setup values from user setup file */
+  filename = getSetupFilename();
+
+  LoadSetupFromFilename(filename);
+
+  LoadSetup_SpecialPostProcessing();
 }
 
 void LoadSetup_EditorCascade()
@@ -8545,6 +8619,9 @@ void SaveSetup()
   for (i = 0; i < NUM_SYSTEM_SETUP_TOKENS; i++)
     fprintf(file, "%s\n", getSetupLine(system_setup_tokens, "", i));
 
+  /* internal setup */
+  /* (internal setup values not saved to user setup file) */
+
   /* options setup */
   soi = setup.options;
   fprintf(file, "\n");
index 3041cc836b1d54045950e12a2b1ac1346c2ef9db..2a3900ebce1d65e7cadd1982e51996db89650f3f 100644 (file)
@@ -54,6 +54,7 @@ boolean SaveTapeChecked(int);
 void LoadScore(int);
 void SaveScore(int);
 
+void LoadSetupFromFilename(char *);
 void LoadSetup();
 void SaveSetup();
 
index b0ed61da0998f84cb9ba1e7a6032fd0b3e71dfda..e54a016b4542caf01148424f68d24eb5cf96f529 100644 (file)
@@ -5087,52 +5087,79 @@ void InitGfx()
   font_height = getFontHeight(FC_RED);
 
   DrawInitText(getProgramInitString(), 20, FC_YELLOW);
-  DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
-  DrawInitText(PROGRAM_WEBSITE_STRING, WIN_YSIZE - 20 - font_height, FC_RED);
+  DrawInitText(setup.internal.program_copyright, 50, FC_RED);
+  DrawInitText(setup.internal.program_website, WIN_YSIZE - 20 - font_height,
+              FC_RED);
 
   DrawInitText("Loading graphics", 120, FC_GREEN);
 
-  /* initialize busy animation with default values */
+  /* initialize settings for busy animation with default values */
   int parameter[NUM_GFX_ARGS];
   for (i = 0; i < NUM_GFX_ARGS; i++)
     parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
                                                image_config_suffix[i].token,
                                                image_config_suffix[i].type);
 
-  /* determine settings for busy animation (when displaying startup messages) */
-  for (i = 0; image_config[i].token != NULL; i++)
+  char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
+  int len_anim_token = strlen(anim_token);
+
+  /* read settings for busy animation from default custom artwork config */
+  char *gfx_config_filename = getPath3(options.graphics_directory,
+                                      GFX_DEFAULT_SUBDIR,
+                                      GRAPHICSINFO_FILENAME);
+
+  if (fileExists(gfx_config_filename))
   {
-    char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
-    int len_anim_token = strlen(anim_token);
+    SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
 
-    if (strEqual(image_config[i].token, anim_token))
-      filename_anim_initial = image_config[i].value;
-    else if (strlen(image_config[i].token) > len_anim_token &&
-            strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
+    if (setup_file_hash)
     {
-      for (j = 0; image_config_suffix[j].token != NULL; j++)
+      char *filename = getHashEntry(setup_file_hash, anim_token);
+
+      if (filename)
       {
-       if (strEqual(&image_config[i].token[len_anim_token],
-                    image_config_suffix[j].token))
-         parameter[j] =
-           get_graphic_parameter_value(image_config[i].value,
-                                       image_config_suffix[j].token,
-                                       image_config_suffix[j].type);
+       filename_anim_initial = getStringCopy(filename);
+
+       for (j = 0; image_config_suffix[j].token != NULL; j++)
+       {
+         int type = image_config_suffix[j].type;
+         char *suffix = image_config_suffix[j].token;
+         char *token = getStringCat2(anim_token, suffix);
+         char *value = getHashEntry(setup_file_hash, token);
+
+         checked_free(token);
+
+         if (value)
+           parameter[j] = get_graphic_parameter_value(value, suffix, type);
+       }
       }
+
+      freeSetupFileHash(setup_file_hash);
     }
   }
 
-#if defined(CREATE_SPECIAL_EDITION_RND_JUE)
-  filename_anim_initial = "loading.pcx";
-
-  parameter[GFX_ARG_X] = 0;
-  parameter[GFX_ARG_Y] = 0;
-  parameter[GFX_ARG_WIDTH] = 128;
-  parameter[GFX_ARG_HEIGHT] = 40;
-  parameter[GFX_ARG_FRAMES] = 32;
-  parameter[GFX_ARG_DELAY] = 4;
-  parameter[GFX_ARG_FRAMES_PER_LINE] = ARG_UNDEFINED_VALUE;
-#endif
+  if (filename_anim_initial == NULL)
+  {
+    /* read settings for busy animation from static default artwork config */
+    for (i = 0; image_config[i].token != NULL; i++)
+    {
+      if (strEqual(image_config[i].token, anim_token))
+       filename_anim_initial = getStringCopy(image_config[i].value);
+      else if (strlen(image_config[i].token) > len_anim_token &&
+              strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
+      {
+       for (j = 0; image_config_suffix[j].token != NULL; j++)
+       {
+         if (strEqual(&image_config[i].token[len_anim_token],
+                      image_config_suffix[j].token))
+           parameter[j] =
+             get_graphic_parameter_value(image_config[i].value,
+                                         image_config_suffix[j].token,
+                                         image_config_suffix[j].type);
+       }
+      }
+    }
+  }
 
   if (filename_anim_initial == NULL)   /* should not happen */
     Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
@@ -5143,6 +5170,8 @@ void InitGfx()
   anim_initial.bitmaps[IMG_BITMAP_STANDARD] =
     LoadCustomImage(filename_anim_initial);
 
+  checked_free(filename_anim_initial);
+
   graphic_info = &anim_initial;                /* graphic == 0 => anim_initial */
 
   set_graphic_parameters_ext(0, parameter, anim_initial.bitmaps);
index 052509f6f914e8afd9f25985d05f62ef70349a13..660f4df6a80ee83a2a4cfc9733514b1c126f5cf2 100644 (file)
@@ -1073,6 +1073,9 @@ void Error(int mode, char *format, ...)
   static boolean last_line_was_separator = FALSE;
   char *process_name = "";
 
+  if (program.error_file == NULL)
+    return;
+
 #if defined(PLATFORM_ANDROID)
   android_log_prio = (mode & ERR_DEBUG ? ANDROID_LOG_DEBUG :
                      mode & ERR_INFO ? ANDROID_LOG_INFO :
index 562152961c32009cb61133db36eeb424b1c0e160..5fc8ccc7953b15faec7cfb47423ec4d0399fc4d1 100644 (file)
@@ -393,6 +393,17 @@ inline static char *getLevelArtworkDir(int type)
   return LEVELDIR_ARTWORK_PATH(leveldir_current, type);
 }
 
+char *getProgramConfigFilename(char *command_filename_ptr)
+{
+  char *command_filename = getStringCopy(command_filename_ptr);
+
+  // strip trailing executable suffix from command filename
+  if (strSuffix(command_filename, ".exe"))
+    command_filename[strlen(command_filename) - 4] = '\0';
+
+  return getStringCat2(command_filename, ".conf");
+}
+
 char *getTapeFilename(int nr)
 {
   static char *filename = NULL;
@@ -456,6 +467,11 @@ char *getSetupFilename()
   return filename;
 }
 
+char *getDefaultSetupFilename()
+{
+  return program.config_filename;
+}
+
 char *getEditorSetupFilename()
 {
   static char *filename = NULL;
@@ -659,18 +675,20 @@ char *getCustomImageFilename(char *basename)
   if (fileExists(filename))
     return filename;
 
-#if defined(CREATE_SPECIAL_EDITION)
-  free(filename);
+  if (!strEqual(GFX_FALLBACK_FILENAME, UNDEFINED_FILENAME))
+  {
+    free(filename);
 
-  if (options.debug)
-    Error(ERR_WARN, "cannot find artwork file '%s' (using fallback)", basename);
+    if (options.debug)
+      Error(ERR_WARN, "cannot find artwork file '%s' (using fallback)",
+           basename);
 
-  /* 6th try: look for fallback artwork in old default artwork directory */
-  /* (needed to prevent errors when trying to access unused artwork files) */
-  filename = getImg2(options.graphics_directory, GFX_FALLBACK_FILENAME);
-  if (fileExists(filename))
-    return filename;
-#endif
+    /* 6th try: look for fallback artwork in old default artwork directory */
+    /* (needed to prevent errors when trying to access unused artwork files) */
+    filename = getImg2(options.graphics_directory, GFX_FALLBACK_FILENAME);
+    if (fileExists(filename))
+      return filename;
+  }
 
   return NULL;         /* cannot find specified artwork file anywhere */
 }
@@ -730,18 +748,20 @@ char *getCustomSoundFilename(char *basename)
   if (fileExists(filename))
     return filename;
 
-#if defined(CREATE_SPECIAL_EDITION)
-  free(filename);
+  if (!strEqual(SND_FALLBACK_FILENAME, UNDEFINED_FILENAME))
+  {
+    free(filename);
 
-  if (options.debug)
-    Error(ERR_WARN, "cannot find artwork file '%s' (using fallback)", basename);
+    if (options.debug)
+      Error(ERR_WARN, "cannot find artwork file '%s' (using fallback)",
+           basename);
 
-  /* 6th try: look for fallback artwork in old default artwork directory */
-  /* (needed to prevent errors when trying to access unused artwork files) */
-  filename = getPath2(options.sounds_directory, SND_FALLBACK_FILENAME);
-  if (fileExists(filename))
-    return filename;
-#endif
+    /* 6th try: look for fallback artwork in old default artwork directory */
+    /* (needed to prevent errors when trying to access unused artwork files) */
+    filename = getPath2(options.sounds_directory, SND_FALLBACK_FILENAME);
+    if (fileExists(filename))
+      return filename;
+  }
 
   return NULL;         /* cannot find specified artwork file anywhere */
 }
@@ -801,18 +821,20 @@ char *getCustomMusicFilename(char *basename)
   if (fileExists(filename))
     return filename;
 
-#if defined(CREATE_SPECIAL_EDITION)
-  free(filename);
+  if (!strEqual(MUS_FALLBACK_FILENAME, UNDEFINED_FILENAME))
+  {
+    free(filename);
 
-  if (options.debug)
-    Error(ERR_WARN, "cannot find artwork file '%s' (using fallback)", basename);
+    if (options.debug)
+      Error(ERR_WARN, "cannot find artwork file '%s' (using fallback)",
+           basename);
 
-  /* 6th try: look for fallback artwork in old default artwork directory */
-  /* (needed to prevent errors when trying to access unused artwork files) */
-  filename = getPath2(options.music_directory, MUS_FALLBACK_FILENAME);
-  if (fileExists(filename))
-    return filename;
-#endif
+    /* 6th try: look for fallback artwork in old default artwork directory */
+    /* (needed to prevent errors when trying to access unused artwork files) */
+    filename = getPath2(options.music_directory, MUS_FALLBACK_FILENAME);
+    if (fileExists(filename))
+      return filename;
+  }
 
   return NULL;         /* cannot find specified artwork file anywhere */
 }
@@ -3626,12 +3648,13 @@ void LoadLevelSetup_LastSeries()
   /* always start with reliable default values */
   leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
 
-#if defined(CREATE_SPECIAL_EDITION_RND_JUE)
-  leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
-                                              "jue_start");
-  if (leveldir_current == NULL)
-    leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
-#endif
+  if (!strEqual(DEFAULT_LEVELSET, UNDEFINED_LEVELSET))
+  {
+    leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
+                                                DEFAULT_LEVELSET);
+    if (leveldir_current == NULL)
+      leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
+  }
 
   if ((level_setup_hash = loadSetupFileHash(filename)))
   {
index c2f0692e9f83ffb4250f188c9adf177016938af2..1f3b7b8186de88f1de38b895f18f2e203ef8adbb 100644 (file)
@@ -222,10 +222,12 @@ typedef struct hashtable     SetupFileHash;
 
 
 char *setLevelArtworkDir(TreeInfo *);
+char *getProgramConfigFilename(char *);
 char *getTapeFilename(int);
 char *getSolutionTapeFilename(int);
 char *getScoreFilename(int);
 char *getSetupFilename(void);
+char *getDefaultSetupFilename(void);
 char *getEditorSetupFilename(void);
 char *getHelpAnimFilename(void);
 char *getHelpTextFilename(void);
index c04c77e5b40ea57947be26754ec3f2c088f683ac..9a0bed5a93e27442626a319da746fe613b655475 100644 (file)
@@ -64,7 +64,7 @@ int                   FrameCounter = 0;
 /* init/close functions                                                      */
 /* ========================================================================= */
 
-void InitProgramInfo(char *argv0,
+void InitProgramInfo(char *argv0, char *config_filename,
                     char *userdata_subdir, char *userdata_subdir_unix,
                     char *program_title, char *icon_title,
                     char *sdl_icon_filename, char *cookie_prefix,
@@ -73,6 +73,8 @@ void InitProgramInfo(char *argv0,
   program.command_basepath = getBasePath(argv0);
   program.command_basename = getBaseName(argv0);
 
+  program.config_filename = config_filename;
+
   program.userdata_subdir = userdata_subdir;
   program.userdata_subdir_unix = userdata_subdir_unix;
   program.userdata_path = getUserGameDataDir();
index eff5452583bbe16db554dbe8c49e7ab8707930de..d0a22f24ff030bc9d609626e9ea94782d69847ed 100644 (file)
 /* default value for undefined filename */
 #define UNDEFINED_FILENAME     "[NONE]"
 
+/* default value for undefined levelset */
+#define UNDEFINED_LEVELSET     "[NONE]"
+
 /* default value for undefined parameter */
 #define ARG_DEFAULT            "[DEFAULT]"
 
 #define SND_CLASSIC_SUBDIR     "snd_classic"
 #define MUS_CLASSIC_SUBDIR     "mus_classic"
 
-#if defined(CREATE_SPECIAL_EDITION_RND_JUE)
-#define GFX_DEFAULT_SUBDIR     "jue0"
-#define SND_DEFAULT_SUBDIR     "jue0"
-#define MUS_DEFAULT_SUBDIR     "jue0"
-#else
-#define GFX_DEFAULT_SUBDIR     GFX_CLASSIC_SUBDIR
-#define SND_DEFAULT_SUBDIR     SND_CLASSIC_SUBDIR
-#define MUS_DEFAULT_SUBDIR     MUS_CLASSIC_SUBDIR
-#endif
+#define GFX_DEFAULT_SUBDIR     (setup.internal.default_graphics_set)
+#define SND_DEFAULT_SUBDIR     (setup.internal.default_sounds_set)
+#define MUS_DEFAULT_SUBDIR     (setup.internal.default_music_set)
 
-#if defined(CREATE_SPECIAL_EDITION)
-#define GFX_FALLBACK_FILENAME  "fallback.pcx"
-#define SND_FALLBACK_FILENAME  "fallback.wav"
-#define MUS_FALLBACK_FILENAME  "fallback.wav"
-#endif
+#define GFX_FALLBACK_FILENAME  (setup.internal.fallback_graphics_file)
+#define SND_FALLBACK_FILENAME  (setup.internal.fallback_sounds_file)
+#define MUS_FALLBACK_FILENAME  (setup.internal.fallback_music_file)
+
+#define DEFAULT_LEVELSET       (setup.internal.default_level_series)
 
 /* file names and filename extensions */
 #define LEVELSETUP_DIRECTORY   "levelsetup"
@@ -664,6 +661,8 @@ struct ProgramInfo
   char *command_basepath;      /* path to the program binary */
   char *command_basename;      /* base filename of the program binary */
 
+  char *config_filename;       /* optional global program config filename */
+
   char *maindata_path;         /* main game data (installation) directory */
 
   char *userdata_subdir;       /* personal user game data directory */
@@ -937,6 +936,28 @@ struct SetupSystemInfo
   int audio_fragment_size;
 };
 
+struct SetupInternalInfo
+{
+  char *program_title;
+  char *program_author;
+  char *program_email;
+  char *program_website;
+  char *program_copyright;
+  char *program_company;
+
+  char *default_graphics_set;
+  char *default_sounds_set;
+  char *default_music_set;
+
+  char *fallback_graphics_file;
+  char *fallback_sounds_file;
+  char *fallback_music_file;
+
+  char *default_level_series;
+
+  boolean choose_from_top_leveldir;
+};
+
 struct SetupInfo
 {
   char *player_name;
@@ -988,6 +1009,7 @@ struct SetupInfo
   struct SetupInputInfo input[MAX_PLAYERS];
   struct SetupTouchInfo touch;
   struct SetupSystemInfo system;
+  struct SetupInternalInfo internal;
   struct OptionInfo options;
 };
 
@@ -1275,7 +1297,7 @@ extern int                        FrameCounter;
 /* function definitions */
 
 void InitProgramInfo(char *, char *, char *, char *, char *, char *, char *,
-                    int);
+                    char *, int);
 
 void SetWindowTitle();
 
index 17a1b3cb3c31fe0c4b3cd0676ff70b9f62c2c09e..1e9124777cf9a13e80b6866339d075efa7b8f883 100644 (file)
@@ -16,6 +16,7 @@
 #include "game.h"
 #include "tape.h"
 #include "tools.h"
+#include "files.h"
 #include "events.h"
 #include "config.h"
 
@@ -5624,11 +5625,51 @@ static void print_version()
   }
 }
 
+static void InitProgramConfig(char *command_filename)
+{
+  char *command_basename = getBaseName(command_filename);
+  char *config_filename = getProgramConfigFilename(command_filename);
+  char *program_title = PROGRAM_TITLE_STRING;
+  char *userdata_subdir;
+  char *userdata_subdir_unix;
+
+  // read default program config, if existing
+  if (fileExists(config_filename))
+    LoadSetupFromFilename(config_filename);
+
+  // set program title from potentially redefined program title
+  if (setup.internal.program_title != NULL &&
+      strlen(setup.internal.program_title) > 0)
+    program_title = getStringCopy(setup.internal.program_title);
+
+  // strip trailing executable suffix from command basename
+  if (strSuffix(command_basename, ".exe"))
+    command_basename[strlen(command_basename) - 4] = '\0';
+
+  userdata_subdir_unix = getStringCat2(".", command_basename);
+
+#if defined(PLATFORM_WIN32) || defined(PLATFORM_MACOSX)
+  userdata_subdir = program_title;
+#elif defined(PLATFORM_UNIX)
+  userdata_subdir = userdata_subdir_unix;
+#else
+  userdata_subdir = USERDATA_DIRECTORY_OTHER;
+#endif
+
+  InitProgramInfo(command_filename,
+                 config_filename,
+                 userdata_subdir,
+                 userdata_subdir_unix,
+                 program_title,
+                 program_title,
+                 SDL_ICON_FILENAME,
+                 COOKIE_PREFIX,
+                 GAME_VERSION_ACTUAL);
+}
+
 int main(int argc, char *argv[])
 {
-  InitProgramInfo(argv[0], USERDATA_DIRECTORY, USERDATA_DIRECTORY_UNIX,
-                 PROGRAM_TITLE_STRING, ICON_TITLE_STRING, SDL_ICON_FILENAME,
-                 COOKIE_PREFIX, GAME_VERSION_ACTUAL);
+  InitProgramConfig(argv[0]);
 
   InitWindowTitleFunction(getWindowTitleString);
   InitExitMessageFunction(DisplayExitMessage);
index aeceace327d92fc67579bd6cd9e0b27d1d61a199..5b919cd3efd764edec0cf685e78eb1d531032db4 100644 (file)
 
 #define PROGRAM_TITLE_STRING           "Rocks'n'Diamonds"
 #define PROGRAM_AUTHOR_STRING          "Holger Schemel"
-#define PROGRAM_COPYRIGHT_STRING       "Copyright \xa9""1995-2015 by Holger Schemel"
 #define PROGRAM_EMAIL_STRING           "info@artsoft.org"
 #define PROGRAM_WEBSITE_STRING         "http://www.artsoft.org/"
-#define PROGRAM_GAME_BY_STRING         "A Game by Artsoft Entertainment"
-#define PROGRAM_UNIX_DATADIR_STRING    ".rocksndiamonds"
-
-#if defined(CREATE_SPECIAL_EDITION_RND_JUE)
-#undef  PROGRAM_TITLE_STRING
-#define PROGRAM_TITLE_STRING           "R'n'D jue"
-#undef  PROGRAM_UNIX_DATADIR_STRING
-#define PROGRAM_UNIX_DATADIR_STRING    ".rnd_jue"
-#endif
+#define PROGRAM_COPYRIGHT_STRING       "Copyright \xa9""1995-2015 by Holger Schemel"
+#define PROGRAM_COMPANY_STRING         "A Game by Artsoft Entertainment"
 
-#define ICON_TITLE_STRING              PROGRAM_TITLE_STRING
 #define COOKIE_PREFIX                  "ROCKSNDIAMONDS"
 
-#define USERDATA_DIRECTORY_WIN32       PROGRAM_TITLE_STRING
-#define USERDATA_DIRECTORY_MACOSX      PROGRAM_TITLE_STRING
-#define USERDATA_DIRECTORY_UNIX                PROGRAM_UNIX_DATADIR_STRING
 #define USERDATA_DIRECTORY_OTHER       "userdata"
 
-#if defined(PLATFORM_WIN32)
-#define USERDATA_DIRECTORY             USERDATA_DIRECTORY_WIN32
-#elif defined(PLATFORM_MACOSX)
-#define USERDATA_DIRECTORY             USERDATA_DIRECTORY_MACOSX
-#elif defined(PLATFORM_UNIX)
-#define USERDATA_DIRECTORY             USERDATA_DIRECTORY_UNIX
-#else
-#define USERDATA_DIRECTORY             USERDATA_DIRECTORY_OTHER
-#endif
-
 #define SDL_ICON_FILENAME              "RocksIcon32x32.png"
 
 /* file version numbers for resource files (levels, tapes, score, setup, etc.)
index 212e2b4caf76c05e675f5c5820e5a8932951eedb..6e661ea5fa996aae9202c7ca7f5aff0d25ab46bd 100644 (file)
@@ -504,9 +504,6 @@ static char *main_text_level_year           = NULL;
 static char *main_text_level_imported_from     = NULL;
 static char *main_text_level_imported_by       = NULL;
 static char *main_text_level_tested_by         = NULL;
-static char *main_text_title_1                 = PROGRAM_TITLE_STRING;
-static char *main_text_title_2                 = PROGRAM_COPYRIGHT_STRING;
-static char *main_text_title_3                 = PROGRAM_GAME_BY_STRING;
 
 struct MainControlInfo
 {
@@ -656,19 +653,19 @@ static struct MainControlInfo main_controls[] =
   {
     MAIN_CONTROL_TITLE_1,
     NULL,                              -1,
-    &menu.main.text.title_1,           &main_text_title_1,
+    &menu.main.text.title_1,           &setup.internal.program_title,
     NULL,                              NULL,
   },
   {
     MAIN_CONTROL_TITLE_2,
     NULL,                              -1,
-    &menu.main.text.title_2,           &main_text_title_2,
+    &menu.main.text.title_2,           &setup.internal.program_copyright,
     NULL,                              NULL,
   },
   {
     MAIN_CONTROL_TITLE_3,
     NULL,                              -1,
-    &menu.main.text.title_3,           &main_text_title_3,
+    &menu.main.text.title_3,           &setup.internal.program_company,
     NULL,                              NULL,
   },
 
@@ -1212,8 +1209,9 @@ static void drawChooseTreeCursor(int ypos, boolean active)
 
 void DrawHeadline()
 {
-  DrawTextSCentered(MENU_TITLE1_YPOS, FONT_TITLE_1, PROGRAM_TITLE_STRING);
-  DrawTextSCentered(MENU_TITLE2_YPOS, FONT_TITLE_2, PROGRAM_COPYRIGHT_STRING);
+  DrawTextSCentered(MENU_TITLE1_YPOS, FONT_TITLE_1, getProgramTitleString());
+  DrawTextSCentered(MENU_TITLE2_YPOS, FONT_TITLE_2,
+                   setup.internal.program_copyright);
 }
 
 int effectiveGameStatus()
@@ -1473,11 +1471,11 @@ void DrawMainMenu()
   DrawMainMenuExt(REDRAW_ALL, FALSE);
 }
 
-#if defined(CREATE_SPECIAL_EDITION_RND_JUE)
 static void gotoTopLevelDir()
 {
-  /* move upwards to top level directory */
-  while (leveldir_current->node_parent)
+  /* move upwards until inside (but not above) top level directory */
+  while (leveldir_current->node_parent &&
+        !strEqual(leveldir_current->node_parent->subdir, STRING_TOP_DIRECTORY))
   {
     /* write a "path" into level tree for easy navigation to last level */
     if (leveldir_current->node_parent->node_group->cl_first == -1)
@@ -1502,7 +1500,6 @@ static void gotoTopLevelDir()
     leveldir_current = leveldir_current->node_parent;
   }
 }
-#endif
 
 void HandleTitleScreen(int mx, int my, int dx, int dy, int button)
 {
@@ -1835,9 +1832,8 @@ void HandleMainMenu(int mx, int my, int dx, int dy, int button)
          SaveLevelSetup_LastSeries();
          SaveLevelSetup_SeriesInfo();
 
-#if defined(CREATE_SPECIAL_EDITION_RND_JUE)
-         gotoTopLevelDir();
-#endif
+         if (setup.internal.choose_from_top_leveldir)
+           gotoTopLevelDir();
 
          ChangeViewportPropertiesIfNeeded();
 
@@ -2855,11 +2851,11 @@ void DrawInfoScreen_Program()
   DrawTextSCentered(ystart2 + 1 * ystep, FONT_TEXT_2,
                    "If you like it, send e-mail to:");
   DrawTextSCentered(ystart2 + 2 * ystep, FONT_TEXT_3,
-                   PROGRAM_EMAIL_STRING);
+                   setup.internal.program_email);
   DrawTextSCentered(ystart2 + 4 * ystep, FONT_TEXT_2,
                    "More information and levels:");
   DrawTextSCentered(ystart2 + 5 * ystep, FONT_TEXT_3,
-                   PROGRAM_WEBSITE_STRING);
+                   setup.internal.program_website);
   DrawTextSCentered(ystart2 + 7 * ystep, FONT_TEXT_2,
                    "If you have created new levels,");
   DrawTextSCentered(ystart2 + 8 * ystep, FONT_TEXT_2,
@@ -2931,7 +2927,7 @@ void DrawInfoScreen_Version()
   DrawTextSCentered(ystart1, FONT_TEXT_1, "Version Information:");
 
   DrawTextF(xstart1, ystart2, font_header, "Name");
-  DrawTextF(xstart2, ystart2, font_text, PROGRAM_TITLE_STRING);
+  DrawTextF(xstart2, ystart2, font_text, getProgramTitleString());
 
   ystart2 += ystep;
   DrawTextF(xstart1, ystart2, font_header, "Version");