+ element_info[i].token_name = element_name_info[i].token_name;
+ element_info[i].class_name = element_name_info[i].class_name;
+ element_info[i].editor_description= element_name_info[i].editor_description;
+ }
+
+ for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS + 1; i++)
+ {
+ // check if global_anim_name_info defined for each entry in "main.h"
+ if (i < NUM_GLOBAL_ANIM_TOKENS &&
+ global_anim_name_info[i].token_name == NULL)
+ Fail("undefined 'global_anim_name_info' entry for anim %d", i);
+
+ global_anim_info[i].token_name = global_anim_name_info[i].token_name;
+ }
+
+ // 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.patchtapes_leveldir = NULL;
+ global.convert_leveldir = NULL;
+ global.create_images_dir = NULL;
+
+ global.frames_per_second = 0;
+ global.show_frames_per_second = FALSE;
+
+ global.border_status = GAME_MODE_LOADING;
+ global.anim_status = global.anim_status_next = GAME_MODE_LOADING;
+
+ global.use_envelope_request = FALSE;
+
+ global.user_names = NULL;
+}
+
+static 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))
+ Fail("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))
+ Fail("cannot open file '%s'", filename);
+
+ LoadTapeFromFilename(filename);
+ DumpTape(&tape);
+
+ exit(0);
+ }
+ else if (strPrefix(command, "autoplay ") ||
+ strPrefix(command, "autoffwd ") ||
+ strPrefix(command, "autowarp ") ||
+ strPrefix(command, "autotest ") ||
+ strPrefix(command, "autofix "))
+ {
+ char *str_ptr = getStringCopy(&command[8]); // read command parameters
+
+ global.autoplay_mode =
+ (strPrefix(command, "autoplay") ? AUTOPLAY_MODE_PLAY :
+ strPrefix(command, "autoffwd") ? AUTOPLAY_MODE_FFWD :
+ strPrefix(command, "autowarp") ? AUTOPLAY_MODE_WARP :
+ strPrefix(command, "autotest") ? AUTOPLAY_MODE_TEST :
+ strPrefix(command, "autofix") ? AUTOPLAY_MODE_FIX :
+ AUTOPLAY_MODE_NONE);
+
+ 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++;
+ }
+
+ if (global.autoplay_mode & AUTOPLAY_WARP_NO_DISPLAY)
+ program.headless = TRUE;
+ }
+ else if (strPrefix(command, "patch tapes "))
+ {
+ char *str_ptr = getStringCopy(&command[12]); // read command parameters
+
+ // skip leading whitespace
+ while (*str_ptr == ' ' || *str_ptr == '\t')
+ str_ptr++;
+
+ if (*str_ptr == '\0')
+ Fail("cannot find MODE in command '%s'", command);
+
+ global.patchtapes_mode = str_ptr; // store patch mode
+
+ // advance to next whitespace (or end of string)
+ while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
+ str_ptr++;
+
+ 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.patchtapes_leveldir == NULL) // read level set string
+ {
+ global.patchtapes_leveldir = str_ptr;
+ global.patchtapes_all = TRUE; // default: patch all tapes
+
+ for (i = 0; i < MAX_TAPES_PER_SET; i++)
+ global.patchtapes_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.patchtapes_level[level_nr] = TRUE;
+
+ global.patchtapes_all = FALSE;
+ }
+
+ // advance string pointer to the next whitespace (or end of string)
+ while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
+ str_ptr++;
+ }
+
+ if (global.patchtapes_leveldir == NULL)
+ {
+ if (strEqual(global.patchtapes_mode, "help"))
+ global.patchtapes_leveldir = UNDEFINED_LEVELSET;
+ else
+ Fail("cannot find LEVELDIR in command '%s'", command);
+ }
+
+ program.headless = TRUE;
+ }
+ 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
+ }
+
+ program.headless = TRUE;
+ }
+ else if (strPrefix(command, "create images "))
+ {
+ global.create_images_dir = getStringCopy(&command[14]);
+
+ if (access(global.create_images_dir, W_OK) != 0)
+ Fail("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);
+ }
+ else
+ {
+ FailWithHelp("unrecognized command '%s'", command);
+ }
+
+ // disable networking if any valid command was recognized
+ options.network = setup.network_mode = FALSE;
+}
+
+static void InitSetup(void)
+{
+ LoadUserNames(); // global user names
+ LoadUserSetup(); // global user number
+
+ LoadSetup(); // global setup info
+ LoadSetup_AutoSetup(); // global auto setup info
+
+ // set some options from setup file
+
+ if (setup.options.verbose)
+ options.verbose = TRUE;
+
+ if (setup.debug.show_frames_per_second)
+ global.show_frames_per_second = TRUE;
+}
+
+static void InitGameInfo(void)
+{
+ game.restart_level = FALSE;
+ game.restart_game_message = NULL;
+ game.request_active = FALSE;
+}
+
+static void InitPlayerInfo(void)
+{
+ int i;
+
+ // choose default local player
+ local_player = &stored_player[0];
+
+ for (i = 0; i < MAX_PLAYERS; i++)
+ {
+ stored_player[i].connected_locally = FALSE;
+ stored_player[i].connected_network = FALSE;
+ }
+
+ local_player->connected_locally = TRUE;
+}
+
+static void InitArtworkInfo(void)
+{
+ 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(void)
+{
+ static char *image_id_prefix[MAX_NUM_ELEMENTS +
+ NUM_FONTS +
+ NUM_GLOBAL_ANIM_TOKENS + 1];
+ static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS +
+ NUM_GLOBAL_ANIM_TOKENS + 1];
+ static char *music_id_prefix[NUM_MUSIC_PREFIXES +
+ NUM_GLOBAL_ANIM_TOKENS + 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",
+ "program_title",
+ "program_copyright",
+ "program_company",
+
+ 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);
+ for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
+ sound_id_prefix[2 * MAX_NUM_ELEMENTS + i] =
+ global_anim_info[i].token_name;
+ sound_id_prefix[2 * MAX_NUM_ELEMENTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
+
+ for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
+ music_id_prefix[i] = music_prefix_info[i].prefix;
+ for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
+ music_id_prefix[NUM_MUSIC_PREFIXES + i] =
+ global_anim_info[i].token_name;
+ music_id_prefix[NUM_MUSIC_PREFIXES + NUM_GLOBAL_ANIM_TOKENS] = 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, action_id_suffix, special_id_suffix,
+ level_id_suffix, ignore_music_tokens);
+}
+
+static void InitMixer(void)
+{
+ OpenAudio();
+
+ StartMixer();
+}
+
+static void InitVideoOverlay(void)
+{
+ // if virtual buttons are not loaded from setup file, repeat initializing
+ // virtual buttons grid with default values now that video is initialized
+ if (!setup.touch.grid_initialized)
+ InitSetup();
+
+ InitTileCursorInfo();
+ InitOverlayInfo();
+}
+
+void InitGfxBuffers(void)
+{
+ 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)
+ {
+ // used to temporarily store the backbuffer -- only re-create if changed
+ ReCreateBitmap(&bitmap_db_store_1, WIN_XSIZE, WIN_YSIZE);
+ ReCreateBitmap(&bitmap_db_store_2, WIN_XSIZE, WIN_YSIZE);
+
+ win_xsize_last = WIN_XSIZE;
+ win_ysize_last = WIN_YSIZE;
+ }
+
+ ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE);
+ ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE);
+ ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE);
+ ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE);
+
+ // 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();
+}
+
+static void InitGfx(void)
+{
+ struct GraphicInfo *graphic_info_last = graphic_info;
+ char *filename_font_initial = NULL;
+ char *filename_anim_initial = NULL;
+ Bitmap *bitmap_font_initial = NULL;
+ 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
+ Fail("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();
+
+ DrawProgramInfo();
+
+ 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
+ Fail("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(DrawGlobalAnimations);
+ InitGfxDrawGlobalBorderFunction(DrawMaskedBorderToTarget);
+ InitGfxDrawTileCursorFunction(DrawTileCursor);
+
+ gfx.fade_border_source_status = global.border_status;
+ gfx.fade_border_target_status = global.border_status;
+ gfx.masked_border_bitmap_ptr = backbuffer;
+
+ // use copy of busy animation to prevent change while reloading artwork
+ init_last = init;
+}
+
+static void InitGfxBackground(void)
+{
+ fieldbuffer = bitmap_db_field;
+ SetDrawtoField(DRAW_TO_BACKBUFFER);
+
+ ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
+
+ redraw_mask = REDRAW_ALL;
+}
+
+static void InitLevelInfo(void)
+{
+ LoadLevelInfo(); // global level info
+ LoadLevelSetup_LastSeries(); // last played series info
+ LoadLevelSetup_SeriesInfo(); // last played level info
+
+ if (global.autoplay_leveldir &&
+ global.autoplay_mode != AUTOPLAY_MODE_TEST)
+ {
+ leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
+ global.autoplay_leveldir);
+ if (leveldir_current == NULL)
+ leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
+ }
+
+ SetLevelSetInfo(leveldir_current->identifier, level_nr);
+}
+
+static void InitLevelArtworkInfo(void)
+{
+ LoadLevelArtworkInfo();
+}
+
+static void InitImages(void)
+{
+ print_timestamp_init("InitImages");
+
+#if 0
+ Debug("init:InitImages", "leveldir_current->identifier == '%s'",
+ leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
+ Debug("init:InitImages", "leveldir_current->graphics_path == '%s'",
+ leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
+ Debug("init:InitImages", "leveldir_current->graphics_set == '%s'",
+ leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
+ Debug("init:InitImages", "getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'",
+ leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
+#endif
+
+ setLevelArtworkDir(artwork.gfx_first);
+
+#if 0
+ Debug("init:InitImages", "leveldir_current->identifier == '%s'",
+ leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
+ Debug("init:InitImages", "leveldir_current->graphics_path == '%s'",
+ leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
+ Debug("init:InitImages", "leveldir_current->graphics_set == '%s'",
+ leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
+ Debug("init:InitImages", "getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'",
+ leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
+#endif
+
+#if 0
+ Debug("init:InitImages", "InitImages for '%s' ['%s', '%s'] ['%s', '%s']",
+ 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");
+
+ LoadMenuDesignSettings_AfterGraphics();
+ print_timestamp_time("LoadMenuDesignSettings_AfterGraphics");
+
+ 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");
+}
+
+static void InitArtworkDone(void)
+{
+ if (program.headless)
+ return;
+
+ InitGlobalAnimations();
+}
+
+static void InitNetworkSettings(void)
+{
+ boolean network_enabled = (options.network || setup.network_mode);
+ char *network_server = (options.server_host != NULL ? options.server_host :
+ setup.network_server_hostname);
+
+ if (strEqual(network_server, STR_NETWORK_AUTO_DETECT))
+ network_server = NULL;
+
+ InitNetworkInfo(network_enabled,
+ FALSE,
+ options.serveronly,
+ network_server,
+ options.server_port);
+}
+
+void InitNetworkServer(void)
+{
+ if (!network.enabled || network.connected)
+ return;
+
+ LimitScreenUpdates(FALSE);
+
+ if (game_status == GAME_MODE_LOADING)
+ DrawProgramInfo();
+
+ if (!ConnectToServer(network.server_host, network.server_port))
+ {
+ network.enabled = FALSE;
+
+ setup.network_mode = FALSE;
+ }
+ else
+ {
+ SendToServer_ProtocolVersion();
+ SendToServer_PlayerName(setup.player_name);
+ SendToServer_NrWanted(setup.network_player_nr + 1);
+
+ network.connected = TRUE;
+ }
+
+ // short time to recognize result of network initialization
+ if (game_status == GAME_MODE_LOADING)
+ Delay_WithScreenUpdates(1000);
+}
+
+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
+ Debug("init:CheckArtworkTypeForRedefinedCustomElements",
+ "leveldir_current->identifier == '%s'",
+ leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
+ Debug("init:CheckArtworkTypeForRedefinedCustomElements",
+ "leveldir_current->graphics_path == '%s'",
+ leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
+ Debug("init:CheckArtworkTypeForRedefinedCustomElements",
+ "leveldir_current->graphics_set == '%s'",
+ leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
+ Debug("init:CheckArtworkTypeForRedefinedCustomElements",
+ "getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'",
+ 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
+ Debug("init:CheckArtworkTypeForRedefinedCustomElements",
+ "filename_base == '%s'", filename_base);
+#endif
+
+ if (fileExists(filename_base))
+ redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
+
+ filename_local = getCustomArtworkConfigFilename(type);
+
+#if 0
+ Debug("init:CheckArtworkTypeForRedefinedCustomElements",
+ "filename_local == '%s'", filename_local);
+#endif
+
+ if (filename_local != NULL && !strEqual(filename_base, filename_local))
+ redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
+
+#if 0
+ Debug("init:CheckArtworkTypeForRedefinedCustomElements",
+ "redefined_ce_found == %d", redefined_ce_found);
+#endif
+
+ return redefined_ce_found;
+}
+
+static void InitOverrideArtwork(void)
+{
+ 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
+ Debug("init:InitOverrideArtwork", "redefined_ce_found == %d",
+ 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
+ Debug("init:InitOverrideArtwork", "%d, %d, %d",
+ gfx.override_level_graphics,
+ gfx.override_level_sounds,
+ gfx.override_level_music);
+#endif
+}
+
+static char *getNewArtworkIdentifier(int type)
+{
+ static char *last_leveldir_identifier[3] = { NULL, NULL, NULL };
+ static char *last_artwork_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 (last_leveldir_identifier[type] != leveldir_identifier &&
+ (last_has_level_artwork_set[type] || has_level_artwork_set))
+ artwork_new_identifier = artwork_current_identifier;
+
+ last_leveldir_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(last_artwork_identifier[type], artwork_current_identifier))
+ artwork_new_identifier = artwork_current_identifier;
+
+ // (we cannot compare string pointers here, so copy string content itself)
+ setString(&last_artwork_identifier[type], 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();
+
+ AdjustGraphicsForEMC();
+ AdjustSoundsForEMC();
+
+ 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");
+
+ SetGameStatus(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
+ Debug("init:ReloadCustomArtwork",
+ "RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']",
+ 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");
+ }
+
+ InitArtworkDone();
+
+ SetGameStatus(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(void)
+{
+ if (global.autoplay_leveldir == NULL)
+ KeyboardAutoRepeatOff();
+}
+
+void DisplayExitMessage(char *format, va_list ap)
+{
+ // also check for initialized video (headless flag may be temporarily unset)
+ if (program.headless || !video.initialized)
+ return;
+
+ // 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(void)
+{
+ print_timestamp_init("OpenAll");
+
+ SetGameStatus(GAME_MODE_LOADING);
+
+ InitCounter();
+
+ InitGlobal(); // initialize some global variables
+
+ print_timestamp_time("[init global stuff]");
+
+ InitSetup();
+
+ print_timestamp_time("[init setup/config stuff (1)]");
+
+ InitScoresInfo();
+
+ if (options.execute_command)
+ Execute_Command(options.execute_command);
+
+ InitNetworkSettings();
+
+ InitRuntimeInfo();
+
+ if (network.serveronly)
+ {
+#if defined(PLATFORM_UNIX)
+ NetworkServer(network.server_port, TRUE);
+#else
+ 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]");
+
+ InitVideoDefaults();
+ InitVideoDisplay();
+ InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
+ InitVideoOverlay();
+
+ InitEventFilter(FilterMouseMotionEvents);
+
+ 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");
+
+ InitArtworkDone();
+
+ InitGfxBackground();
+
+ em_open_all();
+ sp_open_all();
+ mm_open_all();
+
+ if (global.autoplay_leveldir)
+ {
+ AutoPlayTapes();
+ return;
+ }
+ else if (global.patchtapes_leveldir)
+ {
+ PatchTapes();
+ return;
+ }
+ else if (global.convert_leveldir)
+ {
+ ConvertLevels();
+ return;
+ }
+ else if (global.create_images_dir)
+ {
+ CreateLevelSketchImages();
+ return;
+ }
+
+ InitNetworkServer();
+
+ SetGameStatus(GAME_MODE_MAIN);
+
+ FadeSetEnterScreen();
+ if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
+ FadeSkipNextFadeOut();
+
+ print_timestamp_time("[post-artwork]");
+
+ print_timestamp_done("OpenAll");
+
+ DrawMainMenu();
+
+#if 0
+ Debug("internal:path", "SDL_GetBasePath() == '%s'",
+ SDL_GetBasePath());
+ Debug("internal:path", "SDL_GetPrefPath() == '%s'",
+ SDL_GetPrefPath("artsoft", "rocksndiamonds"));
+#if defined(PLATFORM_ANDROID)
+ Debug("internal:path", "SDL_AndroidGetInternalStoragePath() == '%s'",
+ SDL_AndroidGetInternalStoragePath());
+ Debug("internal:path", "SDL_AndroidGetExternalStoragePath() == '%s'",
+ SDL_AndroidGetExternalStoragePath());
+ Debug("internal:path", "SDL_AndroidGetExternalStorageState() == '%s'",
+ (SDL_AndroidGetExternalStorageState() &
+ SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "writable" :
+ SDL_AndroidGetExternalStorageState() &
+ SDL_ANDROID_EXTERNAL_STORAGE_READ ? "readable" : "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();
+
+ // !!! TODO !!!
+ // set a flag to tell the network server thread to quit and wait for it
+ // using SDL_WaitThread()
+ //
+ // Code used with SDL 1.2:
+ // if (network.server_thread) // terminate network server
+ // SDL_KillThread(network.server_thread);
+
+ CloseVideoDisplay();
+ ClosePlatformDependentStuff();
+
+ if (exit_value != 0 && !options.execute_command)
+ {
+ // 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
+ }