+ /* create hash from image config list */
+ image_config_hash = newSetupFileHash();
+ for (i = 0; image_config[i].token != NULL; i++)
+ setHashEntry(image_config_hash,
+ image_config[i].token,
+ image_config[i].value);
+
+ /* create hash from element token list */
+ element_token_hash = newSetupFileHash();
+ for (i = 0; element_name_info[i].token_name != NULL; i++)
+ setHashEntry(element_token_hash,
+ element_name_info[i].token_name,
+ int2str(i, 0));
+
+ /* create hash from graphic token list */
+ graphic_token_hash = newSetupFileHash();
+ for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
+ if (strSuffix(image_config[i].value, ".png") ||
+ strSuffix(image_config[i].value, ".pcx") ||
+ strSuffix(image_config[i].value, ".wav") ||
+ strEqual(image_config[i].value, UNDEFINED_FILENAME))
+ setHashEntry(graphic_token_hash,
+ image_config[i].token,
+ int2str(graphic++, 0));
+
+ /* create hash from font token list */
+ font_token_hash = newSetupFileHash();
+ for (i = 0; font_info[i].token_name != NULL; i++)
+ setHashEntry(font_token_hash,
+ font_info[i].token_name,
+ int2str(i, 0));
+
+ /* set default filenames for all cloned graphics in static configuration */
+ for (i = 0; image_config[i].token != NULL; i++)
+ {
+ if (strEqual(image_config[i].value, UNDEFINED_FILENAME))
+ {
+ char *token = image_config[i].token;
+ char *token_clone_from = getStringCat2(token, ".clone_from");
+ char *token_cloned = getHashEntry(image_config_hash, token_clone_from);
+
+ if (token_cloned != NULL)
+ {
+ char *value_cloned = getHashEntry(image_config_hash, token_cloned);
+
+ if (value_cloned != NULL)
+ {
+ /* set default filename in static configuration */
+ image_config[i].value = value_cloned;
+
+ /* set default filename in image config hash */
+ setHashEntry(image_config_hash, token, value_cloned);
+ }
+ }
+
+ free(token_clone_from);
+ }
+ }
+
+ /* always start with reliable default values (all elements) */
+ for (i = 0; i < MAX_NUM_ELEMENTS; i++)
+ ActiveElement[i] = i;
+
+ /* now add all entries that have an active state (active elements) */
+ for (i = 0; element_with_active_state[i].element != -1; i++)
+ {
+ int element = element_with_active_state[i].element;
+ int element_active = element_with_active_state[i].element_active;
+
+ ActiveElement[element] = element_active;
+ }
+
+ /* always start with reliable default values (all buttons) */
+ for (i = 0; i < NUM_IMAGE_FILES; i++)
+ ActiveButton[i] = i;
+
+ /* now add all entries that have an active state (active buttons) */
+ for (i = 0; button_with_active_state[i].button != -1; i++)
+ {
+ int button = button_with_active_state[i].button;
+ int button_active = button_with_active_state[i].button_active;
+
+ ActiveButton[button] = button_active;
+ }
+
+ /* always start with reliable default values (all fonts) */
+ for (i = 0; i < NUM_FONTS; i++)
+ ActiveFont[i] = i;
+
+ /* now add all entries that have an active state (active fonts) */
+ for (i = 0; font_with_active_state[i].font_nr != -1; i++)
+ {
+ int font = font_with_active_state[i].font_nr;
+ int font_active = font_with_active_state[i].font_nr_active;
+
+ ActiveFont[font] = font_active;
+ }
+
+ global.autoplay_leveldir = NULL;
+ global.convert_leveldir = NULL;
+ global.create_images_dir = NULL;
+
+ global.frames_per_second = 0;
+
+ global.border_status = GAME_MODE_MAIN;
+
+ global.use_envelope_request = FALSE;
+}
+
+void Execute_Command(char *command)
+{
+ int i;
+
+ if (strEqual(command, "print graphicsinfo.conf"))
+ {
+ Print("# You can configure additional/alternative image files here.\n");
+ Print("# (The entries below are default and therefore commented out.)\n");
+ Print("\n");
+ Print("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
+ Print("\n");
+ Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
+ Print("\n");
+
+ for (i = 0; image_config[i].token != NULL; i++)
+ Print("# %s\n", getFormattedSetupEntry(image_config[i].token,
+ image_config[i].value));
+
+ exit(0);
+ }
+ else if (strEqual(command, "print soundsinfo.conf"))
+ {
+ Print("# You can configure additional/alternative sound files here.\n");
+ Print("# (The entries below are default and therefore commented out.)\n");
+ Print("\n");
+ Print("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
+ Print("\n");
+ Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
+ Print("\n");
+
+ for (i = 0; sound_config[i].token != NULL; i++)
+ Print("# %s\n", getFormattedSetupEntry(sound_config[i].token,
+ sound_config[i].value));
+
+ exit(0);
+ }
+ else if (strEqual(command, "print musicinfo.conf"))
+ {
+ Print("# You can configure additional/alternative music files here.\n");
+ Print("# (The entries below are default and therefore commented out.)\n");
+ Print("\n");
+ Print("%s\n", getFormattedSetupEntry("name", "Classic Music"));
+ Print("\n");
+ Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
+ Print("\n");
+
+ for (i = 0; music_config[i].token != NULL; i++)
+ Print("# %s\n", getFormattedSetupEntry(music_config[i].token,
+ music_config[i].value));
+
+ exit(0);
+ }
+ else if (strEqual(command, "print editorsetup.conf"))
+ {
+ Print("# You can configure your personal editor element list here.\n");
+ Print("# (The entries below are default and therefore commented out.)\n");
+ Print("\n");
+
+ /* this is needed to be able to check element list for cascade elements */
+ InitElementPropertiesStatic();
+ InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
+
+ PrintEditorElementList();
+
+ exit(0);
+ }
+ else if (strEqual(command, "print helpanim.conf"))
+ {
+ Print("# You can configure different element help animations here.\n");
+ Print("# (The entries below are default and therefore commented out.)\n");
+ Print("\n");
+
+ for (i = 0; helpanim_config[i].token != NULL; i++)
+ {
+ Print("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
+ helpanim_config[i].value));
+
+ if (strEqual(helpanim_config[i].token, "end"))
+ Print("#\n");
+ }
+
+ exit(0);
+ }
+ else if (strEqual(command, "print helptext.conf"))
+ {
+ Print("# You can configure different element help text here.\n");
+ Print("# (The entries below are default and therefore commented out.)\n");
+ Print("\n");
+
+ for (i = 0; helptext_config[i].token != NULL; i++)
+ Print("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
+ helptext_config[i].value));
+
+ exit(0);
+ }
+ else if (strPrefix(command, "dump level "))
+ {
+ char *filename = &command[11];
+
+ if (!fileExists(filename))
+ Error(ERR_EXIT, "cannot open file '%s'", filename);
+
+ LoadLevelFromFilename(&level, filename);
+ DumpLevel(&level);
+
+ exit(0);
+ }
+ else if (strPrefix(command, "dump tape "))
+ {
+ char *filename = &command[10];
+
+ if (!fileExists(filename))
+ Error(ERR_EXIT, "cannot open file '%s'", filename);
+
+ LoadTapeFromFilename(filename);
+ DumpTape(&tape);
+
+ exit(0);
+ }
+ else if (strPrefix(command, "autotest ") ||
+ strPrefix(command, "autoplay ") ||
+ strPrefix(command, "autoffwd "))
+ {
+ char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
+
+ global.autoplay_mode = (strPrefix(command, "autotest") ? AUTOPLAY_TEST :
+ strPrefix(command, "autoplay") ? AUTOPLAY_PLAY :
+ strPrefix(command, "autoffwd") ? AUTOPLAY_FFWD : 0);
+
+ while (*str_ptr != '\0') /* continue parsing string */
+ {
+ /* cut leading whitespace from string, replace it by string terminator */
+ while (*str_ptr == ' ' || *str_ptr == '\t')
+ *str_ptr++ = '\0';
+
+ if (*str_ptr == '\0') /* end of string reached */
+ break;
+
+ if (global.autoplay_leveldir == NULL) /* read level set string */
+ {
+ global.autoplay_leveldir = str_ptr;
+ global.autoplay_all = TRUE; /* default: play all tapes */
+
+ for (i = 0; i < MAX_TAPES_PER_SET; i++)
+ global.autoplay_level[i] = FALSE;
+ }
+ else /* read level number string */
+ {
+ int level_nr = atoi(str_ptr); /* get level_nr value */
+
+ if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
+ global.autoplay_level[level_nr] = TRUE;
+
+ global.autoplay_all = FALSE;
+ }
+
+ /* advance string pointer to the next whitespace (or end of string) */
+ while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
+ str_ptr++;
+ }
+ }
+ else if (strPrefix(command, "convert "))
+ {
+ char *str_copy = getStringCopy(strchr(command, ' ') + 1);
+ char *str_ptr = strchr(str_copy, ' ');
+
+ global.convert_leveldir = str_copy;
+ global.convert_level_nr = -1;
+
+ if (str_ptr != NULL) /* level number follows */
+ {
+ *str_ptr++ = '\0'; /* terminate leveldir string */
+ global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
+ }
+ }
+ else if (strPrefix(command, "create images "))
+ {
+ global.create_images_dir = getStringCopy(&command[14]);
+
+ if (access(global.create_images_dir, W_OK) != 0)
+ Error(ERR_EXIT, "image target directory '%s' not found or not writable",
+ global.create_images_dir);
+ }
+ else if (strPrefix(command, "create CE image "))
+ {
+ CreateCustomElementImages(&command[16]);
+
+ exit(0);
+ }
+
+#if DEBUG
+#if defined(TARGET_SDL2)
+ else if (strEqual(command, "SDL_ListModes"))
+ {
+ SDL_Init(SDL_INIT_VIDEO);
+
+ int num_displays = SDL_GetNumVideoDisplays();
+
+ // check if there are any displays available
+ if (num_displays < 0)
+ {
+ Print("No displays available: %s\n", SDL_GetError());
+
+ exit(-1);
+ }
+
+ for (i = 0; i < num_displays; i++)
+ {
+ int num_modes = SDL_GetNumDisplayModes(i);
+ int j;
+
+ Print("Available display modes for display %d:\n", i);
+
+ // check if there are any display modes available for this display
+ if (num_modes < 0)
+ {
+ Print("No display modes available for display %d: %s\n",
+ i, SDL_GetError());
+
+ exit(-1);
+ }
+
+ for (j = 0; j < num_modes; j++)
+ {
+ SDL_DisplayMode mode;
+
+ if (SDL_GetDisplayMode(i, j, &mode) < 0)
+ {
+ Print("Cannot get display mode %d for display %d: %s\n",
+ j, i, SDL_GetError());
+
+ exit(-1);
+ }
+
+ Print("- %d x %d\n", mode.w, mode.h);
+ }
+ }
+
+ exit(0);
+ }
+#elif defined(TARGET_SDL)
+ else if (strEqual(command, "SDL_ListModes"))
+ {
+ SDL_Rect **modes;
+ int i;
+
+ SDL_Init(SDL_INIT_VIDEO);
+
+ /* get available fullscreen/hardware modes */
+ modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
+
+ /* check if there are any modes available */
+ if (modes == NULL)
+ {
+ Print("No modes available!\n");
+
+ exit(-1);
+ }
+
+ /* check if our resolution is restricted */
+ if (modes == (SDL_Rect **)-1)
+ {
+ Print("All resolutions available.\n");
+ }
+ else
+ {
+ Print("Available display modes:\n");
+
+ for (i = 0; modes[i]; i++)
+ Print("- %d x %d\n", modes[i]->w, modes[i]->h);
+ }
+
+ exit(0);
+ }
+#endif
+#endif
+
+ else
+ {
+ Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
+ }
+}
+
+static void InitSetup()
+{
+ LoadSetup(); /* global setup info */
+
+ /* set some options from setup file */
+
+ if (setup.options.verbose)
+ options.verbose = TRUE;
+}
+
+static void InitGameInfo()
+{
+ game.restart_level = FALSE;
+}
+
+static void InitPlayerInfo()
+{
+ int i;
+
+ /* choose default local player */
+ local_player = &stored_player[0];
+
+ for (i = 0; i < MAX_PLAYERS; i++)
+ stored_player[i].connected = FALSE;
+
+ local_player->connected = TRUE;
+}
+
+static void InitArtworkInfo()
+{
+ LoadArtworkInfo();
+}
+
+static char *get_string_in_brackets(char *string)
+{
+ char *string_in_brackets = checked_malloc(strlen(string) + 3);
+
+ sprintf(string_in_brackets, "[%s]", string);
+
+ return string_in_brackets;
+}
+
+static char *get_level_id_suffix(int id_nr)
+{
+ char *id_suffix = checked_malloc(1 + 3 + 1);
+
+ if (id_nr < 0 || id_nr > 999)
+ id_nr = 0;
+
+ sprintf(id_suffix, ".%03d", id_nr);
+
+ return id_suffix;
+}
+
+static void InitArtworkConfig()
+{
+ static char *image_id_prefix[MAX_NUM_ELEMENTS +
+ NUM_FONTS +
+ NUM_GLOBAL_ANIM_TOKENS + 1];
+ static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
+ static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
+ static char *action_id_suffix[NUM_ACTIONS + 1];
+ static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
+ static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
+ static char *level_id_suffix[MAX_LEVELS + 1];
+ static char *dummy[1] = { NULL };
+ static char *ignore_generic_tokens[] =
+ {
+ "name",
+ "sort_priority",
+ NULL
+ };
+ static char **ignore_image_tokens;
+ static char **ignore_sound_tokens;
+ static char **ignore_music_tokens;
+ int num_ignore_generic_tokens;
+ int num_ignore_image_tokens;
+ int num_ignore_sound_tokens;
+ int num_ignore_music_tokens;
+ int i;
+
+ /* dynamically determine list of generic tokens to be ignored */
+ num_ignore_generic_tokens = 0;
+ for (i = 0; ignore_generic_tokens[i] != NULL; i++)
+ num_ignore_generic_tokens++;
+
+ /* dynamically determine list of image tokens to be ignored */
+ num_ignore_image_tokens = num_ignore_generic_tokens;
+ for (i = 0; image_config_vars[i].token != NULL; i++)
+ num_ignore_image_tokens++;
+ ignore_image_tokens =
+ checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
+ for (i = 0; i < num_ignore_generic_tokens; i++)
+ ignore_image_tokens[i] = ignore_generic_tokens[i];
+ for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
+ ignore_image_tokens[num_ignore_generic_tokens + i] =
+ image_config_vars[i].token;
+ ignore_image_tokens[num_ignore_image_tokens] = NULL;
+
+ /* dynamically determine list of sound tokens to be ignored */
+ num_ignore_sound_tokens = num_ignore_generic_tokens;
+ ignore_sound_tokens =
+ checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
+ for (i = 0; i < num_ignore_generic_tokens; i++)
+ ignore_sound_tokens[i] = ignore_generic_tokens[i];
+ ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
+
+ /* dynamically determine list of music tokens to be ignored */
+ num_ignore_music_tokens = num_ignore_generic_tokens;
+ ignore_music_tokens =
+ checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
+ for (i = 0; i < num_ignore_generic_tokens; i++)
+ ignore_music_tokens[i] = ignore_generic_tokens[i];
+ ignore_music_tokens[num_ignore_music_tokens] = NULL;
+
+ for (i = 0; i < MAX_NUM_ELEMENTS; i++)
+ image_id_prefix[i] = element_info[i].token_name;
+ for (i = 0; i < NUM_FONTS; i++)
+ image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
+ for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
+ image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] =
+ global_anim_info[i].token_name;
+ image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
+
+ for (i = 0; i < MAX_NUM_ELEMENTS; i++)
+ sound_id_prefix[i] = element_info[i].token_name;
+ for (i = 0; i < MAX_NUM_ELEMENTS; i++)
+ sound_id_prefix[MAX_NUM_ELEMENTS + i] =
+ get_string_in_brackets(element_info[i].class_name);
+ sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
+
+ for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
+ music_id_prefix[i] = music_prefix_info[i].prefix;
+ music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
+
+ for (i = 0; i < NUM_ACTIONS; i++)
+ action_id_suffix[i] = element_action_info[i].suffix;
+ action_id_suffix[NUM_ACTIONS] = NULL;
+
+ for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
+ direction_id_suffix[i] = element_direction_info[i].suffix;
+ direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
+
+ for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
+ special_id_suffix[i] = special_suffix_info[i].suffix;
+ special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
+
+ for (i = 0; i < MAX_LEVELS; i++)
+ level_id_suffix[i] = get_level_id_suffix(i);
+ level_id_suffix[MAX_LEVELS] = NULL;
+
+ InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
+ image_id_prefix, action_id_suffix, direction_id_suffix,
+ special_id_suffix, ignore_image_tokens);
+ InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
+ sound_id_prefix, action_id_suffix, dummy,
+ special_id_suffix, ignore_sound_tokens);
+ InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
+ music_id_prefix, special_id_suffix, level_id_suffix,
+ dummy, ignore_music_tokens);
+}
+
+static void InitMixer()
+{
+ OpenAudio();
+
+ StartMixer();
+}
+
+void InitGfxBuffers()
+{
+ static int win_xsize_last = -1;
+ static int win_ysize_last = -1;
+
+ /* create additional image buffers for double-buffering and cross-fading */
+
+ if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
+ {
+ /* may contain content for cross-fading -- only re-create if changed */
+ ReCreateBitmap(&bitmap_db_store, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
+ ReCreateBitmap(&bitmap_db_cross, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
+
+ win_xsize_last = WIN_XSIZE;
+ win_ysize_last = WIN_YSIZE;
+ }
+
+ ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE, DEFAULT_DEPTH);
+ ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE, DEFAULT_DEPTH);
+ ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE, DEFAULT_DEPTH);
+ ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE, DEFAULT_DEPTH);
+ ReCreateBitmap(&bitmap_db_toons, FULL_SXSIZE, FULL_SYSIZE, DEFAULT_DEPTH);
+
+ /* initialize screen properties */
+ InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
+ REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
+ bitmap_db_field);
+ InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
+ InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
+ InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
+ InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
+ InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
+ InitGfxClipRegion(FALSE, -1, -1, -1, -1);
+
+ /* required if door size definitions have changed */
+ InitGraphicCompatibilityInfo_Doors();
+
+ InitGfxBuffers_EM();
+ InitGfxBuffers_SP();
+}
+
+void InitGfx()
+{
+ struct GraphicInfo *graphic_info_last = graphic_info;
+ char *filename_font_initial = NULL;
+ char *filename_anim_initial = NULL;
+ Bitmap *bitmap_font_initial = NULL;
+ int font_height;
+ int i, j;
+
+ /* determine settings for initial font (for displaying startup messages) */
+ for (i = 0; image_config[i].token != NULL; i++)
+ {
+ for (j = 0; j < NUM_INITIAL_FONTS; j++)
+ {
+ char font_token[128];
+ int len_font_token;
+
+ sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
+ len_font_token = strlen(font_token);
+
+ if (strEqual(image_config[i].token, font_token))
+ filename_font_initial = image_config[i].value;
+ else if (strlen(image_config[i].token) > len_font_token &&
+ strncmp(image_config[i].token, font_token, len_font_token) == 0)
+ {
+ if (strEqual(&image_config[i].token[len_font_token], ".x"))
+ font_initial[j].src_x = atoi(image_config[i].value);
+ else if (strEqual(&image_config[i].token[len_font_token], ".y"))
+ font_initial[j].src_y = atoi(image_config[i].value);
+ else if (strEqual(&image_config[i].token[len_font_token], ".width"))
+ font_initial[j].width = atoi(image_config[i].value);
+ else if (strEqual(&image_config[i].token[len_font_token], ".height"))
+ font_initial[j].height = atoi(image_config[i].value);
+ }
+ }
+ }
+
+ for (j = 0; j < NUM_INITIAL_FONTS; j++)
+ {
+ font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
+ font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
+ }
+
+ if (filename_font_initial == NULL) /* should not happen */
+ Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
+
+ InitGfxBuffers();
+ InitGfxCustomArtworkInfo();
+ InitGfxOtherSettings();
+
+ bitmap_font_initial = LoadCustomImage(filename_font_initial);
+
+ for (j = 0; j < NUM_INITIAL_FONTS; j++)
+ font_initial[j].bitmap = bitmap_font_initial;
+
+ InitFontGraphicInfo();
+
+ font_height = getFontHeight(FC_RED);
+
+ DrawInitText(getProgramInitString(), 20, FC_YELLOW);
+ 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 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);
+
+ 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))
+ {
+ SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
+
+ if (setup_file_hash)
+ {
+ char *filename = getHashEntry(setup_file_hash, anim_token);
+
+ if (filename)
+ {
+ 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 (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);
+
+ anim_initial.bitmaps =
+ checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
+
+ 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);
+
+ graphic_info = graphic_info_last;
+
+ init.busy.width = anim_initial.width;
+ init.busy.height = anim_initial.height;
+
+ InitMenuDesignSettings_Static();
+
+ InitGfxDrawBusyAnimFunction(DrawInitAnim);
+ InitGfxDrawGlobalAnimFunction(DrawGlobalAnim);
+
+ /* use copy of busy animation to prevent change while reloading artwork */
+ init_last = init;
+}
+
+void InitGfxBackground()
+{
+ fieldbuffer = bitmap_db_field;
+ SetDrawtoField(DRAW_BACKBUFFER);
+
+ ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
+
+ redraw_mask = REDRAW_ALL;
+}
+
+static void InitLevelInfo()
+{
+ LoadLevelInfo(); /* global level info */
+ LoadLevelSetup_LastSeries(); /* last played series info */
+ LoadLevelSetup_SeriesInfo(); /* last played level info */
+
+ if (global.autoplay_leveldir &&
+ global.autoplay_mode != AUTOPLAY_TEST)
+ {
+ leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
+ global.autoplay_leveldir);
+ if (leveldir_current == NULL)
+ leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
+ }
+}
+
+static void InitLevelArtworkInfo()
+{
+ LoadLevelArtworkInfo();
+}
+
+static void InitImages()
+{
+ print_timestamp_init("InitImages");
+
+#if 0
+ printf("::: leveldir_current->identifier == '%s'\n",
+ leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
+ printf("::: leveldir_current->graphics_path == '%s'\n",
+ leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
+ printf("::: leveldir_current->graphics_set == '%s'\n",
+ leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
+ printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
+ leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
+#endif
+
+ setLevelArtworkDir(artwork.gfx_first);
+
+#if 0
+ printf("::: leveldir_current->identifier == '%s'\n",
+ leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
+ printf("::: leveldir_current->graphics_path == '%s'\n",
+ leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
+ printf("::: leveldir_current->graphics_set == '%s'\n",
+ leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
+ printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
+ leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
+#endif
+
+#if 0
+ printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
+ leveldir_current->identifier,
+ artwork.gfx_current_identifier,
+ artwork.gfx_current->identifier,
+ leveldir_current->graphics_set,
+ leveldir_current->graphics_path);
+#endif
+
+ UPDATE_BUSY_STATE();
+
+ ReloadCustomImages();
+ print_timestamp_time("ReloadCustomImages");
+
+ UPDATE_BUSY_STATE();
+
+ LoadCustomElementDescriptions();
+ print_timestamp_time("LoadCustomElementDescriptions");
+
+ UPDATE_BUSY_STATE();
+
+ LoadMenuDesignSettings();
+ print_timestamp_time("LoadMenuDesignSettings");
+
+ UPDATE_BUSY_STATE();
+
+ ReinitializeGraphics();
+ print_timestamp_time("ReinitializeGraphics");
+
+ UPDATE_BUSY_STATE();
+
+ print_timestamp_done("InitImages");
+}
+
+static void InitSound(char *identifier)
+{
+ print_timestamp_init("InitSound");
+
+ if (identifier == NULL)
+ identifier = artwork.snd_current->identifier;
+
+ /* set artwork path to send it to the sound server process */
+ setLevelArtworkDir(artwork.snd_first);
+
+ InitReloadCustomSounds(identifier);
+ print_timestamp_time("InitReloadCustomSounds");
+
+ ReinitializeSounds();
+ print_timestamp_time("ReinitializeSounds");
+
+ print_timestamp_done("InitSound");
+}
+
+static void InitMusic(char *identifier)
+{
+ print_timestamp_init("InitMusic");
+
+ if (identifier == NULL)
+ identifier = artwork.mus_current->identifier;
+
+ /* set artwork path to send it to the sound server process */
+ setLevelArtworkDir(artwork.mus_first);
+
+ InitReloadCustomMusic(identifier);
+ print_timestamp_time("InitReloadCustomMusic");
+
+ ReinitializeMusic();
+ print_timestamp_time("ReinitializeMusic");
+
+ print_timestamp_done("InitMusic");
+}
+
+void InitNetworkServer()
+{
+#if defined(NETWORK_AVALIABLE)
+ int nr_wanted;
+#endif
+
+ if (!options.network)
+ return;
+
+#if defined(NETWORK_AVALIABLE)
+ nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
+
+ if (!ConnectToServer(options.server_host, options.server_port))
+ Error(ERR_EXIT, "cannot connect to network game server");
+
+ SendToServer_PlayerName(setup.player_name);
+ SendToServer_ProtocolVersion();
+
+ if (nr_wanted)
+ SendToServer_NrWanted(nr_wanted);
+#endif
+}
+
+static boolean CheckArtworkConfigForCustomElements(char *filename)
+{
+ SetupFileHash *setup_file_hash;
+ boolean redefined_ce_found = FALSE;
+
+ /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */
+
+ if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
+ {
+ BEGIN_HASH_ITERATION(setup_file_hash, itr)
+ {
+ char *token = HASH_ITERATION_TOKEN(itr);
+
+ if (strPrefix(token, "custom_"))
+ {
+ redefined_ce_found = TRUE;
+
+ break;
+ }
+ }
+ END_HASH_ITERATION(setup_file_hash, itr)
+
+ freeSetupFileHash(setup_file_hash);
+ }
+
+ return redefined_ce_found;
+}
+
+static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
+{
+ char *filename_base, *filename_local;
+ boolean redefined_ce_found = FALSE;
+
+ setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
+
+#if 0
+ printf("::: leveldir_current->identifier == '%s'\n",
+ leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
+ printf("::: leveldir_current->graphics_path == '%s'\n",
+ leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
+ printf("::: leveldir_current->graphics_set == '%s'\n",
+ leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
+ printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
+ leveldir_current == NULL ? "[NULL]" :
+ LEVELDIR_ARTWORK_SET(leveldir_current, type));
+#endif
+
+ /* first look for special artwork configured in level series config */
+ filename_base = getCustomArtworkLevelConfigFilename(type);
+
+#if 0
+ printf("::: filename_base == '%s'\n", filename_base);
+#endif
+
+ if (fileExists(filename_base))
+ redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
+
+ filename_local = getCustomArtworkConfigFilename(type);
+
+#if 0
+ printf("::: filename_local == '%s'\n", filename_local);
+#endif
+
+ if (filename_local != NULL && !strEqual(filename_base, filename_local))
+ redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
+
+#if 0
+ printf("::: redefined_ce_found == %d\n", redefined_ce_found);
+#endif
+
+ return redefined_ce_found;
+}
+
+static void InitOverrideArtwork()
+{
+ boolean redefined_ce_found = FALSE;
+
+ /* to check if this level set redefines any CEs, do not use overriding */
+ gfx.override_level_graphics = FALSE;
+ gfx.override_level_sounds = FALSE;
+ gfx.override_level_music = FALSE;
+
+ /* now check if this level set has definitions for custom elements */
+ if (setup.override_level_graphics == AUTO ||
+ setup.override_level_sounds == AUTO ||
+ setup.override_level_music == AUTO)
+ redefined_ce_found =
+ (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
+ CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
+ CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
+
+#if 0
+ printf("::: redefined_ce_found == %d\n", redefined_ce_found);
+#endif
+
+ if (redefined_ce_found)
+ {
+ /* this level set has CE definitions: change "AUTO" to "FALSE" */
+ gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
+ gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
+ gfx.override_level_music = (setup.override_level_music == TRUE);
+ }
+ else
+ {
+ /* this level set has no CE definitions: change "AUTO" to "TRUE" */
+ gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
+ gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
+ gfx.override_level_music = (setup.override_level_music != FALSE);
+ }
+
+#if 0
+ printf("::: => %d, %d, %d\n",
+ gfx.override_level_graphics,
+ gfx.override_level_sounds,
+ gfx.override_level_music);
+#endif
+}
+
+static char *getNewArtworkIdentifier(int type)
+{
+ static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
+ static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
+ static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
+ static boolean initialized[3] = { FALSE, FALSE, FALSE };
+ TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
+ boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
+ char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
+ char *leveldir_identifier = leveldir_current->identifier;
+ /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
+ char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
+ boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
+ char *artwork_current_identifier;
+ char *artwork_new_identifier = NULL; /* default: nothing has changed */
+
+ /* leveldir_current may be invalid (level group, parent link) */
+ if (!validLevelSeries(leveldir_current))
+ return NULL;
+
+ /* 1st step: determine artwork set to be activated in descending order:
+ --------------------------------------------------------------------
+ 1. setup artwork (when configured to override everything else)
+ 2. artwork set configured in "levelinfo.conf" of current level set
+ (artwork in level directory will have priority when loading later)
+ 3. artwork in level directory (stored in artwork sub-directory)
+ 4. setup artwork (currently configured in setup menu) */
+
+ if (setup_override_artwork)
+ artwork_current_identifier = setup_artwork_set;
+ else if (leveldir_artwork_set != NULL)
+ artwork_current_identifier = leveldir_artwork_set;
+ else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
+ artwork_current_identifier = leveldir_identifier;
+ else
+ artwork_current_identifier = setup_artwork_set;
+
+
+ /* 2nd step: check if it is really needed to reload artwork set
+ ------------------------------------------------------------ */
+
+ /* ---------- reload if level set and also artwork set has changed ------- */
+ if (leveldir_current_identifier[type] != leveldir_identifier &&
+ (last_has_level_artwork_set[type] || has_level_artwork_set))
+ artwork_new_identifier = artwork_current_identifier;
+
+ leveldir_current_identifier[type] = leveldir_identifier;
+ last_has_level_artwork_set[type] = has_level_artwork_set;
+
+ /* ---------- reload if "override artwork" setting has changed ----------- */
+ if (last_override_level_artwork[type] != setup_override_artwork)
+ artwork_new_identifier = artwork_current_identifier;
+
+ last_override_level_artwork[type] = setup_override_artwork;
+
+ /* ---------- reload if current artwork identifier has changed ----------- */
+ if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
+ artwork_current_identifier))
+ artwork_new_identifier = artwork_current_identifier;
+
+ *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
+
+ /* ---------- do not reload directly after starting ---------------------- */
+ if (!initialized[type])
+ artwork_new_identifier = NULL;
+
+ initialized[type] = TRUE;
+
+ return artwork_new_identifier;
+}
+
+void ReloadCustomArtwork(int force_reload)
+{
+ int last_game_status = game_status; /* save current game status */
+ char *gfx_new_identifier;
+ char *snd_new_identifier;
+ char *mus_new_identifier;
+ boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
+ boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
+ boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
+ boolean reload_needed;
+
+ InitOverrideArtwork();
+
+ force_reload_gfx |= AdjustGraphicsForEMC();
+
+ gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
+ snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
+ mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
+
+ reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
+ snd_new_identifier != NULL || force_reload_snd ||
+ mus_new_identifier != NULL || force_reload_mus);
+
+ if (!reload_needed)
+ return;
+
+ print_timestamp_init("ReloadCustomArtwork");
+
+ game_status = GAME_MODE_LOADING;
+
+ FadeOut(REDRAW_ALL);
+
+ ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
+ print_timestamp_time("ClearRectangle");
+
+ FadeIn(REDRAW_ALL);
+
+ if (gfx_new_identifier != NULL || force_reload_gfx)
+ {
+#if 0
+ printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
+ artwork.gfx_current_identifier,
+ gfx_new_identifier,
+ artwork.gfx_current->identifier,
+ leveldir_current->graphics_set);
+#endif
+
+ InitImages();
+ print_timestamp_time("InitImages");
+ }
+
+ if (snd_new_identifier != NULL || force_reload_snd)
+ {
+ InitSound(snd_new_identifier);
+ print_timestamp_time("InitSound");
+ }
+
+ if (mus_new_identifier != NULL || force_reload_mus)
+ {
+ InitMusic(mus_new_identifier);
+ print_timestamp_time("InitMusic");
+ }
+
+ game_status = last_game_status; /* restore current game status */
+
+ init_last = init; /* switch to new busy animation */
+
+ FadeOut(REDRAW_ALL);
+
+ RedrawGlobalBorder();
+
+ /* force redraw of (open or closed) door graphics */
+ SetDoorState(DOOR_OPEN_ALL);
+ CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
+
+ FadeSetEnterScreen();
+ FadeSkipNextFadeOut();
+
+ print_timestamp_done("ReloadCustomArtwork");
+
+ LimitScreenUpdates(FALSE);
+}
+
+void KeyboardAutoRepeatOffUnlessAutoplay()
+{
+ if (global.autoplay_leveldir == NULL)
+ KeyboardAutoRepeatOff();
+}
+
+void DisplayExitMessage(char *format, va_list ap)
+{
+ // check if draw buffer and fonts for exit message are already available
+ if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
+ return;
+
+ int font_1 = FC_RED;
+ int font_2 = FC_YELLOW;
+ int font_3 = FC_BLUE;
+ int font_width = getFontWidth(font_2);
+ int font_height = getFontHeight(font_2);
+ int sx = SX;
+ int sy = SY;
+ int sxsize = WIN_XSIZE - 2 * sx;
+ int sysize = WIN_YSIZE - 2 * sy;
+ int line_length = sxsize / font_width;
+ int max_lines = sysize / font_height;
+ int num_lines_printed;
+
+ gfx.sx = sx;
+ gfx.sy = sy;
+ gfx.sxsize = sxsize;
+ gfx.sysize = sysize;
+
+ sy = 20;
+
+ ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
+
+ DrawTextSCentered(sy, font_1, "Fatal error:");
+ sy += 3 * font_height;;
+
+ num_lines_printed =
+ DrawTextBufferVA(sx, sy, format, ap, font_2,
+ line_length, line_length, max_lines,
+ 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
+ sy += (num_lines_printed + 3) * font_height;
+
+ DrawTextSCentered(sy, font_1, "For details, see the following error file:");
+ sy += 3 * font_height;
+
+ num_lines_printed =
+ DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2,
+ line_length, line_length, max_lines,
+ 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
+
+ DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
+
+ redraw_mask = REDRAW_ALL;
+
+ /* force drawing exit message even if screen updates are currently limited */
+ LimitScreenUpdates(FALSE);
+
+ BackToFront();
+
+ /* deactivate toons on error message screen */
+ setup.toons = FALSE;
+
+ WaitForEventToContinue();
+}
+
+
+/* ========================================================================= */
+/* OpenAll() */
+/* ========================================================================= */
+
+void OpenAll()
+{
+ print_timestamp_init("OpenAll");
+
+ game_status = GAME_MODE_LOADING;
+
+ InitCounter();
+
+ InitGlobal(); /* initialize some global variables */
+
+ print_timestamp_time("[init global stuff]");
+
+ InitSetup();
+
+ print_timestamp_time("[init setup/config stuff (1)]");
+
+ if (options.execute_command)
+ Execute_Command(options.execute_command);
+
+ if (options.serveronly)
+ {
+#if defined(PLATFORM_UNIX)
+ NetworkServer(options.server_port, options.serveronly);
+#else
+ Error(ERR_WARN, "networking only supported in Unix version");
+#endif
+
+ exit(0); /* never reached, server loops forever */
+ }
+
+ InitGameInfo();
+ print_timestamp_time("[init setup/config stuff (2)]");
+ InitPlayerInfo();
+ print_timestamp_time("[init setup/config stuff (3)]");
+ InitArtworkInfo(); /* needed before loading gfx, sound & music */
+ print_timestamp_time("[init setup/config stuff (4)]");
+ InitArtworkConfig(); /* needed before forking sound child process */
+ print_timestamp_time("[init setup/config stuff (5)]");
+ InitMixer();
+ print_timestamp_time("[init setup/config stuff (6)]");
+
+ InitRND(NEW_RANDOMIZE);
+ InitSimpleRandom(NEW_RANDOMIZE);
+
+ InitJoysticks();
+
+ print_timestamp_time("[init setup/config stuff]");
+
+ InitVideoDisplay();
+ InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
+
+ InitEventFilter(FilterEvents);
+
+ print_timestamp_time("[init video stuff]");
+
+ InitElementPropertiesStatic();
+ InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
+ InitElementPropertiesGfxElement();
+
+ print_timestamp_time("[init element properties stuff]");
+
+ InitGfx();
+
+ print_timestamp_time("InitGfx");
+
+ InitLevelInfo();
+ print_timestamp_time("InitLevelInfo");
+
+ InitLevelArtworkInfo();
+ print_timestamp_time("InitLevelArtworkInfo");
+
+ InitOverrideArtwork(); /* needs to know current level directory */
+ print_timestamp_time("InitOverrideArtwork");
+
+ InitImages(); /* needs to know current level directory */
+ print_timestamp_time("InitImages");
+
+ InitSound(NULL); /* needs to know current level directory */
+ print_timestamp_time("InitSound");
+
+ InitMusic(NULL); /* needs to know current level directory */
+ print_timestamp_time("InitMusic");
+
+ InitGfxBackground();
+
+ em_open_all();
+ sp_open_all();
+
+ if (global.autoplay_leveldir)
+ {
+ AutoPlayTape();
+ return;
+ }
+ else if (global.convert_leveldir)
+ {
+ ConvertLevels();
+ return;
+ }
+ else if (global.create_images_dir)
+ {
+ CreateLevelSketchImages();
+ return;
+ }
+
+ game_status = GAME_MODE_MAIN;
+
+ FadeSetEnterScreen();
+ if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
+ FadeSkipNextFadeOut();
+
+ print_timestamp_time("[post-artwork]");
+
+ print_timestamp_done("OpenAll");
+
+ DrawMainMenu();
+
+ InitNetworkServer();
+
+#if 0
+ Error(ERR_DEBUG, "::: SDL_GetBasePath() == '%s'",
+ SDL_GetBasePath());
+ Error(ERR_DEBUG, "::: SDL_GetPrefPath() == '%s'",
+ SDL_GetPrefPath("artsoft", "rocksndiamonds"));
+#if defined(PLATFORM_ANDROID)
+ Error(ERR_DEBUG, "::: SDL_AndroidGetInternalStoragePath() == '%s'",
+ SDL_AndroidGetInternalStoragePath());
+ Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStoragePath() == '%s'",
+ SDL_AndroidGetExternalStoragePath());
+ Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStorageState() == '%s'",
+ (SDL_AndroidGetExternalStorageState() ==
+ SDL_ANDROID_EXTERNAL_STORAGE_READ ? "read" :
+ SDL_AndroidGetExternalStorageState() ==
+ SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "write" : "not available"));
+#endif
+#endif
+}
+
+void CloseAllAndExit(int exit_value)
+{
+ StopSounds();
+ FreeAllSounds();
+ FreeAllMusic();
+ CloseAudio(); /* called after freeing sounds (needed for SDL) */
+
+ em_close_all();
+ sp_close_all();
+
+ FreeAllImages();
+
+#if defined(TARGET_SDL)
+#if defined(TARGET_SDL2)
+ // !!! TODO !!!
+ // set a flag to tell the network server thread to quit and wait for it
+ // using SDL_WaitThread()
+#else
+ if (network_server) /* terminate network server */
+ SDL_KillThread(server_thread);
+#endif
+#endif
+
+ CloseVideoDisplay();
+ ClosePlatformDependentStuff();
+
+ if (exit_value != 0)
+ {
+ /* fall back to default level set (current set may have caused an error) */
+ SaveLevelSetup_LastSeries_Deactivate();
+
+ /* tell user where to find error log file which may contain more details */
+ // (error notification now directly displayed on screen inside R'n'D
+ // NotifyUserAboutErrorFile(); /* currently only works for Windows */
+ }