+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;
+}
+
+#if 0
+static char *get_element_class_token(int element)
+{
+ char *element_class_name = element_info[element].class_name;
+ char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
+
+ sprintf(element_class_token, "[%s]", element_class_name);
+
+ return element_class_token;
+}
+
+static char *get_action_class_token(int action)
+{
+ char *action_class_name = &element_action_info[action].suffix[1];
+ char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
+
+ sprintf(action_class_token, "[%s]", action_class_name);
+
+ return action_class_token;
+}
+#endif
+
+static void InitArtworkConfig()
+{
+ static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 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 + 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;
+ image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = 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[MAX_LEVELS] = 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; i++)
+ direction_id_suffix[i] = element_direction_info[i].suffix;
+ direction_id_suffix[NUM_DIRECTIONS] = 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 InitGfx()
+{
+ char *filename_font_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 (strcmp(image_config[i].token, font_token) == 0)
+ 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 (strcmp(&image_config[i].token[len_font_token], ".x") == 0)
+ font_initial[j].src_x = atoi(image_config[i].value);
+ else if (strcmp(&image_config[i].token[len_font_token], ".y") == 0)
+ font_initial[j].src_y = atoi(image_config[i].value);
+ else if (strcmp(&image_config[i].token[len_font_token], ".width") == 0)
+ font_initial[j].width = atoi(image_config[i].value);
+ else if (strcmp(&image_config[i].token[len_font_token],".height") == 0)
+ 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);
+
+ /* create additional image buffers for double-buffering */
+ bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
+ bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, 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);
+ InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
+
+ bitmap_font_initial = LoadCustomImage(filename_font_initial);
+
+ for (j = 0; j < NUM_INITIAL_FONTS; j++)
+ font_initial[j].bitmap = bitmap_font_initial;
+
+ InitFontGraphicInfo();
+
+ DrawInitText(getProgramInitString(), 20, FC_YELLOW);
+ DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
+
+ DrawInitText("Loading graphics:", 120, FC_GREEN);
+
+ InitTileClipmasks();
+}
+
+void InitGfxBackground()
+{
+ int x, y;
+
+ drawto = backbuffer;
+ fieldbuffer = bitmap_db_field;
+ SetDrawtoField(DRAW_BACKBUFFER);
+
+ BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
+ 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
+ ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
+ ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
+
+ for (x = 0; x < MAX_BUF_XSIZE; x++)
+ for (y = 0; y < MAX_BUF_YSIZE; y++)
+ redraw[x][y] = 0;
+ redraw_tiles = 0;
+ redraw_mask = REDRAW_ALL;
+}
+
+static void InitLevelInfo()
+{
+ LoadLevelInfo(); /* global level info */
+ LoadLevelSetup_LastSeries(); /* last played series info */
+ LoadLevelSetup_SeriesInfo(); /* last played level info */
+}
+
+void InitLevelArtworkInfo()
+{
+ LoadLevelArtworkInfo();
+}
+
+static void InitImages()
+{
+#if 1
+ setLevelArtworkDir(artwork.gfx_first);
+#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
+
+ ReloadCustomImages();
+
+ LoadCustomElementDescriptions();
+ LoadSpecialMenuDesignSettings();
+
+ ReinitializeGraphics();
+}
+
+static void InitSound(char *identifier)
+{
+ if (identifier == NULL)
+ identifier = artwork.snd_current->identifier;
+
+#if 1
+ /* set artwork path to send it to the sound server process */
+ setLevelArtworkDir(artwork.snd_first);
+#endif
+
+ InitReloadCustomSounds(identifier);
+ ReinitializeSounds();
+}
+
+static void InitMusic(char *identifier)
+{
+ if (identifier == NULL)
+ identifier = artwork.mus_current->identifier;
+
+#if 1
+ /* set artwork path to send it to the sound server process */
+ setLevelArtworkDir(artwork.mus_first);
+#endif
+
+ InitReloadCustomMusic(identifier);
+ ReinitializeMusic();
+}
+
+void InitNetworkServer()
+{
+#if defined(PLATFORM_UNIX)
+ int nr_wanted;
+#endif
+
+ if (!options.network)
+ return;
+
+#if defined(PLATFORM_UNIX)
+ 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 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 = SETUP_OVERRIDE_ARTWORK(setup, type);
+ char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
+ char *leveldir_identifier = leveldir_current->identifier;
+#if 1
+ /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
+ char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
+#else
+ char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
+#endif
+ 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
+ ------------------------------------------------------------ */
+
+#if 0
+ if (type == ARTWORK_TYPE_GRAPHICS)
+ printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
+ artwork_new_identifier,
+ ARTWORK_CURRENT_IDENTIFIER(artwork, type),
+ artwork_current_identifier,
+ leveldir_current->graphics_set,
+ leveldir_current->identifier);
+#endif
+
+ /* ---------- 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;
+
+#if 0
+ if (type == ARTWORK_TYPE_GRAPHICS)
+ printf("::: 1: '%s'\n", artwork_new_identifier);
+#endif
+
+ /* ---------- 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;
+
+#if 0
+ if (type == ARTWORK_TYPE_GRAPHICS)
+ printf("::: 2: '%s'\n", artwork_new_identifier);
+#endif
+
+ /* ---------- reload if current artwork identifier has changed ----------- */
+ if (strcmp(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
+ artwork_current_identifier) != 0)
+ artwork_new_identifier = artwork_current_identifier;
+
+ *(&(ARTWORK_CURRENT_IDENTIFIER(artwork, type))) = artwork_current_identifier;
+
+#if 0
+ if (type == ARTWORK_TYPE_GRAPHICS)
+ printf("::: 3: '%s'\n", artwork_new_identifier);
+#endif
+
+ /* ---------- do not reload directly after starting ---------------------- */
+ if (!initialized[type])
+ artwork_new_identifier = NULL;
+
+ initialized[type] = TRUE;
+
+#if 0
+ if (type == ARTWORK_TYPE_GRAPHICS)
+ printf("::: 4: '%s'\n", artwork_new_identifier);
+#endif
+
+#if 0
+ if (type == ARTWORK_TYPE_GRAPHICS)
+ printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
+ artwork.gfx_current_identifier, artwork_current_identifier,
+ artwork.gfx_current->identifier, leveldir_current->graphics_set,
+ artwork_new_identifier);
+#endif
+
+ return artwork_new_identifier;
+}
+
+void ReloadCustomArtwork()
+{
+ char *gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
+ char *snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
+ char *mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
+ boolean redraw_screen = FALSE;
+
+ if (gfx_new_identifier != NULL)
+ {
+#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
+
+ ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
+
+ InitImages();
+
+#if 0
+ printf("... '%s'\n",
+ leveldir_current->graphics_set);
+#endif
+
+ FreeTileClipmasks();
+ InitTileClipmasks();
+
+ redraw_screen = TRUE;
+ }
+
+ if (snd_new_identifier != NULL)
+ {
+ ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
+
+ InitSound(snd_new_identifier);
+
+ redraw_screen = TRUE;
+ }
+
+ if (mus_new_identifier != NULL)
+ {
+ ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
+
+ InitMusic(mus_new_identifier);
+
+ redraw_screen = TRUE;
+ }
+
+ if (redraw_screen)
+ {
+ InitGfxBackground();
+
+ /* force redraw of (open or closed) door graphics */
+ SetDoorState(DOOR_OPEN_ALL);
+ CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
+ }
+}
+
+void KeyboardAutoRepeatOffUnlessAutoplay()
+{
+ if (global.autoplay_leveldir == NULL)
+ KeyboardAutoRepeatOff();
+}
+
+
+/* ========================================================================= */
+/* OpenAll() */
+/* ========================================================================= */
+
+void OpenAll()
+{
+ InitGlobal(); /* initialize some global variables */
+
+ 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 */
+ }
+
+ InitSetup();
+
+ InitPlayerInfo();
+ InitArtworkInfo(); /* needed before loading gfx, sound & music */
+ InitArtworkConfig(); /* needed before forking sound child process */
+ InitMixer();
+
+ InitCounter();
+
+ InitRND(NEW_RANDOMIZE);
+ InitSimpleRND(NEW_RANDOMIZE);
+
+ InitJoysticks();
+
+ InitVideoDisplay();
+ InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
+ setup.fullscreen);
+
+ InitEventFilter(FilterMouseMotionEvents);
+
+ InitElementPropertiesStatic();
+ InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
+
+ InitGfx();
+
+ InitLevelInfo();
+ InitLevelArtworkInfo();
+
+ InitImages(); /* needs to know current level directory */
+ InitSound(NULL); /* needs to know current level directory */
+ InitMusic(NULL); /* needs to know current level directory */
+
+ InitGfxBackground();
+
+ if (global.autoplay_leveldir)
+ {
+ AutoPlayTape();
+ return;
+ }
+
+ game_status = GAME_MODE_MAIN;
+
+ DrawMainMenu();
+
+ InitNetworkServer();
+}
+
+void CloseAllAndExit(int exit_value)
+{
+ StopSounds();
+ FreeAllSounds();
+ FreeAllMusic();
+ CloseAudio(); /* called after freeing sounds (needed for SDL) */
+
+ FreeAllImages();
+ FreeTileClipmasks();