+ music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
+
+ for (i = 0; i < num_music; i++)
+ {
+ struct FileInfo *music = getMusicListEntry(i);
+ int len_music_text = strlen(music->token);
+
+ music_info[i].loop = TRUE; // default: play music in loop mode
+
+ // determine all loop music
+
+ for (j = 0; music_prefix_info[j].prefix; j++)
+ {
+ int len_prefix_text = strlen(music_prefix_info[j].prefix);
+
+ if (len_prefix_text < len_music_text &&
+ strncmp(music->token,
+ music_prefix_info[j].prefix, len_prefix_text) == 0)
+ {
+ music_info[i].loop = music_prefix_info[j].is_loop_music;
+
+ break;
+ }
+ }
+
+ set_music_parameters(i, music->parameter);
+ }
+}
+
+static void ReinitializeGraphics(void)
+{
+ print_timestamp_init("ReinitializeGraphics");
+
+ InitGfxTileSizeInfo(game.tile_size, TILESIZE);
+
+ InitGraphicInfo(); // graphic properties mapping
+ print_timestamp_time("InitGraphicInfo");
+ InitElementGraphicInfo(); // element game graphic mapping
+ print_timestamp_time("InitElementGraphicInfo");
+ InitElementSpecialGraphicInfo(); // element special graphic mapping
+ print_timestamp_time("InitElementSpecialGraphicInfo");
+
+ InitElementSmallImages(); // scale elements to all needed sizes
+ print_timestamp_time("InitElementSmallImages");
+ InitScaledImages(); // scale all other images, if needed
+ print_timestamp_time("InitScaledImages");
+ InitBitmapPointers(); // set standard size bitmap pointers
+ print_timestamp_time("InitBitmapPointers");
+ InitFontGraphicInfo(); // initialize text drawing functions
+ print_timestamp_time("InitFontGraphicInfo");
+ InitGlobalAnimGraphicInfo(); // initialize global animation config
+ print_timestamp_time("InitGlobalAnimGraphicInfo");
+
+ InitImageTextures(); // create textures for certain images
+ print_timestamp_time("InitImageTextures");
+
+ InitGraphicInfo_EM(); // graphic mapping for EM engine
+ print_timestamp_time("InitGraphicInfo_EM");
+
+ InitGraphicCompatibilityInfo();
+ print_timestamp_time("InitGraphicCompatibilityInfo");
+
+ SetMainBackgroundImage(IMG_BACKGROUND);
+ print_timestamp_time("SetMainBackgroundImage");
+ SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
+ print_timestamp_time("SetDoorBackgroundImage");
+
+ InitGadgets();
+ print_timestamp_time("InitGadgets");
+ InitDoors();
+ print_timestamp_time("InitDoors");
+
+ print_timestamp_done("ReinitializeGraphics");
+}
+
+static void ReinitializeSounds(void)
+{
+ InitSoundInfo(); // sound properties mapping
+ InitElementSoundInfo(); // element game sound mapping
+ InitGameModeSoundInfo(); // game mode sound mapping
+ InitGlobalAnimSoundInfo(); // global animation sound settings
+
+ InitPlayLevelSound(); // internal game sound settings
+}
+
+static void ReinitializeMusic(void)
+{
+ InitMusicInfo(); // music properties mapping
+ InitGameModeMusicInfo(); // game mode music mapping
+ InitGlobalAnimMusicInfo(); // global animation music settings
+}
+
+static int get_special_property_bit(int element, int property_bit_nr)
+{
+ struct PropertyBitInfo
+ {
+ int element;
+ int bit_nr;
+ };
+
+ static struct PropertyBitInfo pb_can_move_into_acid[] =
+ {
+ // the player may be able fall into acid when gravity is activated
+ { EL_PLAYER_1, 0 },
+ { EL_PLAYER_2, 0 },
+ { EL_PLAYER_3, 0 },
+ { EL_PLAYER_4, 0 },
+ { EL_SP_MURPHY, 0 },
+ { EL_SOKOBAN_FIELD_PLAYER, 0 },
+
+ // all elements that can move may be able to also move into acid
+ { EL_BUG, 1 },
+ { EL_BUG_LEFT, 1 },
+ { EL_BUG_RIGHT, 1 },
+ { EL_BUG_UP, 1 },
+ { EL_BUG_DOWN, 1 },
+ { EL_SPACESHIP, 2 },
+ { EL_SPACESHIP_LEFT, 2 },
+ { EL_SPACESHIP_RIGHT, 2 },
+ { EL_SPACESHIP_UP, 2 },
+ { EL_SPACESHIP_DOWN, 2 },
+ { EL_BD_BUTTERFLY, 3 },
+ { EL_BD_BUTTERFLY_LEFT, 3 },
+ { EL_BD_BUTTERFLY_RIGHT, 3 },
+ { EL_BD_BUTTERFLY_UP, 3 },
+ { EL_BD_BUTTERFLY_DOWN, 3 },
+ { EL_BD_FIREFLY, 4 },
+ { EL_BD_FIREFLY_LEFT, 4 },
+ { EL_BD_FIREFLY_RIGHT, 4 },
+ { EL_BD_FIREFLY_UP, 4 },
+ { EL_BD_FIREFLY_DOWN, 4 },
+ { EL_YAMYAM, 5 },
+ { EL_YAMYAM_LEFT, 5 },
+ { EL_YAMYAM_RIGHT, 5 },
+ { EL_YAMYAM_UP, 5 },
+ { EL_YAMYAM_DOWN, 5 },
+ { EL_DARK_YAMYAM, 6 },
+ { EL_ROBOT, 7 },
+ { EL_PACMAN, 8 },
+ { EL_PACMAN_LEFT, 8 },
+ { EL_PACMAN_RIGHT, 8 },
+ { EL_PACMAN_UP, 8 },
+ { EL_PACMAN_DOWN, 8 },
+ { EL_MOLE, 9 },
+ { EL_MOLE_LEFT, 9 },
+ { EL_MOLE_RIGHT, 9 },
+ { EL_MOLE_UP, 9 },
+ { EL_MOLE_DOWN, 9 },
+ { EL_PENGUIN, 10 },
+ { EL_PIG, 11 },
+ { EL_DRAGON, 12 },
+ { EL_SATELLITE, 13 },
+ { EL_SP_SNIKSNAK, 14 },
+ { EL_SP_ELECTRON, 15 },
+ { EL_BALLOON, 16 },
+ { EL_SPRING, 17 },
+ { EL_SPRING_LEFT, 17 },
+ { EL_SPRING_RIGHT, 17 },
+ { EL_EMC_ANDROID, 18 },
+
+ { -1, -1 },
+ };
+
+ static struct PropertyBitInfo pb_dont_collide_with[] =
+ {
+ { EL_SP_SNIKSNAK, 0 },
+ { EL_SP_ELECTRON, 1 },
+
+ { -1, -1 },
+ };
+
+ static struct
+ {
+ int bit_nr;
+ struct PropertyBitInfo *pb_info;
+ } pb_definition[] =
+ {
+ { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
+ { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
+
+ { -1, NULL },
+ };
+
+ struct PropertyBitInfo *pb_info = NULL;
+ int i;
+
+ for (i = 0; pb_definition[i].bit_nr != -1; i++)
+ if (pb_definition[i].bit_nr == property_bit_nr)
+ pb_info = pb_definition[i].pb_info;
+
+ if (pb_info == NULL)
+ return -1;
+
+ for (i = 0; pb_info[i].element != -1; i++)
+ if (pb_info[i].element == element)
+ return pb_info[i].bit_nr;
+
+ return -1;
+}
+
+void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
+ boolean property_value)
+{
+ int bit_nr = get_special_property_bit(element, property_bit_nr);
+
+ if (bit_nr > -1)
+ {
+ if (property_value)
+ *bitfield |= (1 << bit_nr);
+ else
+ *bitfield &= ~(1 << bit_nr);
+ }
+}
+
+boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
+{
+ int bit_nr = get_special_property_bit(element, property_bit_nr);
+
+ if (bit_nr > -1)
+ return ((*bitfield & (1 << bit_nr)) != 0);
+
+ return FALSE;
+}
+
+static void ResolveGroupElementExt(int group_element, int recursion_depth)
+{
+ static int group_nr;
+ static struct ElementGroupInfo *group;
+ struct ElementGroupInfo *actual_group = element_info[group_element].group;
+ int i;
+
+ if (actual_group == NULL) // not yet initialized
+ return;
+
+ if (recursion_depth > NUM_GROUP_ELEMENTS) // recursion too deep
+ {
+ Warn("recursion too deep when resolving group element %d",
+ group_element - EL_GROUP_START + 1);
+
+ // replace element which caused too deep recursion by question mark
+ group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
+
+ return;
+ }
+
+ if (recursion_depth == 0) // initialization
+ {
+ group = actual_group;
+ group_nr = GROUP_NR(group_element);
+
+ group->num_elements_resolved = 0;
+ group->choice_pos = 0;
+
+ for (i = 0; i < MAX_NUM_ELEMENTS; i++)
+ element_info[i].in_group[group_nr] = FALSE;
+ }
+
+ for (i = 0; i < actual_group->num_elements; i++)
+ {
+ int element = actual_group->element[i];
+
+ if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
+ break;
+
+ if (IS_GROUP_ELEMENT(element))
+ ResolveGroupElementExt(element, recursion_depth + 1);
+ else
+ {
+ group->element_resolved[group->num_elements_resolved++] = element;
+ element_info[element].in_group[group_nr] = TRUE;
+ }
+ }