1 // ============================================================================
2 // Rocks'n'Diamonds - McDuffin Strikes Back!
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
7 // http://www.artsoft.org/
8 // ----------------------------------------------------------------------------
10 // ============================================================================
12 #include "libgame/libgame.h"
27 #include "conf_e2g.c" /* include auto-generated data structure definitions */
28 #include "conf_esg.c" /* include auto-generated data structure definitions */
29 #include "conf_e2s.c" /* include auto-generated data structure definitions */
30 #include "conf_fnt.c" /* include auto-generated data structure definitions */
31 #include "conf_g2s.c" /* include auto-generated data structure definitions */
32 #include "conf_g2m.c" /* include auto-generated data structure definitions */
33 #include "conf_act.c" /* include auto-generated data structure definitions */
36 #define CONFIG_TOKEN_FONT_INITIAL "font.initial"
37 #define CONFIG_TOKEN_GLOBAL_BUSY "global.busy"
40 static struct FontBitmapInfo font_initial[NUM_INITIAL_FONTS];
41 static struct GraphicInfo anim_initial;
43 static int copy_properties[][5] =
47 EL_BUG_LEFT, EL_BUG_RIGHT,
48 EL_BUG_UP, EL_BUG_DOWN
52 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
53 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
57 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
58 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
62 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
63 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
67 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
68 EL_PACMAN_UP, EL_PACMAN_DOWN
72 EL_YAMYAM_LEFT, EL_YAMYAM_RIGHT,
73 EL_YAMYAM_UP, EL_YAMYAM_DOWN
77 EL_MOLE_LEFT, EL_MOLE_RIGHT,
78 EL_MOLE_UP, EL_MOLE_DOWN
89 struct GraphicInfo *graphic_info_last = graphic_info;
91 static unsigned int action_delay = 0;
92 unsigned int action_delay_value = GameFrameDelay;
93 int sync_frame = FrameCounter;
96 if (game_status != GAME_MODE_LOADING)
99 if (anim_initial.bitmap == NULL || window == NULL)
102 if (!DelayReached(&action_delay, action_delay_value))
105 x = ALIGNED_TEXT_XPOS(&init_last.busy);
106 y = ALIGNED_TEXT_YPOS(&init_last.busy);
108 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
110 if (sync_frame % anim_initial.anim_delay == 0)
114 int width = graphic_info[graphic].width;
115 int height = graphic_info[graphic].height;
116 int frame = getGraphicAnimationFrame(graphic, sync_frame);
118 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
119 BlitBitmap(src_bitmap, window, src_x, src_y, width, height, x, y);
122 graphic_info = graphic_info_last;
129 FreeLevelEditorGadgets();
138 static boolean gadgets_initialized = FALSE;
140 if (gadgets_initialized)
143 CreateLevelEditorGadgets();
147 CreateScreenGadgets();
149 InitGadgetsSoundCallback(PlaySoundActivating, PlaySoundSelecting);
151 gadgets_initialized = TRUE;
154 inline static void InitElementSmallImagesScaledUp(int graphic)
156 struct GraphicInfo *g = &graphic_info[graphic];
158 // create small and game tile sized bitmaps (and scale up, if needed)
159 CreateImageWithSmallImages(graphic, g->scale_up_factor, g->tile_size);
162 void InitElementSmallImages()
164 print_timestamp_init("InitElementSmallImages");
166 static int special_graphics[] =
168 IMG_EDITOR_ELEMENT_BORDER,
169 IMG_EDITOR_ELEMENT_BORDER_INPUT,
170 IMG_EDITOR_CASCADE_LIST,
171 IMG_EDITOR_CASCADE_LIST_ACTIVE,
174 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
175 int num_property_mappings = getImageListPropertyMappingSize();
178 print_timestamp_time("getImageListPropertyMapping/Size");
180 print_timestamp_init("InitElementSmallImagesScaledUp (1)");
181 /* initialize normal images from static configuration */
182 for (i = 0; element_to_graphic[i].element > -1; i++)
183 InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
184 print_timestamp_done("InitElementSmallImagesScaledUp (1)");
186 /* initialize special images from static configuration */
187 for (i = 0; element_to_special_graphic[i].element > -1; i++)
188 InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
189 print_timestamp_time("InitElementSmallImagesScaledUp (2)");
191 /* initialize images from dynamic configuration (may be elements or other) */
192 for (i = 0; i < num_property_mappings; i++)
193 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
194 print_timestamp_time("InitElementSmallImagesScaledUp (3)");
196 /* initialize special images from above list (non-element images) */
197 for (i = 0; special_graphics[i] > -1; i++)
198 InitElementSmallImagesScaledUp(special_graphics[i]);
199 print_timestamp_time("InitElementSmallImagesScaledUp (4)");
201 print_timestamp_done("InitElementSmallImages");
204 void InitScaledImages()
208 /* scale normal images from static configuration, if not already scaled */
209 for (i = 0; i < NUM_IMAGE_FILES; i++)
210 ScaleImage(i, graphic_info[i].scale_up_factor);
213 void InitBitmapPointers()
215 int num_images = getImageListSize();
218 // standard size bitmap may have changed -- update default bitmap pointer
219 for (i = 0; i < num_images; i++)
220 if (graphic_info[i].bitmaps)
221 graphic_info[i].bitmap = graphic_info[i].bitmaps[IMG_BITMAP_STANDARD];
225 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
226 void SetBitmaps_EM(Bitmap **em_bitmap)
228 em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
229 em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].bitmap;
234 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
235 void SetBitmaps_SP(Bitmap **sp_bitmap)
237 *sp_bitmap = graphic_info[IMG_SP_OBJECTS].bitmap;
241 static int getFontBitmapID(int font_nr)
245 /* (special case: do not use special font for GAME_MODE_LOADING) */
246 if (game_status >= GAME_MODE_TITLE_INITIAL &&
247 game_status <= GAME_MODE_PSEUDO_PREVIEW)
248 special = game_status;
249 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
250 special = GFX_SPECIAL_ARG_MAIN;
253 return font_info[font_nr].special_bitmap_id[special];
258 static int getFontFromToken(char *token)
260 char *value = getHashEntry(font_token_hash, token);
265 /* if font not found, use reliable default value */
266 return FONT_INITIAL_1;
269 void InitFontGraphicInfo()
271 static struct FontBitmapInfo *font_bitmap_info = NULL;
272 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
273 int num_property_mappings = getImageListPropertyMappingSize();
274 int num_font_bitmaps = NUM_FONTS;
277 if (graphic_info == NULL) /* still at startup phase */
279 InitFontInfo(font_initial, NUM_INITIAL_FONTS,
280 getFontBitmapID, getFontFromToken);
285 /* ---------- initialize font graphic definitions ---------- */
287 /* always start with reliable default values (normal font graphics) */
288 for (i = 0; i < NUM_FONTS; i++)
289 font_info[i].graphic = IMG_FONT_INITIAL_1;
291 /* initialize normal font/graphic mapping from static configuration */
292 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
294 int font_nr = font_to_graphic[i].font_nr;
295 int special = font_to_graphic[i].special;
296 int graphic = font_to_graphic[i].graphic;
301 font_info[font_nr].graphic = graphic;
304 /* always start with reliable default values (special font graphics) */
305 for (i = 0; i < NUM_FONTS; i++)
307 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
309 font_info[i].special_graphic[j] = font_info[i].graphic;
310 font_info[i].special_bitmap_id[j] = i;
314 /* initialize special font/graphic mapping from static configuration */
315 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
317 int font_nr = font_to_graphic[i].font_nr;
318 int special = font_to_graphic[i].special;
319 int graphic = font_to_graphic[i].graphic;
320 int base_graphic = font2baseimg(font_nr);
322 if (IS_SPECIAL_GFX_ARG(special))
324 boolean base_redefined =
325 getImageListEntryFromImageID(base_graphic)->redefined;
326 boolean special_redefined =
327 getImageListEntryFromImageID(graphic)->redefined;
328 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
330 /* if the base font ("font.title_1", for example) has been redefined,
331 but not the special font ("font.title_1.LEVELS", for example), do not
332 use an existing (in this case considered obsolete) special font
333 anymore, but use the automatically determined default font */
334 /* special case: cloned special fonts must be explicitly redefined,
335 but are not automatically redefined by redefining base font */
336 if (base_redefined && !special_redefined && !special_cloned)
339 font_info[font_nr].special_graphic[special] = graphic;
340 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
345 /* initialize special font/graphic mapping from dynamic configuration */
346 for (i = 0; i < num_property_mappings; i++)
348 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
349 int special = property_mapping[i].ext3_index;
350 int graphic = property_mapping[i].artwork_index;
355 if (IS_SPECIAL_GFX_ARG(special))
357 font_info[font_nr].special_graphic[special] = graphic;
358 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
363 /* correct special font/graphic mapping for cloned fonts for downwards
364 compatibility of PREVIEW fonts -- this is only needed for implicit
365 redefinition of special font by redefined base font, and only if other
366 fonts are cloned from this special font (like in the "Zelda" level set) */
367 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
369 int font_nr = font_to_graphic[i].font_nr;
370 int special = font_to_graphic[i].special;
371 int graphic = font_to_graphic[i].graphic;
373 if (IS_SPECIAL_GFX_ARG(special))
375 boolean special_redefined =
376 getImageListEntryFromImageID(graphic)->redefined;
377 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
379 if (special_cloned && !special_redefined)
383 for (j = 0; font_to_graphic[j].font_nr > -1; j++)
385 int font_nr2 = font_to_graphic[j].font_nr;
386 int special2 = font_to_graphic[j].special;
387 int graphic2 = font_to_graphic[j].graphic;
389 if (IS_SPECIAL_GFX_ARG(special2) &&
390 graphic2 == graphic_info[graphic].clone_from)
392 font_info[font_nr].special_graphic[special] =
393 font_info[font_nr2].special_graphic[special2];
394 font_info[font_nr].special_bitmap_id[special] =
395 font_info[font_nr2].special_bitmap_id[special2];
402 /* reset non-redefined ".active" font graphics if normal font is redefined */
403 /* (this different treatment is needed because normal and active fonts are
404 independently defined ("active" is not a property of font definitions!) */
405 for (i = 0; i < NUM_FONTS; i++)
407 int font_nr_base = i;
408 int font_nr_active = FONT_ACTIVE(font_nr_base);
410 /* check only those fonts with exist as normal and ".active" variant */
411 if (font_nr_base != font_nr_active)
413 int base_graphic = font_info[font_nr_base].graphic;
414 int active_graphic = font_info[font_nr_active].graphic;
415 boolean base_redefined =
416 getImageListEntryFromImageID(base_graphic)->redefined;
417 boolean active_redefined =
418 getImageListEntryFromImageID(active_graphic)->redefined;
420 /* if the base font ("font.menu_1", for example) has been redefined,
421 but not the active font ("font.menu_1.active", for example), do not
422 use an existing (in this case considered obsolete) active font
423 anymore, but use the automatically determined default font */
424 if (base_redefined && !active_redefined)
425 font_info[font_nr_active].graphic = base_graphic;
427 /* now also check each "special" font (which may be the same as above) */
428 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
430 int base_graphic = font_info[font_nr_base].special_graphic[j];
431 int active_graphic = font_info[font_nr_active].special_graphic[j];
432 boolean base_redefined =
433 getImageListEntryFromImageID(base_graphic)->redefined;
434 boolean active_redefined =
435 getImageListEntryFromImageID(active_graphic)->redefined;
437 /* same as above, but check special graphic definitions, for example:
438 redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN" */
439 if (base_redefined && !active_redefined)
441 font_info[font_nr_active].special_graphic[j] =
442 font_info[font_nr_base].special_graphic[j];
443 font_info[font_nr_active].special_bitmap_id[j] =
444 font_info[font_nr_base].special_bitmap_id[j];
450 /* ---------- initialize font bitmap array ---------- */
452 if (font_bitmap_info != NULL)
453 FreeFontInfo(font_bitmap_info);
456 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
458 /* ---------- initialize font bitmap definitions ---------- */
460 for (i = 0; i < NUM_FONTS; i++)
462 if (i < NUM_INITIAL_FONTS)
464 font_bitmap_info[i] = font_initial[i];
468 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
470 int font_bitmap_id = font_info[i].special_bitmap_id[j];
471 int graphic = font_info[i].special_graphic[j];
473 /* set 'graphic_info' for font entries, if uninitialized (guessed) */
474 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
476 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
477 graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
480 /* copy font relevant information from graphics information */
481 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
482 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
483 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
484 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
485 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
487 font_bitmap_info[font_bitmap_id].draw_xoffset =
488 graphic_info[graphic].draw_xoffset;
489 font_bitmap_info[font_bitmap_id].draw_yoffset =
490 graphic_info[graphic].draw_yoffset;
492 font_bitmap_info[font_bitmap_id].num_chars =
493 graphic_info[graphic].anim_frames;
494 font_bitmap_info[font_bitmap_id].num_chars_per_line =
495 graphic_info[graphic].anim_frames_per_line;
499 InitFontInfo(font_bitmap_info, num_font_bitmaps,
500 getFontBitmapID, getFontFromToken);
503 void InitElementGraphicInfo()
505 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
506 int num_property_mappings = getImageListPropertyMappingSize();
509 if (graphic_info == NULL) /* still at startup phase */
512 /* set values to -1 to identify later as "uninitialized" values */
513 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
515 for (act = 0; act < NUM_ACTIONS; act++)
517 element_info[i].graphic[act] = -1;
518 element_info[i].crumbled[act] = -1;
520 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
522 element_info[i].direction_graphic[act][dir] = -1;
523 element_info[i].direction_crumbled[act][dir] = -1;
530 /* initialize normal element/graphic mapping from static configuration */
531 for (i = 0; element_to_graphic[i].element > -1; i++)
533 int element = element_to_graphic[i].element;
534 int action = element_to_graphic[i].action;
535 int direction = element_to_graphic[i].direction;
536 boolean crumbled = element_to_graphic[i].crumbled;
537 int graphic = element_to_graphic[i].graphic;
538 int base_graphic = el2baseimg(element);
540 if (graphic_info[graphic].bitmap == NULL)
543 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
546 boolean base_redefined =
547 getImageListEntryFromImageID(base_graphic)->redefined;
548 boolean act_dir_redefined =
549 getImageListEntryFromImageID(graphic)->redefined;
551 /* if the base graphic ("emerald", for example) has been redefined,
552 but not the action graphic ("emerald.falling", for example), do not
553 use an existing (in this case considered obsolete) action graphic
554 anymore, but use the automatically determined default graphic */
555 if (base_redefined && !act_dir_redefined)
560 action = ACTION_DEFAULT;
565 element_info[element].direction_crumbled[action][direction] = graphic;
567 element_info[element].crumbled[action] = graphic;
572 element_info[element].direction_graphic[action][direction] = graphic;
574 element_info[element].graphic[action] = graphic;
578 /* initialize normal element/graphic mapping from dynamic configuration */
579 for (i = 0; i < num_property_mappings; i++)
581 int element = property_mapping[i].base_index;
582 int action = property_mapping[i].ext1_index;
583 int direction = property_mapping[i].ext2_index;
584 int special = property_mapping[i].ext3_index;
585 int graphic = property_mapping[i].artwork_index;
586 boolean crumbled = FALSE;
588 if (special == GFX_SPECIAL_ARG_CRUMBLED)
594 if (graphic_info[graphic].bitmap == NULL)
597 if (element >= MAX_NUM_ELEMENTS || special != -1)
601 action = ACTION_DEFAULT;
606 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
607 element_info[element].direction_crumbled[action][dir] = -1;
610 element_info[element].direction_crumbled[action][direction] = graphic;
612 element_info[element].crumbled[action] = graphic;
617 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
618 element_info[element].direction_graphic[action][dir] = -1;
621 element_info[element].direction_graphic[action][direction] = graphic;
623 element_info[element].graphic[action] = graphic;
627 /* now copy all graphics that are defined to be cloned from other graphics */
628 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
630 int graphic = element_info[i].graphic[ACTION_DEFAULT];
631 int crumbled_like, diggable_like;
636 crumbled_like = graphic_info[graphic].crumbled_like;
637 diggable_like = graphic_info[graphic].diggable_like;
639 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
641 for (act = 0; act < NUM_ACTIONS; act++)
642 element_info[i].crumbled[act] =
643 element_info[crumbled_like].crumbled[act];
644 for (act = 0; act < NUM_ACTIONS; act++)
645 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
646 element_info[i].direction_crumbled[act][dir] =
647 element_info[crumbled_like].direction_crumbled[act][dir];
650 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
652 element_info[i].graphic[ACTION_DIGGING] =
653 element_info[diggable_like].graphic[ACTION_DIGGING];
654 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
655 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
656 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
660 /* set hardcoded definitions for some runtime elements without graphic */
661 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
663 /* set hardcoded definitions for some internal elements without graphic */
664 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
666 if (IS_EDITOR_CASCADE_INACTIVE(i))
667 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
668 else if (IS_EDITOR_CASCADE_ACTIVE(i))
669 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
672 /* now set all undefined/invalid graphics to -1 to set to default after it */
673 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
675 for (act = 0; act < NUM_ACTIONS; act++)
679 graphic = element_info[i].graphic[act];
680 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
681 element_info[i].graphic[act] = -1;
683 graphic = element_info[i].crumbled[act];
684 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
685 element_info[i].crumbled[act] = -1;
687 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
689 graphic = element_info[i].direction_graphic[act][dir];
690 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
691 element_info[i].direction_graphic[act][dir] = -1;
693 graphic = element_info[i].direction_crumbled[act][dir];
694 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
695 element_info[i].direction_crumbled[act][dir] = -1;
702 /* adjust graphics with 2nd tile for movement according to direction
703 (do this before correcting '-1' values to minimize calculations) */
704 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
706 for (act = 0; act < NUM_ACTIONS; act++)
708 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
710 int graphic = element_info[i].direction_graphic[act][dir];
711 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
713 if (act == ACTION_FALLING) /* special case */
714 graphic = element_info[i].graphic[act];
717 graphic_info[graphic].double_movement &&
718 graphic_info[graphic].swap_double_tiles != 0)
720 struct GraphicInfo *g = &graphic_info[graphic];
721 int src_x_front = g->src_x;
722 int src_y_front = g->src_y;
723 int src_x_back = g->src_x + g->offset2_x;
724 int src_y_back = g->src_y + g->offset2_y;
725 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
727 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
728 src_y_front < src_y_back);
729 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
730 boolean swap_movement_tiles_autodetected =
731 (!frames_are_ordered_diagonally &&
732 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
733 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
734 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
735 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
738 /* swap frontside and backside graphic tile coordinates, if needed */
739 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
741 /* get current (wrong) backside tile coordinates */
742 getFixedGraphicSourceExt(graphic, 0, &dummy,
743 &src_x_back, &src_y_back, TRUE);
745 /* set frontside tile coordinates to backside tile coordinates */
746 g->src_x = src_x_back;
747 g->src_y = src_y_back;
749 /* invert tile offset to point to new backside tile coordinates */
753 /* do not swap front and backside tiles again after correction */
754 g->swap_double_tiles = 0;
763 /* now set all '-1' values to element specific default values */
764 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
766 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
767 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
768 int default_direction_graphic[NUM_DIRECTIONS_FULL];
769 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
771 if (default_graphic == -1)
772 default_graphic = IMG_UNKNOWN;
774 if (default_crumbled == -1)
775 default_crumbled = default_graphic;
777 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
779 default_direction_graphic[dir] =
780 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
781 default_direction_crumbled[dir] =
782 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
784 if (default_direction_graphic[dir] == -1)
785 default_direction_graphic[dir] = default_graphic;
787 if (default_direction_crumbled[dir] == -1)
788 default_direction_crumbled[dir] = default_direction_graphic[dir];
791 for (act = 0; act < NUM_ACTIONS; act++)
793 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
794 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
795 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
796 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
797 act == ACTION_TURNING_FROM_RIGHT ||
798 act == ACTION_TURNING_FROM_UP ||
799 act == ACTION_TURNING_FROM_DOWN);
801 /* generic default action graphic (defined by "[default]" directive) */
802 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
803 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
804 int default_remove_graphic = IMG_EMPTY;
806 if (act_remove && default_action_graphic != -1)
807 default_remove_graphic = default_action_graphic;
809 /* look for special default action graphic (classic game specific) */
810 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
811 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
812 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
813 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
814 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
815 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
817 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
818 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
819 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
820 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
821 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
822 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
824 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
825 /* !!! make this better !!! */
826 if (i == EL_EMPTY_SPACE)
828 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
829 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
832 if (default_action_graphic == -1)
833 default_action_graphic = default_graphic;
835 if (default_action_crumbled == -1)
836 default_action_crumbled = default_action_graphic;
838 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
840 /* use action graphic as the default direction graphic, if undefined */
841 int default_action_direction_graphic = element_info[i].graphic[act];
842 int default_action_direction_crumbled = element_info[i].crumbled[act];
844 /* no graphic for current action -- use default direction graphic */
845 if (default_action_direction_graphic == -1)
846 default_action_direction_graphic =
847 (act_remove ? default_remove_graphic :
849 element_info[i].direction_graphic[ACTION_TURNING][dir] :
850 default_action_graphic != default_graphic ?
851 default_action_graphic :
852 default_direction_graphic[dir]);
854 if (element_info[i].direction_graphic[act][dir] == -1)
855 element_info[i].direction_graphic[act][dir] =
856 default_action_direction_graphic;
858 if (default_action_direction_crumbled == -1)
859 default_action_direction_crumbled =
860 element_info[i].direction_graphic[act][dir];
862 if (element_info[i].direction_crumbled[act][dir] == -1)
863 element_info[i].direction_crumbled[act][dir] =
864 default_action_direction_crumbled;
867 /* no graphic for this specific action -- use default action graphic */
868 if (element_info[i].graphic[act] == -1)
869 element_info[i].graphic[act] =
870 (act_remove ? default_remove_graphic :
871 act_turning ? element_info[i].graphic[ACTION_TURNING] :
872 default_action_graphic);
874 if (element_info[i].crumbled[act] == -1)
875 element_info[i].crumbled[act] = element_info[i].graphic[act];
882 void InitElementSpecialGraphicInfo()
884 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
885 int num_property_mappings = getImageListPropertyMappingSize();
888 /* always start with reliable default values */
889 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
890 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
891 element_info[i].special_graphic[j] =
892 element_info[i].graphic[ACTION_DEFAULT];
894 /* initialize special element/graphic mapping from static configuration */
895 for (i = 0; element_to_special_graphic[i].element > -1; i++)
897 int element = element_to_special_graphic[i].element;
898 int special = element_to_special_graphic[i].special;
899 int graphic = element_to_special_graphic[i].graphic;
900 int base_graphic = el2baseimg(element);
901 boolean base_redefined =
902 getImageListEntryFromImageID(base_graphic)->redefined;
903 boolean special_redefined =
904 getImageListEntryFromImageID(graphic)->redefined;
906 /* if the base graphic ("emerald", for example) has been redefined,
907 but not the special graphic ("emerald.EDITOR", for example), do not
908 use an existing (in this case considered obsolete) special graphic
909 anymore, but use the automatically created (down-scaled) graphic */
910 if (base_redefined && !special_redefined)
913 element_info[element].special_graphic[special] = graphic;
916 /* initialize special element/graphic mapping from dynamic configuration */
917 for (i = 0; i < num_property_mappings; i++)
919 int element = property_mapping[i].base_index;
920 int action = property_mapping[i].ext1_index;
921 int direction = property_mapping[i].ext2_index;
922 int special = property_mapping[i].ext3_index;
923 int graphic = property_mapping[i].artwork_index;
925 /* for action ".active", replace element with active element, if exists */
926 if (action == ACTION_ACTIVE && element != ELEMENT_ACTIVE(element))
928 element = ELEMENT_ACTIVE(element);
932 if (element >= MAX_NUM_ELEMENTS)
935 /* do not change special graphic if action or direction was specified */
936 if (action != -1 || direction != -1)
939 if (IS_SPECIAL_GFX_ARG(special))
940 element_info[element].special_graphic[special] = graphic;
943 /* now set all undefined/invalid graphics to default */
944 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
945 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
946 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
947 element_info[i].special_graphic[j] =
948 element_info[i].graphic[ACTION_DEFAULT];
951 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
953 if (type != TYPE_ELEMENT && type != TYPE_GRAPHIC)
954 return get_parameter_value(value_raw, suffix, type);
956 if (strEqual(value_raw, ARG_UNDEFINED))
957 return ARG_UNDEFINED_VALUE;
959 if (type == TYPE_ELEMENT)
961 char *value = getHashEntry(element_token_hash, value_raw);
965 Error(ERR_INFO_LINE, "-");
966 Error(ERR_INFO, "warning: error found in config file:");
967 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
968 Error(ERR_INFO, "error: invalid element token '%s'", value_raw);
969 Error(ERR_INFO, "custom graphic rejected for this element/action");
970 Error(ERR_INFO, "fallback done to undefined element for this graphic");
971 Error(ERR_INFO_LINE, "-");
974 return (value != NULL ? atoi(value) : EL_UNDEFINED);
976 else if (type == TYPE_GRAPHIC)
978 char *value = getHashEntry(graphic_token_hash, value_raw);
979 int fallback_graphic = IMG_CHAR_EXCLAM;
983 Error(ERR_INFO_LINE, "-");
984 Error(ERR_INFO, "warning: error found in config file:");
985 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
986 Error(ERR_INFO, "error: invalid graphic token '%s'", value_raw);
987 Error(ERR_INFO, "custom graphic rejected for this element/action");
988 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
989 Error(ERR_INFO_LINE, "-");
992 return (value != NULL ? atoi(value) : fallback_graphic);
998 static int get_scaled_graphic_width(int graphic)
1000 int original_width = getOriginalImageWidthFromImageID(graphic);
1001 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1003 return original_width * scale_up_factor;
1006 static int get_scaled_graphic_height(int graphic)
1008 int original_height = getOriginalImageHeightFromImageID(graphic);
1009 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1011 return original_height * scale_up_factor;
1014 static void set_graphic_parameters_ext(int graphic, int *parameter,
1015 Bitmap **src_bitmaps)
1017 struct GraphicInfo *g = &graphic_info[graphic];
1018 Bitmap *src_bitmap = (src_bitmaps ? src_bitmaps[IMG_BITMAP_STANDARD] : NULL);
1019 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1020 int anim_frames_per_line = 1;
1022 /* always start with reliable default values */
1023 g->src_image_width = 0;
1024 g->src_image_height = 0;
1027 g->width = TILEX; /* default for element graphics */
1028 g->height = TILEY; /* default for element graphics */
1029 g->offset_x = 0; /* one or both of these values ... */
1030 g->offset_y = 0; /* ... will be corrected later */
1031 g->offset2_x = 0; /* one or both of these values ... */
1032 g->offset2_y = 0; /* ... will be corrected later */
1033 g->swap_double_tiles = -1; /* auto-detect tile swapping */
1034 g->crumbled_like = -1; /* do not use clone element */
1035 g->diggable_like = -1; /* do not use clone element */
1036 g->border_size = TILEX / 8; /* "CRUMBLED" border size */
1037 g->scale_up_factor = 1; /* default: no scaling up */
1038 g->tile_size = TILESIZE; /* default: standard tile size */
1039 g->clone_from = -1; /* do not use clone graphic */
1040 g->anim_delay_fixed = 0;
1041 g->anim_delay_random = 0;
1042 g->post_delay_fixed = 0;
1043 g->post_delay_random = 0;
1044 g->fade_mode = FADE_MODE_DEFAULT;
1048 g->align = ALIGN_CENTER; /* default for title screens */
1049 g->valign = VALIGN_MIDDLE; /* default for title screens */
1050 g->sort_priority = 0; /* default for title screens */
1052 g->style = STYLE_DEFAULT;
1054 g->bitmaps = src_bitmaps;
1055 g->bitmap = src_bitmap;
1057 /* optional zoom factor for scaling up the image to a larger size */
1058 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1059 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1060 if (g->scale_up_factor < 1)
1061 g->scale_up_factor = 1; /* no scaling */
1063 /* optional tile size for using non-standard image size */
1064 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1066 g->tile_size = parameter[GFX_ARG_TILE_SIZE];
1069 // CHECK: should tile sizes less than standard tile size be allowed?
1070 if (g->tile_size < TILESIZE)
1071 g->tile_size = TILESIZE; /* standard tile size */
1075 // CHECK: when setting tile size, should this set width and height?
1076 g->width = g->tile_size;
1077 g->height = g->tile_size;
1081 if (g->use_image_size)
1083 /* set new default bitmap size (with scaling, but without small images) */
1084 g->width = get_scaled_graphic_width(graphic);
1085 g->height = get_scaled_graphic_height(graphic);
1088 /* optional width and height of each animation frame */
1089 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1090 g->width = parameter[GFX_ARG_WIDTH];
1091 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1092 g->height = parameter[GFX_ARG_HEIGHT];
1094 /* optional x and y tile position of animation frame sequence */
1095 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1096 g->src_x = parameter[GFX_ARG_XPOS] * g->width;
1097 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1098 g->src_y = parameter[GFX_ARG_YPOS] * g->height;
1100 /* optional x and y pixel position of animation frame sequence */
1101 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1102 g->src_x = parameter[GFX_ARG_X];
1103 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1104 g->src_y = parameter[GFX_ARG_Y];
1110 Error(ERR_INFO_LINE, "-");
1111 Error(ERR_WARN, "invalid value %d for '%s.width' (fallback done to %d)",
1112 g->width, getTokenFromImageID(graphic), TILEX);
1113 Error(ERR_INFO_LINE, "-");
1115 g->width = TILEX; /* will be checked to be inside bitmap later */
1120 Error(ERR_INFO_LINE, "-");
1121 Error(ERR_WARN, "invalid value %d for '%s.height' (fallback done to %d)",
1122 g->height, getTokenFromImageID(graphic), TILEY);
1123 Error(ERR_INFO_LINE, "-");
1125 g->height = TILEY; /* will be checked to be inside bitmap later */
1131 /* get final bitmap size (with scaling, but without small images) */
1132 int src_image_width = get_scaled_graphic_width(graphic);
1133 int src_image_height = get_scaled_graphic_height(graphic);
1135 if (src_image_width == 0 || src_image_height == 0)
1137 /* only happens when loaded outside artwork system (like "global.busy") */
1138 src_image_width = src_bitmap->width;
1139 src_image_height = src_bitmap->height;
1142 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1144 anim_frames_per_row = src_image_width / g->tile_size;
1145 anim_frames_per_col = src_image_height / g->tile_size;
1149 anim_frames_per_row = src_image_width / g->width;
1150 anim_frames_per_col = src_image_height / g->height;
1153 g->src_image_width = src_image_width;
1154 g->src_image_height = src_image_height;
1157 /* correct x or y offset dependent of vertical or horizontal frame order */
1158 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1160 g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1161 parameter[GFX_ARG_OFFSET] : g->height);
1162 anim_frames_per_line = anim_frames_per_col;
1164 else /* frames are ordered horizontally */
1166 g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1167 parameter[GFX_ARG_OFFSET] : g->width);
1168 anim_frames_per_line = anim_frames_per_row;
1171 /* optionally, the x and y offset of frames can be specified directly */
1172 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1173 g->offset_x = parameter[GFX_ARG_XOFFSET];
1174 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1175 g->offset_y = parameter[GFX_ARG_YOFFSET];
1177 /* optionally, moving animations may have separate start and end graphics */
1178 g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1180 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1181 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1183 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1184 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1185 g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1186 parameter[GFX_ARG_2ND_OFFSET] : g->height);
1187 else /* frames are ordered horizontally */
1188 g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1189 parameter[GFX_ARG_2ND_OFFSET] : g->width);
1191 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1192 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1193 g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1194 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1195 g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1197 /* optionally, the second movement tile can be specified as start tile */
1198 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1199 g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1201 /* automatically determine correct number of frames, if not defined */
1202 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1203 g->anim_frames = parameter[GFX_ARG_FRAMES];
1204 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1205 g->anim_frames = anim_frames_per_row;
1206 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1207 g->anim_frames = anim_frames_per_col;
1211 if (g->anim_frames == 0) /* frames must be at least 1 */
1214 g->anim_frames_per_line =
1215 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1216 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1218 g->anim_delay = parameter[GFX_ARG_DELAY];
1219 if (g->anim_delay == 0) /* delay must be at least 1 */
1222 g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1224 /* automatically determine correct start frame, if not defined */
1225 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1226 g->anim_start_frame = 0;
1227 else if (g->anim_mode & ANIM_REVERSE)
1228 g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1230 g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1232 /* animation synchronized with global frame counter, not move position */
1233 g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1235 /* optional element for cloning crumble graphics */
1236 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1237 g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1239 /* optional element for cloning digging graphics */
1240 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1241 g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1243 /* optional border size for "crumbling" diggable graphics */
1244 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1245 g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1247 /* this is only used for player "boring" and "sleeping" actions */
1248 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1249 g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1250 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1251 g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1252 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1253 g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1254 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1255 g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1257 /* this is only used for toon animations */
1258 g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1259 g->step_delay = parameter[GFX_ARG_STEP_DELAY];
1261 /* this is only used for drawing font characters */
1262 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1263 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1265 /* this is only used for drawing envelope graphics */
1266 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1268 /* optional graphic for cloning all graphics settings */
1269 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1270 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1272 /* optional settings for drawing title screens and title messages */
1273 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1274 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1275 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1276 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1277 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1278 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1279 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1280 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1281 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1282 g->align = parameter[GFX_ARG_ALIGN];
1283 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1284 g->valign = parameter[GFX_ARG_VALIGN];
1285 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1286 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1288 if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
1289 g->class = parameter[GFX_ARG_CLASS];
1290 if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
1291 g->style = parameter[GFX_ARG_STYLE];
1293 /* this is only used for drawing menu buttons and text */
1294 g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
1295 g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
1296 g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
1297 g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
1300 static void set_graphic_parameters(int graphic)
1302 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1303 char **parameter_raw = image->parameter;
1304 Bitmap **src_bitmaps = getBitmapsFromImageID(graphic);
1305 int parameter[NUM_GFX_ARGS];
1308 /* if fallback to default artwork is done, also use the default parameters */
1309 if (image->fallback_to_default)
1310 parameter_raw = image->default_parameter;
1312 /* get integer values from string parameters */
1313 for (i = 0; i < NUM_GFX_ARGS; i++)
1314 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1315 image_config_suffix[i].token,
1316 image_config_suffix[i].type);
1318 set_graphic_parameters_ext(graphic, parameter, src_bitmaps);
1320 UPDATE_BUSY_STATE();
1323 static void set_cloned_graphic_parameters(int graphic)
1325 int fallback_graphic = IMG_CHAR_EXCLAM;
1326 int max_num_images = getImageListSize();
1327 int clone_graphic = graphic_info[graphic].clone_from;
1328 int num_references_followed = 1;
1330 while (graphic_info[clone_graphic].clone_from != -1 &&
1331 num_references_followed < max_num_images)
1333 clone_graphic = graphic_info[clone_graphic].clone_from;
1335 num_references_followed++;
1338 if (num_references_followed >= max_num_images)
1340 Error(ERR_INFO_LINE, "-");
1341 Error(ERR_INFO, "warning: error found in config file:");
1342 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1343 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1344 Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1345 Error(ERR_INFO, "custom graphic rejected for this element/action");
1347 if (graphic == fallback_graphic)
1348 Error(ERR_EXIT, "no fallback graphic available");
1350 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1351 Error(ERR_INFO_LINE, "-");
1353 graphic_info[graphic] = graphic_info[fallback_graphic];
1357 graphic_info[graphic] = graphic_info[clone_graphic];
1358 graphic_info[graphic].clone_from = clone_graphic;
1362 static void InitGraphicInfo()
1364 int fallback_graphic = IMG_CHAR_EXCLAM;
1365 int num_images = getImageListSize();
1368 /* use image size as default values for width and height for these images */
1369 static int full_size_graphics[] =
1372 IMG_GLOBAL_BORDER_MAIN,
1373 IMG_GLOBAL_BORDER_SCORES,
1374 IMG_GLOBAL_BORDER_EDITOR,
1375 IMG_GLOBAL_BORDER_PLAYING,
1378 IMG_BACKGROUND_ENVELOPE_1,
1379 IMG_BACKGROUND_ENVELOPE_2,
1380 IMG_BACKGROUND_ENVELOPE_3,
1381 IMG_BACKGROUND_ENVELOPE_4,
1382 IMG_BACKGROUND_REQUEST,
1385 IMG_BACKGROUND_TITLE_INITIAL,
1386 IMG_BACKGROUND_TITLE,
1387 IMG_BACKGROUND_MAIN,
1388 IMG_BACKGROUND_LEVELS,
1389 IMG_BACKGROUND_LEVELNR,
1390 IMG_BACKGROUND_SCORES,
1391 IMG_BACKGROUND_EDITOR,
1392 IMG_BACKGROUND_INFO,
1393 IMG_BACKGROUND_INFO_ELEMENTS,
1394 IMG_BACKGROUND_INFO_MUSIC,
1395 IMG_BACKGROUND_INFO_CREDITS,
1396 IMG_BACKGROUND_INFO_PROGRAM,
1397 IMG_BACKGROUND_INFO_VERSION,
1398 IMG_BACKGROUND_INFO_LEVELSET,
1399 IMG_BACKGROUND_SETUP,
1400 IMG_BACKGROUND_PLAYING,
1401 IMG_BACKGROUND_DOOR,
1402 IMG_BACKGROUND_TAPE,
1403 IMG_BACKGROUND_PANEL,
1404 IMG_BACKGROUND_PALETTE,
1405 IMG_BACKGROUND_TOOLBOX,
1407 IMG_TITLESCREEN_INITIAL_1,
1408 IMG_TITLESCREEN_INITIAL_2,
1409 IMG_TITLESCREEN_INITIAL_3,
1410 IMG_TITLESCREEN_INITIAL_4,
1411 IMG_TITLESCREEN_INITIAL_5,
1418 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1,
1419 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2,
1420 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3,
1421 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4,
1422 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5,
1423 IMG_BACKGROUND_TITLEMESSAGE_1,
1424 IMG_BACKGROUND_TITLEMESSAGE_2,
1425 IMG_BACKGROUND_TITLEMESSAGE_3,
1426 IMG_BACKGROUND_TITLEMESSAGE_4,
1427 IMG_BACKGROUND_TITLEMESSAGE_5,
1432 checked_free(graphic_info);
1434 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1436 /* initialize "use_image_size" flag with default value */
1437 for (i = 0; i < num_images; i++)
1438 graphic_info[i].use_image_size = FALSE;
1440 /* initialize "use_image_size" flag from static configuration above */
1441 for (i = 0; full_size_graphics[i] != -1; i++)
1442 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1444 /* first set all graphic paramaters ... */
1445 for (i = 0; i < num_images; i++)
1446 set_graphic_parameters(i);
1448 /* ... then copy these parameters for cloned graphics */
1449 for (i = 0; i < num_images; i++)
1450 if (graphic_info[i].clone_from != -1)
1451 set_cloned_graphic_parameters(i);
1453 for (i = 0; i < num_images; i++)
1458 int first_frame, last_frame;
1459 int src_bitmap_width, src_bitmap_height;
1461 /* now check if no animation frames are outside of the loaded image */
1463 if (graphic_info[i].bitmap == NULL)
1464 continue; /* skip check for optional images that are undefined */
1466 /* get image size (this can differ from the standard element tile size!) */
1467 width = graphic_info[i].width;
1468 height = graphic_info[i].height;
1470 /* get final bitmap size (with scaling, but without small images) */
1471 src_bitmap_width = graphic_info[i].src_image_width;
1472 src_bitmap_height = graphic_info[i].src_image_height;
1474 /* check if first animation frame is inside specified bitmap */
1477 getFixedGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1479 /* this avoids calculating wrong start position for out-of-bounds frame */
1480 src_x = graphic_info[i].src_x;
1481 src_y = graphic_info[i].src_y;
1483 if (src_x < 0 || src_y < 0 ||
1484 src_x + width > src_bitmap_width ||
1485 src_y + height > src_bitmap_height)
1487 Error(ERR_INFO_LINE, "-");
1488 Error(ERR_INFO, "warning: error found in config file:");
1489 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1490 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1491 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1493 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1494 src_x, src_y, src_bitmap_width, src_bitmap_height);
1495 Error(ERR_INFO, "custom graphic rejected for this element/action");
1497 if (i == fallback_graphic)
1498 Error(ERR_EXIT, "no fallback graphic available");
1500 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1501 Error(ERR_INFO_LINE, "-");
1503 graphic_info[i] = graphic_info[fallback_graphic];
1506 /* check if last animation frame is inside specified bitmap */
1508 last_frame = graphic_info[i].anim_frames - 1;
1509 getFixedGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1511 if (src_x < 0 || src_y < 0 ||
1512 src_x + width > src_bitmap_width ||
1513 src_y + height > src_bitmap_height)
1515 Error(ERR_INFO_LINE, "-");
1516 Error(ERR_INFO, "warning: error found in config file:");
1517 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1518 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1519 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1521 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1522 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1523 Error(ERR_INFO, "::: %d, %d", width, height);
1524 Error(ERR_INFO, "custom graphic rejected for this element/action");
1526 if (i == fallback_graphic)
1527 Error(ERR_EXIT, "no fallback graphic available");
1529 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1530 Error(ERR_INFO_LINE, "-");
1532 graphic_info[i] = graphic_info[fallback_graphic];
1537 static void InitGraphicCompatibilityInfo()
1539 struct FileInfo *fi_global_door =
1540 getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1541 int num_images = getImageListSize();
1544 /* the following compatibility handling is needed for the following case:
1545 versions up to 3.3.0.0 used one large bitmap "global.door" for various
1546 graphics mainly used for door and panel graphics, like editor, tape and
1547 in-game buttons with hard-coded bitmap positions and button sizes; as
1548 these graphics now have individual definitions, redefining "global.door"
1549 to change all these graphics at once like before does not work anymore
1550 (because all those individual definitions still have their default values);
1551 to solve this, remap all those individual definitions that are not
1552 redefined to the new bitmap of "global.door" if it was redefined */
1554 /* special compatibility handling if image "global.door" was redefined */
1555 if (fi_global_door->redefined)
1557 for (i = 0; i < num_images; i++)
1559 struct FileInfo *fi = getImageListEntryFromImageID(i);
1561 /* process only those images that still use the default settings */
1564 /* process all images which default to same image as "global.door" */
1565 if (strEqual(fi->default_filename, fi_global_door->default_filename))
1567 // printf("::: special treatment needed for token '%s'\n", fi->token);
1569 graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
1575 InitGraphicCompatibilityInfo_Doors();
1578 static void InitElementSoundInfo()
1580 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1581 int num_property_mappings = getSoundListPropertyMappingSize();
1584 /* set values to -1 to identify later as "uninitialized" values */
1585 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1586 for (act = 0; act < NUM_ACTIONS; act++)
1587 element_info[i].sound[act] = -1;
1589 /* initialize element/sound mapping from static configuration */
1590 for (i = 0; element_to_sound[i].element > -1; i++)
1592 int element = element_to_sound[i].element;
1593 int action = element_to_sound[i].action;
1594 int sound = element_to_sound[i].sound;
1595 boolean is_class = element_to_sound[i].is_class;
1598 action = ACTION_DEFAULT;
1601 element_info[element].sound[action] = sound;
1603 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1604 if (strEqual(element_info[j].class_name,
1605 element_info[element].class_name))
1606 element_info[j].sound[action] = sound;
1609 /* initialize element class/sound mapping from dynamic configuration */
1610 for (i = 0; i < num_property_mappings; i++)
1612 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1613 int action = property_mapping[i].ext1_index;
1614 int sound = property_mapping[i].artwork_index;
1616 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1620 action = ACTION_DEFAULT;
1622 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1623 if (strEqual(element_info[j].class_name,
1624 element_info[element_class].class_name))
1625 element_info[j].sound[action] = sound;
1628 /* initialize element/sound mapping from dynamic configuration */
1629 for (i = 0; i < num_property_mappings; i++)
1631 int element = property_mapping[i].base_index;
1632 int action = property_mapping[i].ext1_index;
1633 int sound = property_mapping[i].artwork_index;
1635 if (element >= MAX_NUM_ELEMENTS)
1639 action = ACTION_DEFAULT;
1641 element_info[element].sound[action] = sound;
1644 /* now set all '-1' values to element specific default values */
1645 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1647 for (act = 0; act < NUM_ACTIONS; act++)
1649 /* generic default action sound (defined by "[default]" directive) */
1650 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1652 /* look for special default action sound (classic game specific) */
1653 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1654 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1655 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1656 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1657 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1658 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1660 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1661 /* !!! make this better !!! */
1662 if (i == EL_EMPTY_SPACE)
1663 default_action_sound = element_info[EL_DEFAULT].sound[act];
1665 /* no sound for this specific action -- use default action sound */
1666 if (element_info[i].sound[act] == -1)
1667 element_info[i].sound[act] = default_action_sound;
1671 /* copy sound settings to some elements that are only stored in level file
1672 in native R'n'D levels, but are used by game engine in native EM levels */
1673 for (i = 0; copy_properties[i][0] != -1; i++)
1674 for (j = 1; j <= 4; j++)
1675 for (act = 0; act < NUM_ACTIONS; act++)
1676 element_info[copy_properties[i][j]].sound[act] =
1677 element_info[copy_properties[i][0]].sound[act];
1680 static void InitGameModeSoundInfo()
1684 /* set values to -1 to identify later as "uninitialized" values */
1685 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1688 /* initialize gamemode/sound mapping from static configuration */
1689 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1691 int gamemode = gamemode_to_sound[i].gamemode;
1692 int sound = gamemode_to_sound[i].sound;
1695 gamemode = GAME_MODE_DEFAULT;
1697 menu.sound[gamemode] = sound;
1700 /* now set all '-1' values to levelset specific default values */
1701 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1702 if (menu.sound[i] == -1)
1703 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1706 static void set_sound_parameters(int sound, char **parameter_raw)
1708 int parameter[NUM_SND_ARGS];
1711 /* get integer values from string parameters */
1712 for (i = 0; i < NUM_SND_ARGS; i++)
1714 get_parameter_value(parameter_raw[i],
1715 sound_config_suffix[i].token,
1716 sound_config_suffix[i].type);
1718 /* explicit loop mode setting in configuration overrides default value */
1719 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1720 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1722 /* sound volume to change the original volume when loading the sound file */
1723 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1725 /* sound priority to give certain sounds a higher or lower priority */
1726 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
1729 static void InitSoundInfo()
1731 int *sound_effect_properties;
1732 int num_sounds = getSoundListSize();
1735 checked_free(sound_info);
1737 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1738 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1740 /* initialize sound effect for all elements to "no sound" */
1741 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1742 for (j = 0; j < NUM_ACTIONS; j++)
1743 element_info[i].sound[j] = SND_UNDEFINED;
1745 for (i = 0; i < num_sounds; i++)
1747 struct FileInfo *sound = getSoundListEntry(i);
1748 int len_effect_text = strlen(sound->token);
1750 sound_effect_properties[i] = ACTION_OTHER;
1751 sound_info[i].loop = FALSE; /* default: play sound only once */
1753 /* determine all loop sounds and identify certain sound classes */
1755 for (j = 0; element_action_info[j].suffix; j++)
1757 int len_action_text = strlen(element_action_info[j].suffix);
1759 if (len_action_text < len_effect_text &&
1760 strEqual(&sound->token[len_effect_text - len_action_text],
1761 element_action_info[j].suffix))
1763 sound_effect_properties[i] = element_action_info[j].value;
1764 sound_info[i].loop = element_action_info[j].is_loop_sound;
1770 /* associate elements and some selected sound actions */
1772 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1774 if (element_info[j].class_name)
1776 int len_class_text = strlen(element_info[j].class_name);
1778 if (len_class_text + 1 < len_effect_text &&
1779 strncmp(sound->token,
1780 element_info[j].class_name, len_class_text) == 0 &&
1781 sound->token[len_class_text] == '.')
1783 int sound_action_value = sound_effect_properties[i];
1785 element_info[j].sound[sound_action_value] = i;
1790 set_sound_parameters(i, sound->parameter);
1793 free(sound_effect_properties);
1796 static void InitGameModeMusicInfo()
1798 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1799 int num_property_mappings = getMusicListPropertyMappingSize();
1800 int default_levelset_music = -1;
1803 /* set values to -1 to identify later as "uninitialized" values */
1804 for (i = 0; i < MAX_LEVELS; i++)
1805 levelset.music[i] = -1;
1806 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1809 /* initialize gamemode/music mapping from static configuration */
1810 for (i = 0; gamemode_to_music[i].music > -1; i++)
1812 int gamemode = gamemode_to_music[i].gamemode;
1813 int music = gamemode_to_music[i].music;
1816 gamemode = GAME_MODE_DEFAULT;
1818 menu.music[gamemode] = music;
1821 /* initialize gamemode/music mapping from dynamic configuration */
1822 for (i = 0; i < num_property_mappings; i++)
1824 int prefix = property_mapping[i].base_index;
1825 int gamemode = property_mapping[i].ext1_index;
1826 int level = property_mapping[i].ext2_index;
1827 int music = property_mapping[i].artwork_index;
1829 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1833 gamemode = GAME_MODE_DEFAULT;
1835 /* level specific music only allowed for in-game music */
1836 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1837 gamemode = GAME_MODE_PLAYING;
1842 default_levelset_music = music;
1845 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1846 levelset.music[level] = music;
1847 if (gamemode != GAME_MODE_PLAYING)
1848 menu.music[gamemode] = music;
1851 /* now set all '-1' values to menu specific default values */
1852 /* (undefined values of "levelset.music[]" might stay at "-1" to
1853 allow dynamic selection of music files from music directory!) */
1854 for (i = 0; i < MAX_LEVELS; i++)
1855 if (levelset.music[i] == -1)
1856 levelset.music[i] = default_levelset_music;
1857 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1858 if (menu.music[i] == -1)
1859 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1862 static void set_music_parameters(int music, char **parameter_raw)
1864 int parameter[NUM_MUS_ARGS];
1867 /* get integer values from string parameters */
1868 for (i = 0; i < NUM_MUS_ARGS; i++)
1870 get_parameter_value(parameter_raw[i],
1871 music_config_suffix[i].token,
1872 music_config_suffix[i].type);
1874 /* explicit loop mode setting in configuration overrides default value */
1875 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1876 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1879 static void InitMusicInfo()
1881 int num_music = getMusicListSize();
1884 checked_free(music_info);
1886 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1888 for (i = 0; i < num_music; i++)
1890 struct FileInfo *music = getMusicListEntry(i);
1891 int len_music_text = strlen(music->token);
1893 music_info[i].loop = TRUE; /* default: play music in loop mode */
1895 /* determine all loop music */
1897 for (j = 0; music_prefix_info[j].prefix; j++)
1899 int len_prefix_text = strlen(music_prefix_info[j].prefix);
1901 if (len_prefix_text < len_music_text &&
1902 strncmp(music->token,
1903 music_prefix_info[j].prefix, len_prefix_text) == 0)
1905 music_info[i].loop = music_prefix_info[j].is_loop_music;
1911 set_music_parameters(i, music->parameter);
1915 static void ReinitializeGraphics()
1917 print_timestamp_init("ReinitializeGraphics");
1919 InitGfxTileSizeInfo(game.tile_size, TILESIZE);
1921 InitGraphicInfo(); /* graphic properties mapping */
1922 print_timestamp_time("InitGraphicInfo");
1923 InitElementGraphicInfo(); /* element game graphic mapping */
1924 print_timestamp_time("InitElementGraphicInfo");
1925 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
1926 print_timestamp_time("InitElementSpecialGraphicInfo");
1928 InitElementSmallImages(); /* scale elements to all needed sizes */
1929 print_timestamp_time("InitElementSmallImages");
1930 InitScaledImages(); /* scale all other images, if needed */
1931 print_timestamp_time("InitScaledImages");
1932 InitBitmapPointers(); /* set standard size bitmap pointers */
1933 print_timestamp_time("InitBitmapPointers");
1934 InitFontGraphicInfo(); /* initialize text drawing functions */
1935 print_timestamp_time("InitFontGraphicInfo");
1937 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
1938 print_timestamp_time("InitGraphicInfo_EM");
1940 InitGraphicCompatibilityInfo();
1941 print_timestamp_time("InitGraphicCompatibilityInfo");
1943 SetMainBackgroundImage(IMG_BACKGROUND);
1944 print_timestamp_time("SetMainBackgroundImage");
1945 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1946 print_timestamp_time("SetDoorBackgroundImage");
1949 print_timestamp_time("InitGadgets");
1951 print_timestamp_time("InitToons");
1953 print_timestamp_time("InitDoors");
1955 print_timestamp_done("ReinitializeGraphics");
1958 static void ReinitializeSounds()
1960 InitSoundInfo(); /* sound properties mapping */
1961 InitElementSoundInfo(); /* element game sound mapping */
1962 InitGameModeSoundInfo(); /* game mode sound mapping */
1964 InitPlayLevelSound(); /* internal game sound settings */
1967 static void ReinitializeMusic()
1969 InitMusicInfo(); /* music properties mapping */
1970 InitGameModeMusicInfo(); /* game mode music mapping */
1973 static int get_special_property_bit(int element, int property_bit_nr)
1975 struct PropertyBitInfo
1981 static struct PropertyBitInfo pb_can_move_into_acid[] =
1983 /* the player may be able fall into acid when gravity is activated */
1988 { EL_SP_MURPHY, 0 },
1989 { EL_SOKOBAN_FIELD_PLAYER, 0 },
1991 /* all elements that can move may be able to also move into acid */
1994 { EL_BUG_RIGHT, 1 },
1997 { EL_SPACESHIP, 2 },
1998 { EL_SPACESHIP_LEFT, 2 },
1999 { EL_SPACESHIP_RIGHT, 2 },
2000 { EL_SPACESHIP_UP, 2 },
2001 { EL_SPACESHIP_DOWN, 2 },
2002 { EL_BD_BUTTERFLY, 3 },
2003 { EL_BD_BUTTERFLY_LEFT, 3 },
2004 { EL_BD_BUTTERFLY_RIGHT, 3 },
2005 { EL_BD_BUTTERFLY_UP, 3 },
2006 { EL_BD_BUTTERFLY_DOWN, 3 },
2007 { EL_BD_FIREFLY, 4 },
2008 { EL_BD_FIREFLY_LEFT, 4 },
2009 { EL_BD_FIREFLY_RIGHT, 4 },
2010 { EL_BD_FIREFLY_UP, 4 },
2011 { EL_BD_FIREFLY_DOWN, 4 },
2013 { EL_YAMYAM_LEFT, 5 },
2014 { EL_YAMYAM_RIGHT, 5 },
2015 { EL_YAMYAM_UP, 5 },
2016 { EL_YAMYAM_DOWN, 5 },
2017 { EL_DARK_YAMYAM, 6 },
2020 { EL_PACMAN_LEFT, 8 },
2021 { EL_PACMAN_RIGHT, 8 },
2022 { EL_PACMAN_UP, 8 },
2023 { EL_PACMAN_DOWN, 8 },
2025 { EL_MOLE_LEFT, 9 },
2026 { EL_MOLE_RIGHT, 9 },
2028 { EL_MOLE_DOWN, 9 },
2032 { EL_SATELLITE, 13 },
2033 { EL_SP_SNIKSNAK, 14 },
2034 { EL_SP_ELECTRON, 15 },
2037 { EL_EMC_ANDROID, 18 },
2042 static struct PropertyBitInfo pb_dont_collide_with[] =
2044 { EL_SP_SNIKSNAK, 0 },
2045 { EL_SP_ELECTRON, 1 },
2053 struct PropertyBitInfo *pb_info;
2056 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2057 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2062 struct PropertyBitInfo *pb_info = NULL;
2065 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2066 if (pb_definition[i].bit_nr == property_bit_nr)
2067 pb_info = pb_definition[i].pb_info;
2069 if (pb_info == NULL)
2072 for (i = 0; pb_info[i].element != -1; i++)
2073 if (pb_info[i].element == element)
2074 return pb_info[i].bit_nr;
2079 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2080 boolean property_value)
2082 int bit_nr = get_special_property_bit(element, property_bit_nr);
2087 *bitfield |= (1 << bit_nr);
2089 *bitfield &= ~(1 << bit_nr);
2093 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2095 int bit_nr = get_special_property_bit(element, property_bit_nr);
2098 return ((*bitfield & (1 << bit_nr)) != 0);
2103 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2105 static int group_nr;
2106 static struct ElementGroupInfo *group;
2107 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2110 if (actual_group == NULL) /* not yet initialized */
2113 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
2115 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2116 group_element - EL_GROUP_START + 1);
2118 /* replace element which caused too deep recursion by question mark */
2119 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2124 if (recursion_depth == 0) /* initialization */
2126 group = actual_group;
2127 group_nr = GROUP_NR(group_element);
2129 group->num_elements_resolved = 0;
2130 group->choice_pos = 0;
2132 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2133 element_info[i].in_group[group_nr] = FALSE;
2136 for (i = 0; i < actual_group->num_elements; i++)
2138 int element = actual_group->element[i];
2140 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2143 if (IS_GROUP_ELEMENT(element))
2144 ResolveGroupElementExt(element, recursion_depth + 1);
2147 group->element_resolved[group->num_elements_resolved++] = element;
2148 element_info[element].in_group[group_nr] = TRUE;
2153 void ResolveGroupElement(int group_element)
2155 ResolveGroupElementExt(group_element, 0);
2158 void InitElementPropertiesStatic()
2160 static boolean clipboard_elements_initialized = FALSE;
2162 static int ep_diggable[] =
2167 EL_SP_BUGGY_BASE_ACTIVATING,
2170 EL_INVISIBLE_SAND_ACTIVE,
2173 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2174 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2179 EL_SP_BUGGY_BASE_ACTIVE,
2186 static int ep_collectible_only[] =
2208 EL_DYNABOMB_INCREASE_NUMBER,
2209 EL_DYNABOMB_INCREASE_SIZE,
2210 EL_DYNABOMB_INCREASE_POWER,
2228 /* !!! handle separately !!! */
2229 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2235 static int ep_dont_run_into[] =
2237 /* same elements as in 'ep_dont_touch' */
2243 /* same elements as in 'ep_dont_collide_with' */
2255 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2260 EL_SP_BUGGY_BASE_ACTIVE,
2267 static int ep_dont_collide_with[] =
2269 /* same elements as in 'ep_dont_touch' */
2286 static int ep_dont_touch[] =
2296 static int ep_indestructible[] =
2300 EL_ACID_POOL_TOPLEFT,
2301 EL_ACID_POOL_TOPRIGHT,
2302 EL_ACID_POOL_BOTTOMLEFT,
2303 EL_ACID_POOL_BOTTOM,
2304 EL_ACID_POOL_BOTTOMRIGHT,
2305 EL_SP_HARDWARE_GRAY,
2306 EL_SP_HARDWARE_GREEN,
2307 EL_SP_HARDWARE_BLUE,
2309 EL_SP_HARDWARE_YELLOW,
2310 EL_SP_HARDWARE_BASE_1,
2311 EL_SP_HARDWARE_BASE_2,
2312 EL_SP_HARDWARE_BASE_3,
2313 EL_SP_HARDWARE_BASE_4,
2314 EL_SP_HARDWARE_BASE_5,
2315 EL_SP_HARDWARE_BASE_6,
2316 EL_INVISIBLE_STEELWALL,
2317 EL_INVISIBLE_STEELWALL_ACTIVE,
2318 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2319 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2320 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2321 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2322 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2323 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2324 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2325 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2326 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2327 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2328 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2329 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2331 EL_LIGHT_SWITCH_ACTIVE,
2332 EL_SIGN_EXCLAMATION,
2333 EL_SIGN_RADIOACTIVITY,
2340 EL_SIGN_ENTRY_FORBIDDEN,
2341 EL_SIGN_EMERGENCY_EXIT,
2349 EL_STEEL_EXIT_CLOSED,
2351 EL_STEEL_EXIT_OPENING,
2352 EL_STEEL_EXIT_CLOSING,
2353 EL_EM_STEEL_EXIT_CLOSED,
2354 EL_EM_STEEL_EXIT_OPEN,
2355 EL_EM_STEEL_EXIT_OPENING,
2356 EL_EM_STEEL_EXIT_CLOSING,
2357 EL_DC_STEELWALL_1_LEFT,
2358 EL_DC_STEELWALL_1_RIGHT,
2359 EL_DC_STEELWALL_1_TOP,
2360 EL_DC_STEELWALL_1_BOTTOM,
2361 EL_DC_STEELWALL_1_HORIZONTAL,
2362 EL_DC_STEELWALL_1_VERTICAL,
2363 EL_DC_STEELWALL_1_TOPLEFT,
2364 EL_DC_STEELWALL_1_TOPRIGHT,
2365 EL_DC_STEELWALL_1_BOTTOMLEFT,
2366 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2367 EL_DC_STEELWALL_1_TOPLEFT_2,
2368 EL_DC_STEELWALL_1_TOPRIGHT_2,
2369 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2370 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2371 EL_DC_STEELWALL_2_LEFT,
2372 EL_DC_STEELWALL_2_RIGHT,
2373 EL_DC_STEELWALL_2_TOP,
2374 EL_DC_STEELWALL_2_BOTTOM,
2375 EL_DC_STEELWALL_2_HORIZONTAL,
2376 EL_DC_STEELWALL_2_VERTICAL,
2377 EL_DC_STEELWALL_2_MIDDLE,
2378 EL_DC_STEELWALL_2_SINGLE,
2379 EL_STEELWALL_SLIPPERY,
2393 EL_GATE_1_GRAY_ACTIVE,
2394 EL_GATE_2_GRAY_ACTIVE,
2395 EL_GATE_3_GRAY_ACTIVE,
2396 EL_GATE_4_GRAY_ACTIVE,
2405 EL_EM_GATE_1_GRAY_ACTIVE,
2406 EL_EM_GATE_2_GRAY_ACTIVE,
2407 EL_EM_GATE_3_GRAY_ACTIVE,
2408 EL_EM_GATE_4_GRAY_ACTIVE,
2417 EL_EMC_GATE_5_GRAY_ACTIVE,
2418 EL_EMC_GATE_6_GRAY_ACTIVE,
2419 EL_EMC_GATE_7_GRAY_ACTIVE,
2420 EL_EMC_GATE_8_GRAY_ACTIVE,
2422 EL_DC_GATE_WHITE_GRAY,
2423 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2424 EL_DC_GATE_FAKE_GRAY,
2426 EL_SWITCHGATE_OPENING,
2427 EL_SWITCHGATE_CLOSED,
2428 EL_SWITCHGATE_CLOSING,
2429 EL_DC_SWITCHGATE_SWITCH_UP,
2430 EL_DC_SWITCHGATE_SWITCH_DOWN,
2432 EL_TIMEGATE_OPENING,
2434 EL_TIMEGATE_CLOSING,
2435 EL_DC_TIMEGATE_SWITCH,
2436 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2440 EL_TUBE_VERTICAL_LEFT,
2441 EL_TUBE_VERTICAL_RIGHT,
2442 EL_TUBE_HORIZONTAL_UP,
2443 EL_TUBE_HORIZONTAL_DOWN,
2448 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2449 EL_EXPANDABLE_STEELWALL_VERTICAL,
2450 EL_EXPANDABLE_STEELWALL_ANY,
2455 static int ep_slippery[] =
2469 EL_ROBOT_WHEEL_ACTIVE,
2475 EL_ACID_POOL_TOPLEFT,
2476 EL_ACID_POOL_TOPRIGHT,
2486 EL_STEELWALL_SLIPPERY,
2489 EL_EMC_WALL_SLIPPERY_1,
2490 EL_EMC_WALL_SLIPPERY_2,
2491 EL_EMC_WALL_SLIPPERY_3,
2492 EL_EMC_WALL_SLIPPERY_4,
2494 EL_EMC_MAGIC_BALL_ACTIVE,
2499 static int ep_can_change[] =
2504 static int ep_can_move[] =
2506 /* same elements as in 'pb_can_move_into_acid' */
2529 static int ep_can_fall[] =
2543 EL_QUICKSAND_FAST_FULL,
2545 EL_BD_MAGIC_WALL_FULL,
2546 EL_DC_MAGIC_WALL_FULL,
2560 static int ep_can_smash_player[] =
2586 static int ep_can_smash_enemies[] =
2595 static int ep_can_smash_everything[] =
2604 static int ep_explodes_by_fire[] =
2606 /* same elements as in 'ep_explodes_impact' */
2611 /* same elements as in 'ep_explodes_smashed' */
2621 EL_EM_DYNAMITE_ACTIVE,
2622 EL_DYNABOMB_PLAYER_1_ACTIVE,
2623 EL_DYNABOMB_PLAYER_2_ACTIVE,
2624 EL_DYNABOMB_PLAYER_3_ACTIVE,
2625 EL_DYNABOMB_PLAYER_4_ACTIVE,
2626 EL_DYNABOMB_INCREASE_NUMBER,
2627 EL_DYNABOMB_INCREASE_SIZE,
2628 EL_DYNABOMB_INCREASE_POWER,
2629 EL_SP_DISK_RED_ACTIVE,
2643 static int ep_explodes_smashed[] =
2645 /* same elements as in 'ep_explodes_impact' */
2659 static int ep_explodes_impact[] =
2668 static int ep_walkable_over[] =
2672 EL_SOKOBAN_FIELD_EMPTY,
2679 EL_EM_STEEL_EXIT_OPEN,
2680 EL_EM_STEEL_EXIT_OPENING,
2689 EL_GATE_1_GRAY_ACTIVE,
2690 EL_GATE_2_GRAY_ACTIVE,
2691 EL_GATE_3_GRAY_ACTIVE,
2692 EL_GATE_4_GRAY_ACTIVE,
2700 static int ep_walkable_inside[] =
2705 EL_TUBE_VERTICAL_LEFT,
2706 EL_TUBE_VERTICAL_RIGHT,
2707 EL_TUBE_HORIZONTAL_UP,
2708 EL_TUBE_HORIZONTAL_DOWN,
2717 static int ep_walkable_under[] =
2722 static int ep_passable_over[] =
2732 EL_EM_GATE_1_GRAY_ACTIVE,
2733 EL_EM_GATE_2_GRAY_ACTIVE,
2734 EL_EM_GATE_3_GRAY_ACTIVE,
2735 EL_EM_GATE_4_GRAY_ACTIVE,
2744 EL_EMC_GATE_5_GRAY_ACTIVE,
2745 EL_EMC_GATE_6_GRAY_ACTIVE,
2746 EL_EMC_GATE_7_GRAY_ACTIVE,
2747 EL_EMC_GATE_8_GRAY_ACTIVE,
2749 EL_DC_GATE_WHITE_GRAY,
2750 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2757 static int ep_passable_inside[] =
2763 EL_SP_PORT_HORIZONTAL,
2764 EL_SP_PORT_VERTICAL,
2766 EL_SP_GRAVITY_PORT_LEFT,
2767 EL_SP_GRAVITY_PORT_RIGHT,
2768 EL_SP_GRAVITY_PORT_UP,
2769 EL_SP_GRAVITY_PORT_DOWN,
2770 EL_SP_GRAVITY_ON_PORT_LEFT,
2771 EL_SP_GRAVITY_ON_PORT_RIGHT,
2772 EL_SP_GRAVITY_ON_PORT_UP,
2773 EL_SP_GRAVITY_ON_PORT_DOWN,
2774 EL_SP_GRAVITY_OFF_PORT_LEFT,
2775 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2776 EL_SP_GRAVITY_OFF_PORT_UP,
2777 EL_SP_GRAVITY_OFF_PORT_DOWN,
2782 static int ep_passable_under[] =
2787 static int ep_droppable[] =
2792 static int ep_explodes_1x1_old[] =
2797 static int ep_pushable[] =
2809 EL_SOKOBAN_FIELD_FULL,
2818 static int ep_explodes_cross_old[] =
2823 static int ep_protected[] =
2825 /* same elements as in 'ep_walkable_inside' */
2829 EL_TUBE_VERTICAL_LEFT,
2830 EL_TUBE_VERTICAL_RIGHT,
2831 EL_TUBE_HORIZONTAL_UP,
2832 EL_TUBE_HORIZONTAL_DOWN,
2838 /* same elements as in 'ep_passable_over' */
2847 EL_EM_GATE_1_GRAY_ACTIVE,
2848 EL_EM_GATE_2_GRAY_ACTIVE,
2849 EL_EM_GATE_3_GRAY_ACTIVE,
2850 EL_EM_GATE_4_GRAY_ACTIVE,
2859 EL_EMC_GATE_5_GRAY_ACTIVE,
2860 EL_EMC_GATE_6_GRAY_ACTIVE,
2861 EL_EMC_GATE_7_GRAY_ACTIVE,
2862 EL_EMC_GATE_8_GRAY_ACTIVE,
2864 EL_DC_GATE_WHITE_GRAY,
2865 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2869 /* same elements as in 'ep_passable_inside' */
2874 EL_SP_PORT_HORIZONTAL,
2875 EL_SP_PORT_VERTICAL,
2877 EL_SP_GRAVITY_PORT_LEFT,
2878 EL_SP_GRAVITY_PORT_RIGHT,
2879 EL_SP_GRAVITY_PORT_UP,
2880 EL_SP_GRAVITY_PORT_DOWN,
2881 EL_SP_GRAVITY_ON_PORT_LEFT,
2882 EL_SP_GRAVITY_ON_PORT_RIGHT,
2883 EL_SP_GRAVITY_ON_PORT_UP,
2884 EL_SP_GRAVITY_ON_PORT_DOWN,
2885 EL_SP_GRAVITY_OFF_PORT_LEFT,
2886 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2887 EL_SP_GRAVITY_OFF_PORT_UP,
2888 EL_SP_GRAVITY_OFF_PORT_DOWN,
2893 static int ep_throwable[] =
2898 static int ep_can_explode[] =
2900 /* same elements as in 'ep_explodes_impact' */
2905 /* same elements as in 'ep_explodes_smashed' */
2911 /* elements that can explode by explosion or by dragonfire */
2915 EL_EM_DYNAMITE_ACTIVE,
2916 EL_DYNABOMB_PLAYER_1_ACTIVE,
2917 EL_DYNABOMB_PLAYER_2_ACTIVE,
2918 EL_DYNABOMB_PLAYER_3_ACTIVE,
2919 EL_DYNABOMB_PLAYER_4_ACTIVE,
2920 EL_DYNABOMB_INCREASE_NUMBER,
2921 EL_DYNABOMB_INCREASE_SIZE,
2922 EL_DYNABOMB_INCREASE_POWER,
2923 EL_SP_DISK_RED_ACTIVE,
2931 /* elements that can explode only by explosion */
2937 static int ep_gravity_reachable[] =
2943 EL_INVISIBLE_SAND_ACTIVE,
2948 EL_SP_PORT_HORIZONTAL,
2949 EL_SP_PORT_VERTICAL,
2951 EL_SP_GRAVITY_PORT_LEFT,
2952 EL_SP_GRAVITY_PORT_RIGHT,
2953 EL_SP_GRAVITY_PORT_UP,
2954 EL_SP_GRAVITY_PORT_DOWN,
2955 EL_SP_GRAVITY_ON_PORT_LEFT,
2956 EL_SP_GRAVITY_ON_PORT_RIGHT,
2957 EL_SP_GRAVITY_ON_PORT_UP,
2958 EL_SP_GRAVITY_ON_PORT_DOWN,
2959 EL_SP_GRAVITY_OFF_PORT_LEFT,
2960 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2961 EL_SP_GRAVITY_OFF_PORT_UP,
2962 EL_SP_GRAVITY_OFF_PORT_DOWN,
2968 static int ep_player[] =
2975 EL_SOKOBAN_FIELD_PLAYER,
2981 static int ep_can_pass_magic_wall[] =
2995 static int ep_can_pass_dc_magic_wall[] =
3011 static int ep_switchable[] =
3015 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3016 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3017 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3018 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3019 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3020 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3021 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3022 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3023 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3024 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3025 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3026 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3027 EL_SWITCHGATE_SWITCH_UP,
3028 EL_SWITCHGATE_SWITCH_DOWN,
3029 EL_DC_SWITCHGATE_SWITCH_UP,
3030 EL_DC_SWITCHGATE_SWITCH_DOWN,
3032 EL_LIGHT_SWITCH_ACTIVE,
3034 EL_DC_TIMEGATE_SWITCH,
3035 EL_BALLOON_SWITCH_LEFT,
3036 EL_BALLOON_SWITCH_RIGHT,
3037 EL_BALLOON_SWITCH_UP,
3038 EL_BALLOON_SWITCH_DOWN,
3039 EL_BALLOON_SWITCH_ANY,
3040 EL_BALLOON_SWITCH_NONE,
3043 EL_EMC_MAGIC_BALL_SWITCH,
3044 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3049 static int ep_bd_element[] =
3083 static int ep_sp_element[] =
3085 /* should always be valid */
3088 /* standard classic Supaplex elements */
3095 EL_SP_HARDWARE_GRAY,
3103 EL_SP_GRAVITY_PORT_RIGHT,
3104 EL_SP_GRAVITY_PORT_DOWN,
3105 EL_SP_GRAVITY_PORT_LEFT,
3106 EL_SP_GRAVITY_PORT_UP,
3111 EL_SP_PORT_VERTICAL,
3112 EL_SP_PORT_HORIZONTAL,
3118 EL_SP_HARDWARE_BASE_1,
3119 EL_SP_HARDWARE_GREEN,
3120 EL_SP_HARDWARE_BLUE,
3122 EL_SP_HARDWARE_YELLOW,
3123 EL_SP_HARDWARE_BASE_2,
3124 EL_SP_HARDWARE_BASE_3,
3125 EL_SP_HARDWARE_BASE_4,
3126 EL_SP_HARDWARE_BASE_5,
3127 EL_SP_HARDWARE_BASE_6,
3131 /* additional elements that appeared in newer Supaplex levels */
3134 /* additional gravity port elements (not switching, but setting gravity) */
3135 EL_SP_GRAVITY_ON_PORT_LEFT,
3136 EL_SP_GRAVITY_ON_PORT_RIGHT,
3137 EL_SP_GRAVITY_ON_PORT_UP,
3138 EL_SP_GRAVITY_ON_PORT_DOWN,
3139 EL_SP_GRAVITY_OFF_PORT_LEFT,
3140 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3141 EL_SP_GRAVITY_OFF_PORT_UP,
3142 EL_SP_GRAVITY_OFF_PORT_DOWN,
3144 /* more than one Murphy in a level results in an inactive clone */
3147 /* runtime Supaplex elements */
3148 EL_SP_DISK_RED_ACTIVE,
3149 EL_SP_TERMINAL_ACTIVE,
3150 EL_SP_BUGGY_BASE_ACTIVATING,
3151 EL_SP_BUGGY_BASE_ACTIVE,
3158 static int ep_sb_element[] =
3163 EL_SOKOBAN_FIELD_EMPTY,
3164 EL_SOKOBAN_FIELD_FULL,
3165 EL_SOKOBAN_FIELD_PLAYER,
3170 EL_INVISIBLE_STEELWALL,
3175 static int ep_gem[] =
3187 static int ep_food_dark_yamyam[] =
3215 static int ep_food_penguin[] =
3229 static int ep_food_pig[] =
3241 static int ep_historic_wall[] =
3252 EL_GATE_1_GRAY_ACTIVE,
3253 EL_GATE_2_GRAY_ACTIVE,
3254 EL_GATE_3_GRAY_ACTIVE,
3255 EL_GATE_4_GRAY_ACTIVE,
3264 EL_EM_GATE_1_GRAY_ACTIVE,
3265 EL_EM_GATE_2_GRAY_ACTIVE,
3266 EL_EM_GATE_3_GRAY_ACTIVE,
3267 EL_EM_GATE_4_GRAY_ACTIVE,
3274 EL_EXPANDABLE_WALL_HORIZONTAL,
3275 EL_EXPANDABLE_WALL_VERTICAL,
3276 EL_EXPANDABLE_WALL_ANY,
3277 EL_EXPANDABLE_WALL_GROWING,
3278 EL_BD_EXPANDABLE_WALL,
3285 EL_SP_HARDWARE_GRAY,
3286 EL_SP_HARDWARE_GREEN,
3287 EL_SP_HARDWARE_BLUE,
3289 EL_SP_HARDWARE_YELLOW,
3290 EL_SP_HARDWARE_BASE_1,
3291 EL_SP_HARDWARE_BASE_2,
3292 EL_SP_HARDWARE_BASE_3,
3293 EL_SP_HARDWARE_BASE_4,
3294 EL_SP_HARDWARE_BASE_5,
3295 EL_SP_HARDWARE_BASE_6,
3297 EL_SP_TERMINAL_ACTIVE,
3300 EL_INVISIBLE_STEELWALL,
3301 EL_INVISIBLE_STEELWALL_ACTIVE,
3303 EL_INVISIBLE_WALL_ACTIVE,
3304 EL_STEELWALL_SLIPPERY,
3321 static int ep_historic_solid[] =
3325 EL_EXPANDABLE_WALL_HORIZONTAL,
3326 EL_EXPANDABLE_WALL_VERTICAL,
3327 EL_EXPANDABLE_WALL_ANY,
3328 EL_BD_EXPANDABLE_WALL,
3341 EL_QUICKSAND_FILLING,
3342 EL_QUICKSAND_EMPTYING,
3344 EL_MAGIC_WALL_ACTIVE,
3345 EL_MAGIC_WALL_EMPTYING,
3346 EL_MAGIC_WALL_FILLING,
3350 EL_BD_MAGIC_WALL_ACTIVE,
3351 EL_BD_MAGIC_WALL_EMPTYING,
3352 EL_BD_MAGIC_WALL_FULL,
3353 EL_BD_MAGIC_WALL_FILLING,
3354 EL_BD_MAGIC_WALL_DEAD,
3363 EL_SP_TERMINAL_ACTIVE,
3367 EL_INVISIBLE_WALL_ACTIVE,
3368 EL_SWITCHGATE_SWITCH_UP,
3369 EL_SWITCHGATE_SWITCH_DOWN,
3370 EL_DC_SWITCHGATE_SWITCH_UP,
3371 EL_DC_SWITCHGATE_SWITCH_DOWN,
3373 EL_TIMEGATE_SWITCH_ACTIVE,
3374 EL_DC_TIMEGATE_SWITCH,
3375 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3387 /* the following elements are a direct copy of "indestructible" elements,
3388 except "EL_ACID", which is "indestructible", but not "solid"! */
3393 EL_ACID_POOL_TOPLEFT,
3394 EL_ACID_POOL_TOPRIGHT,
3395 EL_ACID_POOL_BOTTOMLEFT,
3396 EL_ACID_POOL_BOTTOM,
3397 EL_ACID_POOL_BOTTOMRIGHT,
3398 EL_SP_HARDWARE_GRAY,
3399 EL_SP_HARDWARE_GREEN,
3400 EL_SP_HARDWARE_BLUE,
3402 EL_SP_HARDWARE_YELLOW,
3403 EL_SP_HARDWARE_BASE_1,
3404 EL_SP_HARDWARE_BASE_2,
3405 EL_SP_HARDWARE_BASE_3,
3406 EL_SP_HARDWARE_BASE_4,
3407 EL_SP_HARDWARE_BASE_5,
3408 EL_SP_HARDWARE_BASE_6,
3409 EL_INVISIBLE_STEELWALL,
3410 EL_INVISIBLE_STEELWALL_ACTIVE,
3411 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3412 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3413 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3414 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3415 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3416 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3417 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3418 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3419 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3420 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3421 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3422 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3424 EL_LIGHT_SWITCH_ACTIVE,
3425 EL_SIGN_EXCLAMATION,
3426 EL_SIGN_RADIOACTIVITY,
3433 EL_SIGN_ENTRY_FORBIDDEN,
3434 EL_SIGN_EMERGENCY_EXIT,
3442 EL_STEEL_EXIT_CLOSED,
3444 EL_DC_STEELWALL_1_LEFT,
3445 EL_DC_STEELWALL_1_RIGHT,
3446 EL_DC_STEELWALL_1_TOP,
3447 EL_DC_STEELWALL_1_BOTTOM,
3448 EL_DC_STEELWALL_1_HORIZONTAL,
3449 EL_DC_STEELWALL_1_VERTICAL,
3450 EL_DC_STEELWALL_1_TOPLEFT,
3451 EL_DC_STEELWALL_1_TOPRIGHT,
3452 EL_DC_STEELWALL_1_BOTTOMLEFT,
3453 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3454 EL_DC_STEELWALL_1_TOPLEFT_2,
3455 EL_DC_STEELWALL_1_TOPRIGHT_2,
3456 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3457 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3458 EL_DC_STEELWALL_2_LEFT,
3459 EL_DC_STEELWALL_2_RIGHT,
3460 EL_DC_STEELWALL_2_TOP,
3461 EL_DC_STEELWALL_2_BOTTOM,
3462 EL_DC_STEELWALL_2_HORIZONTAL,
3463 EL_DC_STEELWALL_2_VERTICAL,
3464 EL_DC_STEELWALL_2_MIDDLE,
3465 EL_DC_STEELWALL_2_SINGLE,
3466 EL_STEELWALL_SLIPPERY,
3480 EL_GATE_1_GRAY_ACTIVE,
3481 EL_GATE_2_GRAY_ACTIVE,
3482 EL_GATE_3_GRAY_ACTIVE,
3483 EL_GATE_4_GRAY_ACTIVE,
3492 EL_EM_GATE_1_GRAY_ACTIVE,
3493 EL_EM_GATE_2_GRAY_ACTIVE,
3494 EL_EM_GATE_3_GRAY_ACTIVE,
3495 EL_EM_GATE_4_GRAY_ACTIVE,
3497 EL_SWITCHGATE_OPENING,
3498 EL_SWITCHGATE_CLOSED,
3499 EL_SWITCHGATE_CLOSING,
3501 EL_TIMEGATE_OPENING,
3503 EL_TIMEGATE_CLOSING,
3507 EL_TUBE_VERTICAL_LEFT,
3508 EL_TUBE_VERTICAL_RIGHT,
3509 EL_TUBE_HORIZONTAL_UP,
3510 EL_TUBE_HORIZONTAL_DOWN,
3519 static int ep_classic_enemy[] =
3536 static int ep_belt[] =
3538 EL_CONVEYOR_BELT_1_LEFT,
3539 EL_CONVEYOR_BELT_1_MIDDLE,
3540 EL_CONVEYOR_BELT_1_RIGHT,
3541 EL_CONVEYOR_BELT_2_LEFT,
3542 EL_CONVEYOR_BELT_2_MIDDLE,
3543 EL_CONVEYOR_BELT_2_RIGHT,
3544 EL_CONVEYOR_BELT_3_LEFT,
3545 EL_CONVEYOR_BELT_3_MIDDLE,
3546 EL_CONVEYOR_BELT_3_RIGHT,
3547 EL_CONVEYOR_BELT_4_LEFT,
3548 EL_CONVEYOR_BELT_4_MIDDLE,
3549 EL_CONVEYOR_BELT_4_RIGHT,
3554 static int ep_belt_active[] =
3556 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3557 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3558 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3559 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3560 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3561 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3562 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3563 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3564 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3565 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3566 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3567 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3572 static int ep_belt_switch[] =
3574 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3575 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3576 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3577 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3578 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3579 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3580 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3581 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3582 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3583 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3584 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3585 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3590 static int ep_tube[] =
3597 EL_TUBE_HORIZONTAL_UP,
3598 EL_TUBE_HORIZONTAL_DOWN,
3600 EL_TUBE_VERTICAL_LEFT,
3601 EL_TUBE_VERTICAL_RIGHT,
3607 static int ep_acid_pool[] =
3609 EL_ACID_POOL_TOPLEFT,
3610 EL_ACID_POOL_TOPRIGHT,
3611 EL_ACID_POOL_BOTTOMLEFT,
3612 EL_ACID_POOL_BOTTOM,
3613 EL_ACID_POOL_BOTTOMRIGHT,
3618 static int ep_keygate[] =
3628 EL_GATE_1_GRAY_ACTIVE,
3629 EL_GATE_2_GRAY_ACTIVE,
3630 EL_GATE_3_GRAY_ACTIVE,
3631 EL_GATE_4_GRAY_ACTIVE,
3640 EL_EM_GATE_1_GRAY_ACTIVE,
3641 EL_EM_GATE_2_GRAY_ACTIVE,
3642 EL_EM_GATE_3_GRAY_ACTIVE,
3643 EL_EM_GATE_4_GRAY_ACTIVE,
3652 EL_EMC_GATE_5_GRAY_ACTIVE,
3653 EL_EMC_GATE_6_GRAY_ACTIVE,
3654 EL_EMC_GATE_7_GRAY_ACTIVE,
3655 EL_EMC_GATE_8_GRAY_ACTIVE,
3657 EL_DC_GATE_WHITE_GRAY,
3658 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3663 static int ep_amoeboid[] =
3675 static int ep_amoebalive[] =
3686 static int ep_has_editor_content[] =
3692 EL_SOKOBAN_FIELD_PLAYER,
3709 static int ep_can_turn_each_move[] =
3711 /* !!! do something with this one !!! */
3715 static int ep_can_grow[] =
3729 static int ep_active_bomb[] =
3732 EL_EM_DYNAMITE_ACTIVE,
3733 EL_DYNABOMB_PLAYER_1_ACTIVE,
3734 EL_DYNABOMB_PLAYER_2_ACTIVE,
3735 EL_DYNABOMB_PLAYER_3_ACTIVE,
3736 EL_DYNABOMB_PLAYER_4_ACTIVE,
3737 EL_SP_DISK_RED_ACTIVE,
3742 static int ep_inactive[] =
3752 EL_QUICKSAND_FAST_EMPTY,
3775 EL_GATE_1_GRAY_ACTIVE,
3776 EL_GATE_2_GRAY_ACTIVE,
3777 EL_GATE_3_GRAY_ACTIVE,
3778 EL_GATE_4_GRAY_ACTIVE,
3787 EL_EM_GATE_1_GRAY_ACTIVE,
3788 EL_EM_GATE_2_GRAY_ACTIVE,
3789 EL_EM_GATE_3_GRAY_ACTIVE,
3790 EL_EM_GATE_4_GRAY_ACTIVE,
3799 EL_EMC_GATE_5_GRAY_ACTIVE,
3800 EL_EMC_GATE_6_GRAY_ACTIVE,
3801 EL_EMC_GATE_7_GRAY_ACTIVE,
3802 EL_EMC_GATE_8_GRAY_ACTIVE,
3804 EL_DC_GATE_WHITE_GRAY,
3805 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3806 EL_DC_GATE_FAKE_GRAY,
3809 EL_INVISIBLE_STEELWALL,
3817 EL_WALL_EMERALD_YELLOW,
3818 EL_DYNABOMB_INCREASE_NUMBER,
3819 EL_DYNABOMB_INCREASE_SIZE,
3820 EL_DYNABOMB_INCREASE_POWER,
3824 EL_SOKOBAN_FIELD_EMPTY,
3825 EL_SOKOBAN_FIELD_FULL,
3826 EL_WALL_EMERALD_RED,
3827 EL_WALL_EMERALD_PURPLE,
3828 EL_ACID_POOL_TOPLEFT,
3829 EL_ACID_POOL_TOPRIGHT,
3830 EL_ACID_POOL_BOTTOMLEFT,
3831 EL_ACID_POOL_BOTTOM,
3832 EL_ACID_POOL_BOTTOMRIGHT,
3836 EL_BD_MAGIC_WALL_DEAD,
3838 EL_DC_MAGIC_WALL_DEAD,
3839 EL_AMOEBA_TO_DIAMOND,
3847 EL_SP_GRAVITY_PORT_RIGHT,
3848 EL_SP_GRAVITY_PORT_DOWN,
3849 EL_SP_GRAVITY_PORT_LEFT,
3850 EL_SP_GRAVITY_PORT_UP,
3851 EL_SP_PORT_HORIZONTAL,
3852 EL_SP_PORT_VERTICAL,
3863 EL_SP_HARDWARE_GRAY,
3864 EL_SP_HARDWARE_GREEN,
3865 EL_SP_HARDWARE_BLUE,
3867 EL_SP_HARDWARE_YELLOW,
3868 EL_SP_HARDWARE_BASE_1,
3869 EL_SP_HARDWARE_BASE_2,
3870 EL_SP_HARDWARE_BASE_3,
3871 EL_SP_HARDWARE_BASE_4,
3872 EL_SP_HARDWARE_BASE_5,
3873 EL_SP_HARDWARE_BASE_6,
3874 EL_SP_GRAVITY_ON_PORT_LEFT,
3875 EL_SP_GRAVITY_ON_PORT_RIGHT,
3876 EL_SP_GRAVITY_ON_PORT_UP,
3877 EL_SP_GRAVITY_ON_PORT_DOWN,
3878 EL_SP_GRAVITY_OFF_PORT_LEFT,
3879 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3880 EL_SP_GRAVITY_OFF_PORT_UP,
3881 EL_SP_GRAVITY_OFF_PORT_DOWN,
3882 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3883 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3884 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3885 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3886 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3887 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3888 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3889 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3890 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3891 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3892 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3893 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3894 EL_SIGN_EXCLAMATION,
3895 EL_SIGN_RADIOACTIVITY,
3902 EL_SIGN_ENTRY_FORBIDDEN,
3903 EL_SIGN_EMERGENCY_EXIT,
3911 EL_DC_STEELWALL_1_LEFT,
3912 EL_DC_STEELWALL_1_RIGHT,
3913 EL_DC_STEELWALL_1_TOP,
3914 EL_DC_STEELWALL_1_BOTTOM,
3915 EL_DC_STEELWALL_1_HORIZONTAL,
3916 EL_DC_STEELWALL_1_VERTICAL,
3917 EL_DC_STEELWALL_1_TOPLEFT,
3918 EL_DC_STEELWALL_1_TOPRIGHT,
3919 EL_DC_STEELWALL_1_BOTTOMLEFT,
3920 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3921 EL_DC_STEELWALL_1_TOPLEFT_2,
3922 EL_DC_STEELWALL_1_TOPRIGHT_2,
3923 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3924 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3925 EL_DC_STEELWALL_2_LEFT,
3926 EL_DC_STEELWALL_2_RIGHT,
3927 EL_DC_STEELWALL_2_TOP,
3928 EL_DC_STEELWALL_2_BOTTOM,
3929 EL_DC_STEELWALL_2_HORIZONTAL,
3930 EL_DC_STEELWALL_2_VERTICAL,
3931 EL_DC_STEELWALL_2_MIDDLE,
3932 EL_DC_STEELWALL_2_SINGLE,
3933 EL_STEELWALL_SLIPPERY,
3938 EL_EMC_WALL_SLIPPERY_1,
3939 EL_EMC_WALL_SLIPPERY_2,
3940 EL_EMC_WALL_SLIPPERY_3,
3941 EL_EMC_WALL_SLIPPERY_4,
3962 static int ep_em_slippery_wall[] =
3967 static int ep_gfx_crumbled[] =
3978 static int ep_editor_cascade_active[] =
3980 EL_INTERNAL_CASCADE_BD_ACTIVE,
3981 EL_INTERNAL_CASCADE_EM_ACTIVE,
3982 EL_INTERNAL_CASCADE_EMC_ACTIVE,
3983 EL_INTERNAL_CASCADE_RND_ACTIVE,
3984 EL_INTERNAL_CASCADE_SB_ACTIVE,
3985 EL_INTERNAL_CASCADE_SP_ACTIVE,
3986 EL_INTERNAL_CASCADE_DC_ACTIVE,
3987 EL_INTERNAL_CASCADE_DX_ACTIVE,
3988 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
3989 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
3990 EL_INTERNAL_CASCADE_CE_ACTIVE,
3991 EL_INTERNAL_CASCADE_GE_ACTIVE,
3992 EL_INTERNAL_CASCADE_REF_ACTIVE,
3993 EL_INTERNAL_CASCADE_USER_ACTIVE,
3994 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
3999 static int ep_editor_cascade_inactive[] =
4001 EL_INTERNAL_CASCADE_BD,
4002 EL_INTERNAL_CASCADE_EM,
4003 EL_INTERNAL_CASCADE_EMC,
4004 EL_INTERNAL_CASCADE_RND,
4005 EL_INTERNAL_CASCADE_SB,
4006 EL_INTERNAL_CASCADE_SP,
4007 EL_INTERNAL_CASCADE_DC,
4008 EL_INTERNAL_CASCADE_DX,
4009 EL_INTERNAL_CASCADE_CHARS,
4010 EL_INTERNAL_CASCADE_STEEL_CHARS,
4011 EL_INTERNAL_CASCADE_CE,
4012 EL_INTERNAL_CASCADE_GE,
4013 EL_INTERNAL_CASCADE_REF,
4014 EL_INTERNAL_CASCADE_USER,
4015 EL_INTERNAL_CASCADE_DYNAMIC,
4020 static int ep_obsolete[] =
4024 EL_EM_KEY_1_FILE_OBSOLETE,
4025 EL_EM_KEY_2_FILE_OBSOLETE,
4026 EL_EM_KEY_3_FILE_OBSOLETE,
4027 EL_EM_KEY_4_FILE_OBSOLETE,
4028 EL_ENVELOPE_OBSOLETE,
4037 } element_properties[] =
4039 { ep_diggable, EP_DIGGABLE },
4040 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4041 { ep_dont_run_into, EP_DONT_RUN_INTO },
4042 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4043 { ep_dont_touch, EP_DONT_TOUCH },
4044 { ep_indestructible, EP_INDESTRUCTIBLE },
4045 { ep_slippery, EP_SLIPPERY },
4046 { ep_can_change, EP_CAN_CHANGE },
4047 { ep_can_move, EP_CAN_MOVE },
4048 { ep_can_fall, EP_CAN_FALL },
4049 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4050 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4051 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4052 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4053 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4054 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4055 { ep_walkable_over, EP_WALKABLE_OVER },
4056 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4057 { ep_walkable_under, EP_WALKABLE_UNDER },
4058 { ep_passable_over, EP_PASSABLE_OVER },
4059 { ep_passable_inside, EP_PASSABLE_INSIDE },
4060 { ep_passable_under, EP_PASSABLE_UNDER },
4061 { ep_droppable, EP_DROPPABLE },
4062 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4063 { ep_pushable, EP_PUSHABLE },
4064 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4065 { ep_protected, EP_PROTECTED },
4066 { ep_throwable, EP_THROWABLE },
4067 { ep_can_explode, EP_CAN_EXPLODE },
4068 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4070 { ep_player, EP_PLAYER },
4071 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4072 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4073 { ep_switchable, EP_SWITCHABLE },
4074 { ep_bd_element, EP_BD_ELEMENT },
4075 { ep_sp_element, EP_SP_ELEMENT },
4076 { ep_sb_element, EP_SB_ELEMENT },
4078 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4079 { ep_food_penguin, EP_FOOD_PENGUIN },
4080 { ep_food_pig, EP_FOOD_PIG },
4081 { ep_historic_wall, EP_HISTORIC_WALL },
4082 { ep_historic_solid, EP_HISTORIC_SOLID },
4083 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4084 { ep_belt, EP_BELT },
4085 { ep_belt_active, EP_BELT_ACTIVE },
4086 { ep_belt_switch, EP_BELT_SWITCH },
4087 { ep_tube, EP_TUBE },
4088 { ep_acid_pool, EP_ACID_POOL },
4089 { ep_keygate, EP_KEYGATE },
4090 { ep_amoeboid, EP_AMOEBOID },
4091 { ep_amoebalive, EP_AMOEBALIVE },
4092 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4093 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4094 { ep_can_grow, EP_CAN_GROW },
4095 { ep_active_bomb, EP_ACTIVE_BOMB },
4096 { ep_inactive, EP_INACTIVE },
4098 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4100 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4102 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4103 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4105 { ep_obsolete, EP_OBSOLETE },
4112 /* always start with reliable default values (element has no properties) */
4113 /* (but never initialize clipboard elements after the very first time) */
4114 /* (to be able to use clipboard elements between several levels) */
4115 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4116 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4117 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4118 SET_PROPERTY(i, j, FALSE);
4120 /* set all base element properties from above array definitions */
4121 for (i = 0; element_properties[i].elements != NULL; i++)
4122 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4123 SET_PROPERTY((element_properties[i].elements)[j],
4124 element_properties[i].property, TRUE);
4126 /* copy properties to some elements that are only stored in level file */
4127 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4128 for (j = 0; copy_properties[j][0] != -1; j++)
4129 if (HAS_PROPERTY(copy_properties[j][0], i))
4130 for (k = 1; k <= 4; k++)
4131 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4133 /* set static element properties that are not listed in array definitions */
4134 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4135 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4137 clipboard_elements_initialized = TRUE;
4140 void InitElementPropertiesEngine(int engine_version)
4142 static int no_wall_properties[] =
4145 EP_COLLECTIBLE_ONLY,
4147 EP_DONT_COLLIDE_WITH,
4150 EP_CAN_SMASH_PLAYER,
4151 EP_CAN_SMASH_ENEMIES,
4152 EP_CAN_SMASH_EVERYTHING,
4157 EP_FOOD_DARK_YAMYAM,
4173 /* important: after initialization in InitElementPropertiesStatic(), the
4174 elements are not again initialized to a default value; therefore all
4175 changes have to make sure that they leave the element with a defined
4176 property (which means that conditional property changes must be set to
4177 a reliable default value before) */
4179 /* resolve group elements */
4180 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4181 ResolveGroupElement(EL_GROUP_START + i);
4183 /* set all special, combined or engine dependent element properties */
4184 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4186 /* do not change (already initialized) clipboard elements here */
4187 if (IS_CLIPBOARD_ELEMENT(i))
4190 /* ---------- INACTIVE ------------------------------------------------- */
4191 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4192 i <= EL_CHAR_END) ||
4193 (i >= EL_STEEL_CHAR_START &&
4194 i <= EL_STEEL_CHAR_END)));
4196 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4197 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4198 IS_WALKABLE_INSIDE(i) ||
4199 IS_WALKABLE_UNDER(i)));
4201 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4202 IS_PASSABLE_INSIDE(i) ||
4203 IS_PASSABLE_UNDER(i)));
4205 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4206 IS_PASSABLE_OVER(i)));
4208 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4209 IS_PASSABLE_INSIDE(i)));
4211 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4212 IS_PASSABLE_UNDER(i)));
4214 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4217 /* ---------- COLLECTIBLE ---------------------------------------------- */
4218 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4222 /* ---------- SNAPPABLE ------------------------------------------------ */
4223 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4224 IS_COLLECTIBLE(i) ||
4228 /* ---------- WALL ----------------------------------------------------- */
4229 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4231 for (j = 0; no_wall_properties[j] != -1; j++)
4232 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4233 i >= EL_FIRST_RUNTIME_UNREAL)
4234 SET_PROPERTY(i, EP_WALL, FALSE);
4236 if (IS_HISTORIC_WALL(i))
4237 SET_PROPERTY(i, EP_WALL, TRUE);
4239 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4240 if (engine_version < VERSION_IDENT(2,2,0,0))
4241 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4243 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4245 !IS_COLLECTIBLE(i)));
4247 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4248 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4249 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4251 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4252 IS_INDESTRUCTIBLE(i)));
4254 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4256 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4257 else if (engine_version < VERSION_IDENT(2,2,0,0))
4258 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4260 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4264 if (IS_CUSTOM_ELEMENT(i))
4266 /* these are additional properties which are initially false when set */
4268 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4270 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4271 if (DONT_COLLIDE_WITH(i))
4272 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4274 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4275 if (CAN_SMASH_EVERYTHING(i))
4276 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4277 if (CAN_SMASH_ENEMIES(i))
4278 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4281 /* ---------- CAN_SMASH ------------------------------------------------ */
4282 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4283 CAN_SMASH_ENEMIES(i) ||
4284 CAN_SMASH_EVERYTHING(i)));
4286 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4287 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4288 EXPLODES_BY_FIRE(i)));
4290 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4291 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4292 EXPLODES_SMASHED(i)));
4294 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4295 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4296 EXPLODES_IMPACT(i)));
4298 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4299 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4301 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4302 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4303 i == EL_BLACK_ORB));
4305 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4306 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4308 IS_CUSTOM_ELEMENT(i)));
4310 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4311 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4312 i == EL_SP_ELECTRON));
4314 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4315 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4316 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4317 getMoveIntoAcidProperty(&level, i));
4319 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4320 if (MAYBE_DONT_COLLIDE_WITH(i))
4321 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4322 getDontCollideWithProperty(&level, i));
4324 /* ---------- SP_PORT -------------------------------------------------- */
4325 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4326 IS_PASSABLE_INSIDE(i)));
4328 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4329 for (j = 0; j < level.num_android_clone_elements; j++)
4330 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4332 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4334 /* ---------- CAN_CHANGE ----------------------------------------------- */
4335 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4336 for (j = 0; j < element_info[i].num_change_pages; j++)
4337 if (element_info[i].change_page[j].can_change)
4338 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4340 /* ---------- HAS_ACTION ----------------------------------------------- */
4341 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4342 for (j = 0; j < element_info[i].num_change_pages; j++)
4343 if (element_info[i].change_page[j].has_action)
4344 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4346 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4347 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4350 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4351 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4352 element_info[i].crumbled[ACTION_DEFAULT] !=
4353 element_info[i].graphic[ACTION_DEFAULT]);
4355 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4356 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4357 IS_EDITOR_CASCADE_INACTIVE(i)));
4360 /* dynamically adjust element properties according to game engine version */
4362 static int ep_em_slippery_wall[] =
4367 EL_EXPANDABLE_WALL_HORIZONTAL,
4368 EL_EXPANDABLE_WALL_VERTICAL,
4369 EL_EXPANDABLE_WALL_ANY,
4370 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4371 EL_EXPANDABLE_STEELWALL_VERTICAL,
4372 EL_EXPANDABLE_STEELWALL_ANY,
4373 EL_EXPANDABLE_STEELWALL_GROWING,
4377 static int ep_em_explodes_by_fire[] =
4380 EL_EM_DYNAMITE_ACTIVE,
4385 /* special EM style gems behaviour */
4386 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4387 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4388 level.em_slippery_gems);
4390 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4391 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4392 (level.em_slippery_gems &&
4393 engine_version > VERSION_IDENT(2,0,1,0)));
4395 /* special EM style explosion behaviour regarding chain reactions */
4396 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4397 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4398 level.em_explodes_by_fire);
4401 /* this is needed because some graphics depend on element properties */
4402 if (game_status == GAME_MODE_PLAYING)
4403 InitElementGraphicInfo();
4406 void InitElementPropertiesAfterLoading(int engine_version)
4410 /* set some other uninitialized values of custom elements in older levels */
4411 if (engine_version < VERSION_IDENT(3,1,0,0))
4413 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4415 int element = EL_CUSTOM_START + i;
4417 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4419 element_info[element].explosion_delay = 17;
4420 element_info[element].ignition_delay = 8;
4425 void InitElementPropertiesGfxElement()
4429 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4431 struct ElementInfo *ei = &element_info[i];
4433 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4437 static void InitGlobal()
4442 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4444 /* check if element_name_info entry defined for each element in "main.h" */
4445 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4446 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4448 element_info[i].token_name = element_name_info[i].token_name;
4449 element_info[i].class_name = element_name_info[i].class_name;
4450 element_info[i].editor_description= element_name_info[i].editor_description;
4453 /* create hash from image config list */
4454 image_config_hash = newSetupFileHash();
4455 for (i = 0; image_config[i].token != NULL; i++)
4456 setHashEntry(image_config_hash,
4457 image_config[i].token,
4458 image_config[i].value);
4460 /* create hash from element token list */
4461 element_token_hash = newSetupFileHash();
4462 for (i = 0; element_name_info[i].token_name != NULL; i++)
4463 setHashEntry(element_token_hash,
4464 element_name_info[i].token_name,
4467 /* create hash from graphic token list */
4468 graphic_token_hash = newSetupFileHash();
4469 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4470 if (strSuffix(image_config[i].value, ".png") ||
4471 strSuffix(image_config[i].value, ".pcx") ||
4472 strSuffix(image_config[i].value, ".wav") ||
4473 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4474 setHashEntry(graphic_token_hash,
4475 image_config[i].token,
4476 int2str(graphic++, 0));
4478 /* create hash from font token list */
4479 font_token_hash = newSetupFileHash();
4480 for (i = 0; font_info[i].token_name != NULL; i++)
4481 setHashEntry(font_token_hash,
4482 font_info[i].token_name,
4485 /* set default filenames for all cloned graphics in static configuration */
4486 for (i = 0; image_config[i].token != NULL; i++)
4488 if (strEqual(image_config[i].value, UNDEFINED_FILENAME))
4490 char *token = image_config[i].token;
4491 char *token_clone_from = getStringCat2(token, ".clone_from");
4492 char *token_cloned = getHashEntry(image_config_hash, token_clone_from);
4494 if (token_cloned != NULL)
4496 char *value_cloned = getHashEntry(image_config_hash, token_cloned);
4498 if (value_cloned != NULL)
4500 /* set default filename in static configuration */
4501 image_config[i].value = value_cloned;
4503 /* set default filename in image config hash */
4504 setHashEntry(image_config_hash, token, value_cloned);
4508 free(token_clone_from);
4512 /* always start with reliable default values (all elements) */
4513 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4514 ActiveElement[i] = i;
4516 /* now add all entries that have an active state (active elements) */
4517 for (i = 0; element_with_active_state[i].element != -1; i++)
4519 int element = element_with_active_state[i].element;
4520 int element_active = element_with_active_state[i].element_active;
4522 ActiveElement[element] = element_active;
4525 /* always start with reliable default values (all buttons) */
4526 for (i = 0; i < NUM_IMAGE_FILES; i++)
4527 ActiveButton[i] = i;
4529 /* now add all entries that have an active state (active buttons) */
4530 for (i = 0; button_with_active_state[i].button != -1; i++)
4532 int button = button_with_active_state[i].button;
4533 int button_active = button_with_active_state[i].button_active;
4535 ActiveButton[button] = button_active;
4538 /* always start with reliable default values (all fonts) */
4539 for (i = 0; i < NUM_FONTS; i++)
4542 /* now add all entries that have an active state (active fonts) */
4543 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4545 int font = font_with_active_state[i].font_nr;
4546 int font_active = font_with_active_state[i].font_nr_active;
4548 ActiveFont[font] = font_active;
4551 global.autoplay_leveldir = NULL;
4552 global.convert_leveldir = NULL;
4553 global.create_images_dir = NULL;
4555 global.frames_per_second = 0;
4557 global.border_status = GAME_MODE_MAIN;
4559 global.use_envelope_request = FALSE;
4562 void Execute_Command(char *command)
4566 if (strEqual(command, "print graphicsinfo.conf"))
4568 Print("# You can configure additional/alternative image files here.\n");
4569 Print("# (The entries below are default and therefore commented out.)\n");
4571 Print("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4573 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4576 for (i = 0; image_config[i].token != NULL; i++)
4577 Print("# %s\n", getFormattedSetupEntry(image_config[i].token,
4578 image_config[i].value));
4582 else if (strEqual(command, "print soundsinfo.conf"))
4584 Print("# You can configure additional/alternative sound files here.\n");
4585 Print("# (The entries below are default and therefore commented out.)\n");
4587 Print("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4589 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4592 for (i = 0; sound_config[i].token != NULL; i++)
4593 Print("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4594 sound_config[i].value));
4598 else if (strEqual(command, "print musicinfo.conf"))
4600 Print("# You can configure additional/alternative music files here.\n");
4601 Print("# (The entries below are default and therefore commented out.)\n");
4603 Print("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4605 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4608 for (i = 0; music_config[i].token != NULL; i++)
4609 Print("# %s\n", getFormattedSetupEntry(music_config[i].token,
4610 music_config[i].value));
4614 else if (strEqual(command, "print editorsetup.conf"))
4616 Print("# You can configure your personal editor element list here.\n");
4617 Print("# (The entries below are default and therefore commented out.)\n");
4620 /* this is needed to be able to check element list for cascade elements */
4621 InitElementPropertiesStatic();
4622 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4624 PrintEditorElementList();
4628 else if (strEqual(command, "print helpanim.conf"))
4630 Print("# You can configure different element help animations here.\n");
4631 Print("# (The entries below are default and therefore commented out.)\n");
4634 for (i = 0; helpanim_config[i].token != NULL; i++)
4636 Print("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4637 helpanim_config[i].value));
4639 if (strEqual(helpanim_config[i].token, "end"))
4645 else if (strEqual(command, "print helptext.conf"))
4647 Print("# You can configure different element help text here.\n");
4648 Print("# (The entries below are default and therefore commented out.)\n");
4651 for (i = 0; helptext_config[i].token != NULL; i++)
4652 Print("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4653 helptext_config[i].value));
4657 else if (strPrefix(command, "dump level "))
4659 char *filename = &command[11];
4661 if (!fileExists(filename))
4662 Error(ERR_EXIT, "cannot open file '%s'", filename);
4664 LoadLevelFromFilename(&level, filename);
4669 else if (strPrefix(command, "dump tape "))
4671 char *filename = &command[10];
4673 if (!fileExists(filename))
4674 Error(ERR_EXIT, "cannot open file '%s'", filename);
4676 LoadTapeFromFilename(filename);
4681 else if (strPrefix(command, "autotest ") ||
4682 strPrefix(command, "autoplay ") ||
4683 strPrefix(command, "autoffwd "))
4685 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
4687 global.autoplay_mode = (strPrefix(command, "autotest") ? AUTOPLAY_TEST :
4688 strPrefix(command, "autoplay") ? AUTOPLAY_PLAY :
4689 strPrefix(command, "autoffwd") ? AUTOPLAY_FFWD : 0);
4691 while (*str_ptr != '\0') /* continue parsing string */
4693 /* cut leading whitespace from string, replace it by string terminator */
4694 while (*str_ptr == ' ' || *str_ptr == '\t')
4697 if (*str_ptr == '\0') /* end of string reached */
4700 if (global.autoplay_leveldir == NULL) /* read level set string */
4702 global.autoplay_leveldir = str_ptr;
4703 global.autoplay_all = TRUE; /* default: play all tapes */
4705 for (i = 0; i < MAX_TAPES_PER_SET; i++)
4706 global.autoplay_level[i] = FALSE;
4708 else /* read level number string */
4710 int level_nr = atoi(str_ptr); /* get level_nr value */
4712 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
4713 global.autoplay_level[level_nr] = TRUE;
4715 global.autoplay_all = FALSE;
4718 /* advance string pointer to the next whitespace (or end of string) */
4719 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
4723 else if (strPrefix(command, "convert "))
4725 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
4726 char *str_ptr = strchr(str_copy, ' ');
4728 global.convert_leveldir = str_copy;
4729 global.convert_level_nr = -1;
4731 if (str_ptr != NULL) /* level number follows */
4733 *str_ptr++ = '\0'; /* terminate leveldir string */
4734 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
4737 else if (strPrefix(command, "create images "))
4739 global.create_images_dir = getStringCopy(&command[14]);
4741 if (access(global.create_images_dir, W_OK) != 0)
4742 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
4743 global.create_images_dir);
4745 else if (strPrefix(command, "create CE image "))
4747 CreateCustomElementImages(&command[16]);
4753 #if defined(TARGET_SDL2)
4754 else if (strEqual(command, "SDL_ListModes"))
4756 SDL_Init(SDL_INIT_VIDEO);
4758 int num_displays = SDL_GetNumVideoDisplays();
4760 // check if there are any displays available
4761 if (num_displays < 0)
4763 Print("No displays available: %s\n", SDL_GetError());
4768 for (i = 0; i < num_displays; i++)
4770 int num_modes = SDL_GetNumDisplayModes(i);
4773 Print("Available display modes for display %d:\n", i);
4775 // check if there are any display modes available for this display
4778 Print("No display modes available for display %d: %s\n",
4784 for (j = 0; j < num_modes; j++)
4786 SDL_DisplayMode mode;
4788 if (SDL_GetDisplayMode(i, j, &mode) < 0)
4790 Print("Cannot get display mode %d for display %d: %s\n",
4791 j, i, SDL_GetError());
4796 Print("- %d x %d\n", mode.w, mode.h);
4802 #elif defined(TARGET_SDL)
4803 else if (strEqual(command, "SDL_ListModes"))
4808 SDL_Init(SDL_INIT_VIDEO);
4810 /* get available fullscreen/hardware modes */
4811 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
4813 /* check if there are any modes available */
4816 Print("No modes available!\n");
4821 /* check if our resolution is restricted */
4822 if (modes == (SDL_Rect **)-1)
4824 Print("All resolutions available.\n");
4828 Print("Available display modes:\n");
4830 for (i = 0; modes[i]; i++)
4831 Print("- %d x %d\n", modes[i]->w, modes[i]->h);
4841 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4845 static void InitSetup()
4847 LoadSetup(); /* global setup info */
4849 /* set some options from setup file */
4851 if (setup.options.verbose)
4852 options.verbose = TRUE;
4855 static void InitGameInfo()
4857 game.restart_level = FALSE;
4860 static void InitPlayerInfo()
4864 /* choose default local player */
4865 local_player = &stored_player[0];
4867 for (i = 0; i < MAX_PLAYERS; i++)
4868 stored_player[i].connected = FALSE;
4870 local_player->connected = TRUE;
4873 static void InitArtworkInfo()
4878 static char *get_string_in_brackets(char *string)
4880 char *string_in_brackets = checked_malloc(strlen(string) + 3);
4882 sprintf(string_in_brackets, "[%s]", string);
4884 return string_in_brackets;
4887 static char *get_level_id_suffix(int id_nr)
4889 char *id_suffix = checked_malloc(1 + 3 + 1);
4891 if (id_nr < 0 || id_nr > 999)
4894 sprintf(id_suffix, ".%03d", id_nr);
4899 static void InitArtworkConfig()
4901 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
4902 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
4903 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
4904 static char *action_id_suffix[NUM_ACTIONS + 1];
4905 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
4906 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
4907 static char *level_id_suffix[MAX_LEVELS + 1];
4908 static char *dummy[1] = { NULL };
4909 static char *ignore_generic_tokens[] =
4915 static char **ignore_image_tokens;
4916 static char **ignore_sound_tokens;
4917 static char **ignore_music_tokens;
4918 int num_ignore_generic_tokens;
4919 int num_ignore_image_tokens;
4920 int num_ignore_sound_tokens;
4921 int num_ignore_music_tokens;
4924 /* dynamically determine list of generic tokens to be ignored */
4925 num_ignore_generic_tokens = 0;
4926 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
4927 num_ignore_generic_tokens++;
4929 /* dynamically determine list of image tokens to be ignored */
4930 num_ignore_image_tokens = num_ignore_generic_tokens;
4931 for (i = 0; image_config_vars[i].token != NULL; i++)
4932 num_ignore_image_tokens++;
4933 ignore_image_tokens =
4934 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
4935 for (i = 0; i < num_ignore_generic_tokens; i++)
4936 ignore_image_tokens[i] = ignore_generic_tokens[i];
4937 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
4938 ignore_image_tokens[num_ignore_generic_tokens + i] =
4939 image_config_vars[i].token;
4940 ignore_image_tokens[num_ignore_image_tokens] = NULL;
4942 /* dynamically determine list of sound tokens to be ignored */
4943 num_ignore_sound_tokens = num_ignore_generic_tokens;
4944 ignore_sound_tokens =
4945 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
4946 for (i = 0; i < num_ignore_generic_tokens; i++)
4947 ignore_sound_tokens[i] = ignore_generic_tokens[i];
4948 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
4950 /* dynamically determine list of music tokens to be ignored */
4951 num_ignore_music_tokens = num_ignore_generic_tokens;
4952 ignore_music_tokens =
4953 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
4954 for (i = 0; i < num_ignore_generic_tokens; i++)
4955 ignore_music_tokens[i] = ignore_generic_tokens[i];
4956 ignore_music_tokens[num_ignore_music_tokens] = NULL;
4958 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4959 image_id_prefix[i] = element_info[i].token_name;
4960 for (i = 0; i < NUM_FONTS; i++)
4961 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
4962 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
4964 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4965 sound_id_prefix[i] = element_info[i].token_name;
4966 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4967 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
4968 get_string_in_brackets(element_info[i].class_name);
4969 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
4971 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
4972 music_id_prefix[i] = music_prefix_info[i].prefix;
4973 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
4975 for (i = 0; i < NUM_ACTIONS; i++)
4976 action_id_suffix[i] = element_action_info[i].suffix;
4977 action_id_suffix[NUM_ACTIONS] = NULL;
4979 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
4980 direction_id_suffix[i] = element_direction_info[i].suffix;
4981 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
4983 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
4984 special_id_suffix[i] = special_suffix_info[i].suffix;
4985 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
4987 for (i = 0; i < MAX_LEVELS; i++)
4988 level_id_suffix[i] = get_level_id_suffix(i);
4989 level_id_suffix[MAX_LEVELS] = NULL;
4991 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
4992 image_id_prefix, action_id_suffix, direction_id_suffix,
4993 special_id_suffix, ignore_image_tokens);
4994 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
4995 sound_id_prefix, action_id_suffix, dummy,
4996 special_id_suffix, ignore_sound_tokens);
4997 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
4998 music_id_prefix, special_id_suffix, level_id_suffix,
4999 dummy, ignore_music_tokens);
5002 static void InitMixer()
5009 void InitGfxBuffers()
5011 static int win_xsize_last = -1;
5012 static int win_ysize_last = -1;
5014 /* create additional image buffers for double-buffering and cross-fading */
5016 if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
5018 /* may contain content for cross-fading -- only re-create if changed */
5019 ReCreateBitmap(&bitmap_db_store, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5020 ReCreateBitmap(&bitmap_db_cross, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5022 win_xsize_last = WIN_XSIZE;
5023 win_ysize_last = WIN_YSIZE;
5026 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE, DEFAULT_DEPTH);
5027 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE, DEFAULT_DEPTH);
5028 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE, DEFAULT_DEPTH);
5029 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE, DEFAULT_DEPTH);
5030 ReCreateBitmap(&bitmap_db_toons, FULL_SXSIZE, FULL_SYSIZE, DEFAULT_DEPTH);
5032 /* initialize screen properties */
5033 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5034 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5036 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5037 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5038 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5039 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5040 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5041 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5043 /* required if door size definitions have changed */
5044 InitGraphicCompatibilityInfo_Doors();
5046 InitGfxBuffers_EM();
5047 InitGfxBuffers_SP();
5052 struct GraphicInfo *graphic_info_last = graphic_info;
5053 char *filename_font_initial = NULL;
5054 char *filename_anim_initial = NULL;
5055 Bitmap *bitmap_font_initial = NULL;
5059 /* determine settings for initial font (for displaying startup messages) */
5060 for (i = 0; image_config[i].token != NULL; i++)
5062 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5064 char font_token[128];
5067 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5068 len_font_token = strlen(font_token);
5070 if (strEqual(image_config[i].token, font_token))
5071 filename_font_initial = image_config[i].value;
5072 else if (strlen(image_config[i].token) > len_font_token &&
5073 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5075 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5076 font_initial[j].src_x = atoi(image_config[i].value);
5077 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5078 font_initial[j].src_y = atoi(image_config[i].value);
5079 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5080 font_initial[j].width = atoi(image_config[i].value);
5081 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5082 font_initial[j].height = atoi(image_config[i].value);
5087 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5089 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5090 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5093 if (filename_font_initial == NULL) /* should not happen */
5094 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5097 InitGfxCustomArtworkInfo();
5098 InitGfxOtherSettings();
5100 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5102 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5103 font_initial[j].bitmap = bitmap_font_initial;
5105 InitFontGraphicInfo();
5107 font_height = getFontHeight(FC_RED);
5109 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
5110 DrawInitText(setup.internal.program_copyright, 50, FC_RED);
5111 DrawInitText(setup.internal.program_website, WIN_YSIZE - 20 - font_height,
5114 DrawInitText("Loading graphics", 120, FC_GREEN);
5116 /* initialize settings for busy animation with default values */
5117 int parameter[NUM_GFX_ARGS];
5118 for (i = 0; i < NUM_GFX_ARGS; i++)
5119 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5120 image_config_suffix[i].token,
5121 image_config_suffix[i].type);
5123 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5124 int len_anim_token = strlen(anim_token);
5126 /* read settings for busy animation from default custom artwork config */
5127 char *gfx_config_filename = getPath3(options.graphics_directory,
5129 GRAPHICSINFO_FILENAME);
5131 if (fileExists(gfx_config_filename))
5133 SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
5135 if (setup_file_hash)
5137 char *filename = getHashEntry(setup_file_hash, anim_token);
5141 filename_anim_initial = getStringCopy(filename);
5143 for (j = 0; image_config_suffix[j].token != NULL; j++)
5145 int type = image_config_suffix[j].type;
5146 char *suffix = image_config_suffix[j].token;
5147 char *token = getStringCat2(anim_token, suffix);
5148 char *value = getHashEntry(setup_file_hash, token);
5150 checked_free(token);
5153 parameter[j] = get_graphic_parameter_value(value, suffix, type);
5157 freeSetupFileHash(setup_file_hash);
5161 if (filename_anim_initial == NULL)
5163 /* read settings for busy animation from static default artwork config */
5164 for (i = 0; image_config[i].token != NULL; i++)
5166 if (strEqual(image_config[i].token, anim_token))
5167 filename_anim_initial = getStringCopy(image_config[i].value);
5168 else if (strlen(image_config[i].token) > len_anim_token &&
5169 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5171 for (j = 0; image_config_suffix[j].token != NULL; j++)
5173 if (strEqual(&image_config[i].token[len_anim_token],
5174 image_config_suffix[j].token))
5176 get_graphic_parameter_value(image_config[i].value,
5177 image_config_suffix[j].token,
5178 image_config_suffix[j].type);
5184 if (filename_anim_initial == NULL) /* should not happen */
5185 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5187 anim_initial.bitmaps =
5188 checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5190 anim_initial.bitmaps[IMG_BITMAP_STANDARD] =
5191 LoadCustomImage(filename_anim_initial);
5193 checked_free(filename_anim_initial);
5195 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
5197 set_graphic_parameters_ext(0, parameter, anim_initial.bitmaps);
5199 graphic_info = graphic_info_last;
5201 init.busy.width = anim_initial.width;
5202 init.busy.height = anim_initial.height;
5204 InitMenuDesignSettings_Static();
5205 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5207 /* use copy of busy animation to prevent change while reloading artwork */
5211 void InitGfxBackground()
5213 fieldbuffer = bitmap_db_field;
5214 SetDrawtoField(DRAW_BACKBUFFER);
5216 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5218 redraw_mask = REDRAW_ALL;
5221 static void InitLevelInfo()
5223 LoadLevelInfo(); /* global level info */
5224 LoadLevelSetup_LastSeries(); /* last played series info */
5225 LoadLevelSetup_SeriesInfo(); /* last played level info */
5227 if (global.autoplay_leveldir &&
5228 global.autoplay_mode != AUTOPLAY_TEST)
5230 leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
5231 global.autoplay_leveldir);
5232 if (leveldir_current == NULL)
5233 leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
5237 static void InitLevelArtworkInfo()
5239 LoadLevelArtworkInfo();
5242 static void InitImages()
5244 print_timestamp_init("InitImages");
5247 printf("::: leveldir_current->identifier == '%s'\n",
5248 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5249 printf("::: leveldir_current->graphics_path == '%s'\n",
5250 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5251 printf("::: leveldir_current->graphics_set == '%s'\n",
5252 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5253 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5254 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5257 setLevelArtworkDir(artwork.gfx_first);
5260 printf("::: leveldir_current->identifier == '%s'\n",
5261 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5262 printf("::: leveldir_current->graphics_path == '%s'\n",
5263 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5264 printf("::: leveldir_current->graphics_set == '%s'\n",
5265 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5266 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5267 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5271 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5272 leveldir_current->identifier,
5273 artwork.gfx_current_identifier,
5274 artwork.gfx_current->identifier,
5275 leveldir_current->graphics_set,
5276 leveldir_current->graphics_path);
5279 UPDATE_BUSY_STATE();
5281 ReloadCustomImages();
5282 print_timestamp_time("ReloadCustomImages");
5284 UPDATE_BUSY_STATE();
5286 LoadCustomElementDescriptions();
5287 print_timestamp_time("LoadCustomElementDescriptions");
5289 UPDATE_BUSY_STATE();
5291 LoadMenuDesignSettings();
5292 print_timestamp_time("LoadMenuDesignSettings");
5294 UPDATE_BUSY_STATE();
5296 ReinitializeGraphics();
5297 print_timestamp_time("ReinitializeGraphics");
5299 UPDATE_BUSY_STATE();
5301 print_timestamp_done("InitImages");
5304 static void InitSound(char *identifier)
5306 print_timestamp_init("InitSound");
5308 if (identifier == NULL)
5309 identifier = artwork.snd_current->identifier;
5311 /* set artwork path to send it to the sound server process */
5312 setLevelArtworkDir(artwork.snd_first);
5314 InitReloadCustomSounds(identifier);
5315 print_timestamp_time("InitReloadCustomSounds");
5317 ReinitializeSounds();
5318 print_timestamp_time("ReinitializeSounds");
5320 print_timestamp_done("InitSound");
5323 static void InitMusic(char *identifier)
5325 print_timestamp_init("InitMusic");
5327 if (identifier == NULL)
5328 identifier = artwork.mus_current->identifier;
5330 /* set artwork path to send it to the sound server process */
5331 setLevelArtworkDir(artwork.mus_first);
5333 InitReloadCustomMusic(identifier);
5334 print_timestamp_time("InitReloadCustomMusic");
5336 ReinitializeMusic();
5337 print_timestamp_time("ReinitializeMusic");
5339 print_timestamp_done("InitMusic");
5342 void InitNetworkServer()
5344 #if defined(NETWORK_AVALIABLE)
5348 if (!options.network)
5351 #if defined(NETWORK_AVALIABLE)
5352 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5354 if (!ConnectToServer(options.server_host, options.server_port))
5355 Error(ERR_EXIT, "cannot connect to network game server");
5357 SendToServer_PlayerName(setup.player_name);
5358 SendToServer_ProtocolVersion();
5361 SendToServer_NrWanted(nr_wanted);
5365 static boolean CheckArtworkConfigForCustomElements(char *filename)
5367 SetupFileHash *setup_file_hash;
5368 boolean redefined_ce_found = FALSE;
5370 /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */
5372 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5374 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5376 char *token = HASH_ITERATION_TOKEN(itr);
5378 if (strPrefix(token, "custom_"))
5380 redefined_ce_found = TRUE;
5385 END_HASH_ITERATION(setup_file_hash, itr)
5387 freeSetupFileHash(setup_file_hash);
5390 return redefined_ce_found;
5393 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5395 char *filename_base, *filename_local;
5396 boolean redefined_ce_found = FALSE;
5398 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5401 printf("::: leveldir_current->identifier == '%s'\n",
5402 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5403 printf("::: leveldir_current->graphics_path == '%s'\n",
5404 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5405 printf("::: leveldir_current->graphics_set == '%s'\n",
5406 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5407 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5408 leveldir_current == NULL ? "[NULL]" :
5409 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5412 /* first look for special artwork configured in level series config */
5413 filename_base = getCustomArtworkLevelConfigFilename(type);
5416 printf("::: filename_base == '%s'\n", filename_base);
5419 if (fileExists(filename_base))
5420 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5422 filename_local = getCustomArtworkConfigFilename(type);
5425 printf("::: filename_local == '%s'\n", filename_local);
5428 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5429 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5432 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5435 return redefined_ce_found;
5438 static void InitOverrideArtwork()
5440 boolean redefined_ce_found = FALSE;
5442 /* to check if this level set redefines any CEs, do not use overriding */
5443 gfx.override_level_graphics = FALSE;
5444 gfx.override_level_sounds = FALSE;
5445 gfx.override_level_music = FALSE;
5447 /* now check if this level set has definitions for custom elements */
5448 if (setup.override_level_graphics == AUTO ||
5449 setup.override_level_sounds == AUTO ||
5450 setup.override_level_music == AUTO)
5451 redefined_ce_found =
5452 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5453 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5454 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5457 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5460 if (redefined_ce_found)
5462 /* this level set has CE definitions: change "AUTO" to "FALSE" */
5463 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5464 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
5465 gfx.override_level_music = (setup.override_level_music == TRUE);
5469 /* this level set has no CE definitions: change "AUTO" to "TRUE" */
5470 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5471 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
5472 gfx.override_level_music = (setup.override_level_music != FALSE);
5476 printf("::: => %d, %d, %d\n",
5477 gfx.override_level_graphics,
5478 gfx.override_level_sounds,
5479 gfx.override_level_music);
5483 static char *getNewArtworkIdentifier(int type)
5485 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5486 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5487 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5488 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5489 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5490 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5491 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5492 char *leveldir_identifier = leveldir_current->identifier;
5493 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
5494 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5495 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5496 char *artwork_current_identifier;
5497 char *artwork_new_identifier = NULL; /* default: nothing has changed */
5499 /* leveldir_current may be invalid (level group, parent link) */
5500 if (!validLevelSeries(leveldir_current))
5503 /* 1st step: determine artwork set to be activated in descending order:
5504 --------------------------------------------------------------------
5505 1. setup artwork (when configured to override everything else)
5506 2. artwork set configured in "levelinfo.conf" of current level set
5507 (artwork in level directory will have priority when loading later)
5508 3. artwork in level directory (stored in artwork sub-directory)
5509 4. setup artwork (currently configured in setup menu) */
5511 if (setup_override_artwork)
5512 artwork_current_identifier = setup_artwork_set;
5513 else if (leveldir_artwork_set != NULL)
5514 artwork_current_identifier = leveldir_artwork_set;
5515 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5516 artwork_current_identifier = leveldir_identifier;
5518 artwork_current_identifier = setup_artwork_set;
5521 /* 2nd step: check if it is really needed to reload artwork set
5522 ------------------------------------------------------------ */
5524 /* ---------- reload if level set and also artwork set has changed ------- */
5525 if (leveldir_current_identifier[type] != leveldir_identifier &&
5526 (last_has_level_artwork_set[type] || has_level_artwork_set))
5527 artwork_new_identifier = artwork_current_identifier;
5529 leveldir_current_identifier[type] = leveldir_identifier;
5530 last_has_level_artwork_set[type] = has_level_artwork_set;
5532 /* ---------- reload if "override artwork" setting has changed ----------- */
5533 if (last_override_level_artwork[type] != setup_override_artwork)
5534 artwork_new_identifier = artwork_current_identifier;
5536 last_override_level_artwork[type] = setup_override_artwork;
5538 /* ---------- reload if current artwork identifier has changed ----------- */
5539 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5540 artwork_current_identifier))
5541 artwork_new_identifier = artwork_current_identifier;
5543 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5545 /* ---------- do not reload directly after starting ---------------------- */
5546 if (!initialized[type])
5547 artwork_new_identifier = NULL;
5549 initialized[type] = TRUE;
5551 return artwork_new_identifier;
5554 void ReloadCustomArtwork(int force_reload)
5556 int last_game_status = game_status; /* save current game status */
5557 char *gfx_new_identifier;
5558 char *snd_new_identifier;
5559 char *mus_new_identifier;
5560 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5561 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5562 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5563 boolean reload_needed;
5565 InitOverrideArtwork();
5567 force_reload_gfx |= AdjustGraphicsForEMC();
5569 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5570 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5571 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5573 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
5574 snd_new_identifier != NULL || force_reload_snd ||
5575 mus_new_identifier != NULL || force_reload_mus);
5580 print_timestamp_init("ReloadCustomArtwork");
5582 game_status = GAME_MODE_LOADING;
5584 FadeOut(REDRAW_ALL);
5586 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5587 print_timestamp_time("ClearRectangle");
5591 if (gfx_new_identifier != NULL || force_reload_gfx)
5594 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5595 artwork.gfx_current_identifier,
5597 artwork.gfx_current->identifier,
5598 leveldir_current->graphics_set);
5602 print_timestamp_time("InitImages");
5605 if (snd_new_identifier != NULL || force_reload_snd)
5607 InitSound(snd_new_identifier);
5608 print_timestamp_time("InitSound");
5611 if (mus_new_identifier != NULL || force_reload_mus)
5613 InitMusic(mus_new_identifier);
5614 print_timestamp_time("InitMusic");
5617 game_status = last_game_status; /* restore current game status */
5619 init_last = init; /* switch to new busy animation */
5621 FadeOut(REDRAW_ALL);
5623 RedrawGlobalBorder();
5625 /* force redraw of (open or closed) door graphics */
5626 SetDoorState(DOOR_OPEN_ALL);
5627 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5629 FadeSetEnterScreen();
5630 FadeSkipNextFadeOut();
5632 print_timestamp_done("ReloadCustomArtwork");
5634 LimitScreenUpdates(FALSE);
5637 void KeyboardAutoRepeatOffUnlessAutoplay()
5639 if (global.autoplay_leveldir == NULL)
5640 KeyboardAutoRepeatOff();
5643 void DisplayExitMessage(char *format, va_list ap)
5645 // check if draw buffer and fonts for exit message are already available
5646 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
5649 int font_1 = FC_RED;
5650 int font_2 = FC_YELLOW;
5651 int font_3 = FC_BLUE;
5652 int font_width = getFontWidth(font_2);
5653 int font_height = getFontHeight(font_2);
5656 int sxsize = WIN_XSIZE - 2 * sx;
5657 int sysize = WIN_YSIZE - 2 * sy;
5658 int line_length = sxsize / font_width;
5659 int max_lines = sysize / font_height;
5660 int num_lines_printed;
5664 gfx.sxsize = sxsize;
5665 gfx.sysize = sysize;
5669 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5671 DrawTextSCentered(sy, font_1, "Fatal error:");
5672 sy += 3 * font_height;;
5675 DrawTextBufferVA(sx, sy, format, ap, font_2,
5676 line_length, line_length, max_lines,
5677 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5678 sy += (num_lines_printed + 3) * font_height;
5680 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
5681 sy += 3 * font_height;
5684 DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2,
5685 line_length, line_length, max_lines,
5686 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5688 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
5690 redraw_mask = REDRAW_ALL;
5692 /* force drawing exit message even if screen updates are currently limited */
5693 LimitScreenUpdates(FALSE);
5697 /* deactivate toons on error message screen */
5698 setup.toons = FALSE;
5700 WaitForEventToContinue();
5704 /* ========================================================================= */
5706 /* ========================================================================= */
5710 print_timestamp_init("OpenAll");
5712 game_status = GAME_MODE_LOADING;
5716 InitGlobal(); /* initialize some global variables */
5718 print_timestamp_time("[init global stuff]");
5722 print_timestamp_time("[init setup/config stuff (1)]");
5724 if (options.execute_command)
5725 Execute_Command(options.execute_command);
5727 if (options.serveronly)
5729 #if defined(PLATFORM_UNIX)
5730 NetworkServer(options.server_port, options.serveronly);
5732 Error(ERR_WARN, "networking only supported in Unix version");
5735 exit(0); /* never reached, server loops forever */
5739 print_timestamp_time("[init setup/config stuff (2)]");
5741 print_timestamp_time("[init setup/config stuff (3)]");
5742 InitArtworkInfo(); /* needed before loading gfx, sound & music */
5743 print_timestamp_time("[init setup/config stuff (4)]");
5744 InitArtworkConfig(); /* needed before forking sound child process */
5745 print_timestamp_time("[init setup/config stuff (5)]");
5747 print_timestamp_time("[init setup/config stuff (6)]");
5749 InitRND(NEW_RANDOMIZE);
5750 InitSimpleRandom(NEW_RANDOMIZE);
5754 print_timestamp_time("[init setup/config stuff]");
5757 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
5759 InitEventFilter(FilterEvents);
5761 print_timestamp_time("[init video stuff]");
5763 InitElementPropertiesStatic();
5764 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5765 InitElementPropertiesGfxElement();
5767 print_timestamp_time("[init element properties stuff]");
5771 print_timestamp_time("InitGfx");
5774 print_timestamp_time("InitLevelInfo");
5776 InitLevelArtworkInfo();
5777 print_timestamp_time("InitLevelArtworkInfo");
5779 InitOverrideArtwork(); /* needs to know current level directory */
5780 print_timestamp_time("InitOverrideArtwork");
5782 InitImages(); /* needs to know current level directory */
5783 print_timestamp_time("InitImages");
5785 InitSound(NULL); /* needs to know current level directory */
5786 print_timestamp_time("InitSound");
5788 InitMusic(NULL); /* needs to know current level directory */
5789 print_timestamp_time("InitMusic");
5791 InitGfxBackground();
5796 if (global.autoplay_leveldir)
5801 else if (global.convert_leveldir)
5806 else if (global.create_images_dir)
5808 CreateLevelSketchImages();
5812 game_status = GAME_MODE_MAIN;
5814 FadeSetEnterScreen();
5815 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
5816 FadeSkipNextFadeOut();
5818 print_timestamp_time("[post-artwork]");
5820 print_timestamp_done("OpenAll");
5824 InitNetworkServer();
5827 Error(ERR_DEBUG, "::: SDL_GetBasePath() == '%s'",
5829 Error(ERR_DEBUG, "::: SDL_GetPrefPath() == '%s'",
5830 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
5831 #if defined(PLATFORM_ANDROID)
5832 Error(ERR_DEBUG, "::: SDL_AndroidGetInternalStoragePath() == '%s'",
5833 SDL_AndroidGetInternalStoragePath());
5834 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStoragePath() == '%s'",
5835 SDL_AndroidGetExternalStoragePath());
5836 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStorageState() == '%s'",
5837 (SDL_AndroidGetExternalStorageState() ==
5838 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "read" :
5839 SDL_AndroidGetExternalStorageState() ==
5840 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "write" : "not available"));
5845 void CloseAllAndExit(int exit_value)
5850 CloseAudio(); /* called after freeing sounds (needed for SDL) */
5857 #if defined(TARGET_SDL)
5858 #if defined(TARGET_SDL2)
5860 // set a flag to tell the network server thread to quit and wait for it
5861 // using SDL_WaitThread()
5863 if (network_server) /* terminate network server */
5864 SDL_KillThread(server_thread);
5868 CloseVideoDisplay();
5869 ClosePlatformDependentStuff();
5871 if (exit_value != 0)
5873 /* fall back to default level set (current set may have caused an error) */
5874 SaveLevelSetup_LastSeries_Deactivate();
5876 /* tell user where to find error log file which may contain more details */
5877 // (error notification now directly displayed on screen inside R'n'D
5878 // NotifyUserAboutErrorFile(); /* currently only works for Windows */