1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2006 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
14 #include "libgame/libgame.h"
29 #include "conf_e2g.c" /* include auto-generated data structure definitions */
30 #include "conf_esg.c" /* include auto-generated data structure definitions */
31 #include "conf_e2s.c" /* include auto-generated data structure definitions */
32 #include "conf_fnt.c" /* include auto-generated data structure definitions */
33 #include "conf_g2s.c" /* include auto-generated data structure definitions */
34 #include "conf_g2m.c" /* include auto-generated data structure definitions */
35 #include "conf_act.c" /* include auto-generated data structure definitions */
38 #define CONFIG_TOKEN_FONT_INITIAL "font.initial"
41 static struct FontBitmapInfo font_initial[NUM_INITIAL_FONTS];
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
88 FreeLevelEditorGadgets();
97 static boolean gadgets_initialized = FALSE;
99 if (gadgets_initialized)
102 CreateLevelEditorGadgets();
106 CreateScreenGadgets();
108 InitGadgetsSoundCallback(PlaySoundActivating, PlaySoundSelecting);
110 gadgets_initialized = TRUE;
113 inline void InitElementSmallImagesScaledUp(int graphic)
116 struct FileInfo *fi = getImageListEntryFromImageID(graphic);
118 printf("::: '%s' -> '%s'\n", fi->token, fi->filename);
121 CreateImageWithSmallImages(graphic, graphic_info[graphic].scale_up_factor);
124 void InitElementSmallImages()
126 static int special_graphics[] =
128 IMG_EDITOR_ELEMENT_BORDER,
129 IMG_EDITOR_ELEMENT_BORDER_INPUT,
130 IMG_EDITOR_CASCADE_LIST,
131 IMG_EDITOR_CASCADE_LIST_ACTIVE,
134 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
135 int num_property_mappings = getImageListPropertyMappingSize();
138 /* initialize normal images from static configuration */
139 for (i = 0; element_to_graphic[i].element > -1; i++)
140 InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
142 /* initialize special images from static configuration */
143 for (i = 0; element_to_special_graphic[i].element > -1; i++)
144 InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
146 /* initialize images from dynamic configuration (may be elements or other) */
147 for (i = 0; i < num_property_mappings; i++)
148 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
150 /* initialize special images from above list (non-element images) */
151 for (i = 0; special_graphics[i] > -1; i++)
152 InitElementSmallImagesScaledUp(special_graphics[i]);
155 void InitScaledImages()
159 /* scale normal images from static configuration, if not already scaled */
160 for (i = 0; i < NUM_IMAGE_FILES; i++)
161 ScaleImage(i, graphic_info[i].scale_up_factor);
165 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
166 void SetBitmaps_EM(Bitmap **em_bitmap)
168 em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
169 em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].bitmap;
173 static int getFontBitmapID(int font_nr)
177 if (game_status >= GAME_MODE_TITLE_INITIAL &&
178 game_status <= GAME_MODE_PSEUDO_PREVIEW)
179 special = game_status;
180 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
181 special = GFX_SPECIAL_ARG_MAIN;
183 else if (game_status == GAME_MODE_PLAYING)
184 special = GFX_SPECIAL_ARG_DOOR;
188 return font_info[font_nr].special_bitmap_id[special];
193 static int getFontFromToken(char *token)
197 /* !!! OPTIMIZE THIS BY USING HASH !!! */
198 for (i = 0; i < NUM_FONTS; i++)
199 if (strEqual(token, font_info[i].token_name))
202 /* if font not found, use reliable default value */
203 return FONT_INITIAL_1;
206 void InitFontGraphicInfo()
208 static struct FontBitmapInfo *font_bitmap_info = NULL;
209 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
210 int num_property_mappings = getImageListPropertyMappingSize();
211 int num_font_bitmaps = NUM_FONTS;
214 if (graphic_info == NULL) /* still at startup phase */
216 InitFontInfo(font_initial, NUM_INITIAL_FONTS,
217 getFontBitmapID, getFontFromToken);
222 /* ---------- initialize font graphic definitions ---------- */
224 /* always start with reliable default values (normal font graphics) */
225 for (i = 0; i < NUM_FONTS; i++)
226 font_info[i].graphic = IMG_FONT_INITIAL_1;
228 /* initialize normal font/graphic mapping from static configuration */
229 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
231 int font_nr = font_to_graphic[i].font_nr;
232 int special = font_to_graphic[i].special;
233 int graphic = font_to_graphic[i].graphic;
238 font_info[font_nr].graphic = graphic;
241 /* always start with reliable default values (special font graphics) */
242 for (i = 0; i < NUM_FONTS; i++)
244 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
246 font_info[i].special_graphic[j] = font_info[i].graphic;
247 font_info[i].special_bitmap_id[j] = i;
251 /* initialize special font/graphic mapping from static configuration */
252 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
254 int font_nr = font_to_graphic[i].font_nr;
255 int special = font_to_graphic[i].special;
256 int graphic = font_to_graphic[i].graphic;
257 int base_graphic = font2baseimg(font_nr);
259 if (IS_SPECIAL_GFX_ARG(special))
261 boolean base_redefined =
262 getImageListEntryFromImageID(base_graphic)->redefined;
263 boolean special_redefined =
264 getImageListEntryFromImageID(graphic)->redefined;
265 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
267 /* if the base font ("font.title_1", for example) has been redefined,
268 but not the special font ("font.title_1.LEVELS", for example), do not
269 use an existing (in this case considered obsolete) special font
270 anymore, but use the automatically determined default font */
271 /* special case: cloned special fonts must be explicitly redefined,
272 but are not automatically redefined by redefining base font */
273 if (base_redefined && !special_redefined && !special_cloned)
276 font_info[font_nr].special_graphic[special] = graphic;
277 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
282 /* initialize special font/graphic mapping from dynamic configuration */
283 for (i = 0; i < num_property_mappings; i++)
285 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
286 int special = property_mapping[i].ext3_index;
287 int graphic = property_mapping[i].artwork_index;
292 if (IS_SPECIAL_GFX_ARG(special))
294 font_info[font_nr].special_graphic[special] = graphic;
295 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
300 /* correct special font/graphic mapping for cloned fonts for downwards
301 compatibility of PREVIEW fonts -- this is only needed for implicit
302 redefinition of special font by redefined base font, and only if other
303 fonts are cloned from this special font (like in the "Zelda" level set) */
304 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
306 int font_nr = font_to_graphic[i].font_nr;
307 int special = font_to_graphic[i].special;
308 int graphic = font_to_graphic[i].graphic;
310 if (IS_SPECIAL_GFX_ARG(special))
312 boolean special_redefined =
313 getImageListEntryFromImageID(graphic)->redefined;
314 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
316 if (special_cloned && !special_redefined)
320 for (j = 0; font_to_graphic[j].font_nr > -1; j++)
322 int font_nr2 = font_to_graphic[j].font_nr;
323 int special2 = font_to_graphic[j].special;
324 int graphic2 = font_to_graphic[j].graphic;
326 if (IS_SPECIAL_GFX_ARG(special2) &&
327 graphic2 == graphic_info[graphic].clone_from)
329 font_info[font_nr].special_graphic[special] =
330 font_info[font_nr2].special_graphic[special2];
331 font_info[font_nr].special_bitmap_id[special] =
332 font_info[font_nr2].special_bitmap_id[special2];
339 /* reset non-redefined ".active" font graphics if normal font is redefined */
340 /* (this different treatment is needed because normal and active fonts are
341 independently defined ("active" is not a property of font definitions!) */
342 for (i = 0; i < NUM_FONTS; i++)
344 int font_nr_base = i;
345 int font_nr_active = FONT_ACTIVE(font_nr_base);
347 /* check only those fonts with exist as normal and ".active" variant */
348 if (font_nr_base != font_nr_active)
350 int base_graphic = font_info[font_nr_base].graphic;
351 int active_graphic = font_info[font_nr_active].graphic;
352 boolean base_redefined =
353 getImageListEntryFromImageID(base_graphic)->redefined;
354 boolean active_redefined =
355 getImageListEntryFromImageID(active_graphic)->redefined;
357 /* if the base font ("font.menu_1", for example) has been redefined,
358 but not the active font ("font.menu_1.active", for example), do not
359 use an existing (in this case considered obsolete) active font
360 anymore, but use the automatically determined default font */
361 if (base_redefined && !active_redefined)
362 font_info[font_nr_active].graphic = base_graphic;
364 /* now also check each "special" font (which may be the same as above) */
365 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
367 int base_graphic = font_info[font_nr_base].special_graphic[j];
368 int active_graphic = font_info[font_nr_active].special_graphic[j];
369 boolean base_redefined =
370 getImageListEntryFromImageID(base_graphic)->redefined;
371 boolean active_redefined =
372 getImageListEntryFromImageID(active_graphic)->redefined;
374 /* same as above, but check special graphic definitions, for example:
375 redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN" */
376 if (base_redefined && !active_redefined)
378 font_info[font_nr_active].special_graphic[j] =
379 font_info[font_nr_base].special_graphic[j];
380 font_info[font_nr_active].special_bitmap_id[j] =
381 font_info[font_nr_base].special_bitmap_id[j];
387 /* ---------- initialize font bitmap array ---------- */
389 if (font_bitmap_info != NULL)
390 FreeFontInfo(font_bitmap_info);
393 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
395 /* ---------- initialize font bitmap definitions ---------- */
397 for (i = 0; i < NUM_FONTS; i++)
399 if (i < NUM_INITIAL_FONTS)
401 font_bitmap_info[i] = font_initial[i];
405 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
407 int font_bitmap_id = font_info[i].special_bitmap_id[j];
408 int graphic = font_info[i].special_graphic[j];
410 /* set 'graphic_info' for font entries, if uninitialized (guessed) */
411 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
413 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
414 graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
417 /* copy font relevant information from graphics information */
418 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
419 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
420 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
421 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
422 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
424 font_bitmap_info[font_bitmap_id].draw_xoffset =
425 graphic_info[graphic].draw_xoffset;
426 font_bitmap_info[font_bitmap_id].draw_yoffset =
427 graphic_info[graphic].draw_yoffset;
429 font_bitmap_info[font_bitmap_id].num_chars =
430 graphic_info[graphic].anim_frames;
431 font_bitmap_info[font_bitmap_id].num_chars_per_line =
432 graphic_info[graphic].anim_frames_per_line;
436 InitFontInfo(font_bitmap_info, num_font_bitmaps,
437 getFontBitmapID, getFontFromToken);
440 void InitElementGraphicInfo()
442 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
443 int num_property_mappings = getImageListPropertyMappingSize();
446 if (graphic_info == NULL) /* still at startup phase */
449 /* set values to -1 to identify later as "uninitialized" values */
450 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
452 for (act = 0; act < NUM_ACTIONS; act++)
454 element_info[i].graphic[act] = -1;
455 element_info[i].crumbled[act] = -1;
457 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
459 element_info[i].direction_graphic[act][dir] = -1;
460 element_info[i].direction_crumbled[act][dir] = -1;
465 /* initialize normal element/graphic mapping from static configuration */
466 for (i = 0; element_to_graphic[i].element > -1; i++)
468 int element = element_to_graphic[i].element;
469 int action = element_to_graphic[i].action;
470 int direction = element_to_graphic[i].direction;
471 boolean crumbled = element_to_graphic[i].crumbled;
472 int graphic = element_to_graphic[i].graphic;
473 int base_graphic = el2baseimg(element);
475 if (graphic_info[graphic].bitmap == NULL)
478 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
481 boolean base_redefined =
482 getImageListEntryFromImageID(base_graphic)->redefined;
483 boolean act_dir_redefined =
484 getImageListEntryFromImageID(graphic)->redefined;
486 /* if the base graphic ("emerald", for example) has been redefined,
487 but not the action graphic ("emerald.falling", for example), do not
488 use an existing (in this case considered obsolete) action graphic
489 anymore, but use the automatically determined default graphic */
490 if (base_redefined && !act_dir_redefined)
495 action = ACTION_DEFAULT;
500 element_info[element].direction_crumbled[action][direction] = graphic;
502 element_info[element].crumbled[action] = graphic;
507 element_info[element].direction_graphic[action][direction] = graphic;
509 element_info[element].graphic[action] = graphic;
513 /* initialize normal element/graphic mapping from dynamic configuration */
514 for (i = 0; i < num_property_mappings; i++)
516 int element = property_mapping[i].base_index;
517 int action = property_mapping[i].ext1_index;
518 int direction = property_mapping[i].ext2_index;
519 int special = property_mapping[i].ext3_index;
520 int graphic = property_mapping[i].artwork_index;
521 boolean crumbled = FALSE;
524 if ((element == EL_EM_DYNAMITE ||
525 element == EL_EM_DYNAMITE_ACTIVE) &&
526 action == ACTION_ACTIVE &&
527 (special == GFX_SPECIAL_ARG_EDITOR ||
528 special == GFX_SPECIAL_ARG_PANEL))
529 printf("::: DYNAMIC: %d, %d, %d -> %d\n",
530 element, action, special, graphic);
533 if (special == GFX_SPECIAL_ARG_CRUMBLED)
539 if (graphic_info[graphic].bitmap == NULL)
542 if (element >= MAX_NUM_ELEMENTS || special != -1)
546 action = ACTION_DEFAULT;
551 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
552 element_info[element].direction_crumbled[action][dir] = -1;
555 element_info[element].direction_crumbled[action][direction] = graphic;
557 element_info[element].crumbled[action] = graphic;
562 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
563 element_info[element].direction_graphic[action][dir] = -1;
566 element_info[element].direction_graphic[action][direction] = graphic;
568 element_info[element].graphic[action] = graphic;
572 /* now copy all graphics that are defined to be cloned from other graphics */
573 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
575 int graphic = element_info[i].graphic[ACTION_DEFAULT];
576 int crumbled_like, diggable_like;
581 crumbled_like = graphic_info[graphic].crumbled_like;
582 diggable_like = graphic_info[graphic].diggable_like;
584 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
586 for (act = 0; act < NUM_ACTIONS; act++)
587 element_info[i].crumbled[act] =
588 element_info[crumbled_like].crumbled[act];
589 for (act = 0; act < NUM_ACTIONS; act++)
590 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
591 element_info[i].direction_crumbled[act][dir] =
592 element_info[crumbled_like].direction_crumbled[act][dir];
595 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
597 element_info[i].graphic[ACTION_DIGGING] =
598 element_info[diggable_like].graphic[ACTION_DIGGING];
599 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
600 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
601 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
606 /* set hardcoded definitions for some runtime elements without graphic */
607 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
611 /* set hardcoded definitions for some internal elements without graphic */
612 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
614 if (IS_EDITOR_CASCADE_INACTIVE(i))
615 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
616 else if (IS_EDITOR_CASCADE_ACTIVE(i))
617 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
621 /* now set all undefined/invalid graphics to -1 to set to default after it */
622 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
624 for (act = 0; act < NUM_ACTIONS; act++)
628 graphic = element_info[i].graphic[act];
629 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
630 element_info[i].graphic[act] = -1;
632 graphic = element_info[i].crumbled[act];
633 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
634 element_info[i].crumbled[act] = -1;
636 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
638 graphic = element_info[i].direction_graphic[act][dir];
639 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
640 element_info[i].direction_graphic[act][dir] = -1;
642 graphic = element_info[i].direction_crumbled[act][dir];
643 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
644 element_info[i].direction_crumbled[act][dir] = -1;
649 /* adjust graphics with 2nd tile for movement according to direction
650 (do this before correcting '-1' values to minimize calculations) */
651 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
653 for (act = 0; act < NUM_ACTIONS; act++)
655 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
657 int graphic = element_info[i].direction_graphic[act][dir];
658 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
660 if (act == ACTION_FALLING) /* special case */
661 graphic = element_info[i].graphic[act];
664 graphic_info[graphic].double_movement &&
665 graphic_info[graphic].swap_double_tiles != 0)
667 struct GraphicInfo *g = &graphic_info[graphic];
668 int src_x_front = g->src_x;
669 int src_y_front = g->src_y;
670 int src_x_back = g->src_x + g->offset2_x;
671 int src_y_back = g->src_y + g->offset2_y;
672 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
674 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
675 src_y_front < src_y_back);
676 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
677 boolean swap_movement_tiles_autodetected =
678 (!frames_are_ordered_diagonally &&
679 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
680 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
681 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
682 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
685 /* swap frontside and backside graphic tile coordinates, if needed */
686 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
688 /* get current (wrong) backside tile coordinates */
689 getGraphicSourceExt(graphic, 0, &dummy, &src_x_back, &src_y_back,
692 /* set frontside tile coordinates to backside tile coordinates */
693 g->src_x = src_x_back;
694 g->src_y = src_y_back;
696 /* invert tile offset to point to new backside tile coordinates */
700 /* do not swap front and backside tiles again after correction */
701 g->swap_double_tiles = 0;
708 /* now set all '-1' values to element specific default values */
709 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
711 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
712 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
713 int default_direction_graphic[NUM_DIRECTIONS_FULL];
714 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
716 if (default_graphic == -1)
717 default_graphic = IMG_UNKNOWN;
719 if (default_crumbled == -1)
720 default_crumbled = default_graphic;
722 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
723 if (default_crumbled == -1)
724 default_crumbled = IMG_EMPTY;
727 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
729 default_direction_graphic[dir] =
730 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
731 default_direction_crumbled[dir] =
732 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
734 if (default_direction_graphic[dir] == -1)
735 default_direction_graphic[dir] = default_graphic;
737 if (default_direction_crumbled[dir] == -1)
738 default_direction_crumbled[dir] = default_direction_graphic[dir];
740 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
741 if (default_direction_crumbled[dir] == -1)
742 default_direction_crumbled[dir] = default_crumbled;
746 for (act = 0; act < NUM_ACTIONS; act++)
748 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
749 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
750 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
751 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
752 act == ACTION_TURNING_FROM_RIGHT ||
753 act == ACTION_TURNING_FROM_UP ||
754 act == ACTION_TURNING_FROM_DOWN);
756 /* generic default action graphic (defined by "[default]" directive) */
757 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
758 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
759 int default_remove_graphic = IMG_EMPTY;
761 if (act_remove && default_action_graphic != -1)
762 default_remove_graphic = default_action_graphic;
764 /* look for special default action graphic (classic game specific) */
765 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
766 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
767 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
768 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
769 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
770 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
772 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
773 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
774 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
775 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
776 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
777 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
780 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
781 /* !!! make this better !!! */
782 if (i == EL_EMPTY_SPACE)
784 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
785 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
789 if (default_action_graphic == -1)
790 default_action_graphic = default_graphic;
792 if (default_action_crumbled == -1)
793 default_action_crumbled = default_action_graphic;
795 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
796 if (default_action_crumbled == -1)
797 default_action_crumbled = default_crumbled;
800 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
802 /* use action graphic as the default direction graphic, if undefined */
803 int default_action_direction_graphic = element_info[i].graphic[act];
804 int default_action_direction_crumbled = element_info[i].crumbled[act];
806 /* no graphic for current action -- use default direction graphic */
807 if (default_action_direction_graphic == -1)
808 default_action_direction_graphic =
809 (act_remove ? default_remove_graphic :
811 element_info[i].direction_graphic[ACTION_TURNING][dir] :
812 default_action_graphic != default_graphic ?
813 default_action_graphic :
814 default_direction_graphic[dir]);
816 if (element_info[i].direction_graphic[act][dir] == -1)
817 element_info[i].direction_graphic[act][dir] =
818 default_action_direction_graphic;
821 if (default_action_direction_crumbled == -1)
822 default_action_direction_crumbled =
823 element_info[i].direction_graphic[act][dir];
825 if (default_action_direction_crumbled == -1)
826 default_action_direction_crumbled =
827 (act_remove ? default_remove_graphic :
829 element_info[i].direction_crumbled[ACTION_TURNING][dir] :
830 default_action_crumbled != default_crumbled ?
831 default_action_crumbled :
832 default_direction_crumbled[dir]);
835 if (element_info[i].direction_crumbled[act][dir] == -1)
836 element_info[i].direction_crumbled[act][dir] =
837 default_action_direction_crumbled;
840 /* no graphic for this specific action -- use default action graphic */
841 if (element_info[i].graphic[act] == -1)
842 element_info[i].graphic[act] =
843 (act_remove ? default_remove_graphic :
844 act_turning ? element_info[i].graphic[ACTION_TURNING] :
845 default_action_graphic);
847 if (element_info[i].crumbled[act] == -1)
848 element_info[i].crumbled[act] = element_info[i].graphic[act];
850 if (element_info[i].crumbled[act] == -1)
851 element_info[i].crumbled[act] =
852 (act_remove ? default_remove_graphic :
853 act_turning ? element_info[i].crumbled[ACTION_TURNING] :
854 default_action_crumbled);
860 /* !!! THIS ALSO CLEARS SPECIAL FLAGS (AND IS NOT NEEDED ANYWAY) !!! */
861 /* set animation mode to "none" for each graphic with only 1 frame */
862 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
864 for (act = 0; act < NUM_ACTIONS; act++)
866 int graphic = element_info[i].graphic[act];
867 int crumbled = element_info[i].crumbled[act];
869 if (graphic_info[graphic].anim_frames == 1)
870 graphic_info[graphic].anim_mode = ANIM_NONE;
871 if (graphic_info[crumbled].anim_frames == 1)
872 graphic_info[crumbled].anim_mode = ANIM_NONE;
874 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
876 graphic = element_info[i].direction_graphic[act][dir];
877 crumbled = element_info[i].direction_crumbled[act][dir];
879 if (graphic_info[graphic].anim_frames == 1)
880 graphic_info[graphic].anim_mode = ANIM_NONE;
881 if (graphic_info[crumbled].anim_frames == 1)
882 graphic_info[crumbled].anim_mode = ANIM_NONE;
892 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
893 if (element_info[i].graphic[ACTION_DEFAULT] == IMG_UNKNOWN &&
895 Error(ERR_INFO, "warning: no graphic for element '%s' (%d)",
896 element_info[i].token_name, i);
902 void InitElementSpecialGraphicInfo()
904 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
905 int num_property_mappings = getImageListPropertyMappingSize();
908 /* always start with reliable default values */
909 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
910 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
911 element_info[i].special_graphic[j] =
912 element_info[i].graphic[ACTION_DEFAULT];
914 /* initialize special element/graphic mapping from static configuration */
915 for (i = 0; element_to_special_graphic[i].element > -1; i++)
917 int element = element_to_special_graphic[i].element;
918 int special = element_to_special_graphic[i].special;
919 int graphic = element_to_special_graphic[i].graphic;
920 int base_graphic = el2baseimg(element);
921 boolean base_redefined =
922 getImageListEntryFromImageID(base_graphic)->redefined;
923 boolean special_redefined =
924 getImageListEntryFromImageID(graphic)->redefined;
927 if ((element == EL_EM_DYNAMITE ||
928 element == EL_EM_DYNAMITE_ACTIVE) &&
929 (special == GFX_SPECIAL_ARG_EDITOR ||
930 special == GFX_SPECIAL_ARG_PANEL))
931 printf("::: SPECIAL STATIC: %d, %d -> %d\n",
932 element, special, graphic);
935 /* if the base graphic ("emerald", for example) has been redefined,
936 but not the special graphic ("emerald.EDITOR", for example), do not
937 use an existing (in this case considered obsolete) special graphic
938 anymore, but use the automatically created (down-scaled) graphic */
939 if (base_redefined && !special_redefined)
942 element_info[element].special_graphic[special] = graphic;
945 /* initialize special element/graphic mapping from dynamic configuration */
946 for (i = 0; i < num_property_mappings; i++)
948 int element = property_mapping[i].base_index;
949 int action = property_mapping[i].ext1_index;
950 int direction = property_mapping[i].ext2_index;
951 int special = property_mapping[i].ext3_index;
952 int graphic = property_mapping[i].artwork_index;
955 if ((element == EL_EM_DYNAMITE ||
956 element == EL_EM_DYNAMITE_ACTIVE ||
957 element == EL_CONVEYOR_BELT_1_MIDDLE ||
958 element == EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE) &&
959 (special == GFX_SPECIAL_ARG_EDITOR ||
960 special == GFX_SPECIAL_ARG_PANEL))
961 printf("::: SPECIAL DYNAMIC: %d, %d -> %d [%d]\n",
962 element, special, graphic, property_mapping[i].ext1_index);
966 if (element == EL_CONVEYOR_BELT_1_MIDDLE &&
967 action == ACTION_ACTIVE)
969 element = EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE;
975 if (element == EL_MAGIC_WALL &&
976 action == ACTION_ACTIVE)
978 element = EL_MAGIC_WALL_ACTIVE;
984 /* for action ".active", replace element with active element, if exists */
985 if (action == ACTION_ACTIVE && element != ELEMENT_ACTIVE(element))
987 element = ELEMENT_ACTIVE(element);
992 if (element >= MAX_NUM_ELEMENTS)
995 /* do not change special graphic if action or direction was specified */
996 if (action != -1 || direction != -1)
999 if (IS_SPECIAL_GFX_ARG(special))
1000 element_info[element].special_graphic[special] = graphic;
1003 /* now set all undefined/invalid graphics to default */
1004 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1005 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1006 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
1007 element_info[i].special_graphic[j] =
1008 element_info[i].graphic[ACTION_DEFAULT];
1011 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
1016 if (type != TYPE_TOKEN)
1017 return get_parameter_value(value_raw, suffix, type);
1019 if (strEqual(value_raw, ARG_UNDEFINED))
1020 return ARG_UNDEFINED_VALUE;
1022 /* !!! OPTIMIZE THIS BY USING HASH !!! */
1023 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1024 if (strEqual(element_info[i].token_name, value_raw))
1027 /* !!! OPTIMIZE THIS BY USING HASH !!! */
1028 for (i = 0; image_config[i].token != NULL; i++)
1030 int len_config_value = strlen(image_config[i].value);
1032 if (!strEqual(&image_config[i].value[len_config_value - 4], ".pcx") &&
1033 !strEqual(&image_config[i].value[len_config_value - 4], ".wav") &&
1034 !strEqual(image_config[i].value, UNDEFINED_FILENAME))
1037 if (strEqual(image_config[i].token, value_raw))
1046 static int get_scaled_graphic_width(int graphic)
1048 int original_width = getOriginalImageWidthFromImageID(graphic);
1049 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1051 return original_width * scale_up_factor;
1054 static int get_scaled_graphic_height(int graphic)
1056 int original_height = getOriginalImageHeightFromImageID(graphic);
1057 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1059 return original_height * scale_up_factor;
1062 static void set_graphic_parameters(int graphic)
1064 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1065 char **parameter_raw = image->parameter;
1066 Bitmap *src_bitmap = getBitmapFromImageID(graphic);
1067 int parameter[NUM_GFX_ARGS];
1068 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1069 int anim_frames_per_line = 1;
1072 /* if fallback to default artwork is done, also use the default parameters */
1073 if (image->fallback_to_default)
1074 parameter_raw = image->default_parameter;
1076 /* get integer values from string parameters */
1077 for (i = 0; i < NUM_GFX_ARGS; i++)
1078 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1079 image_config_suffix[i].token,
1080 image_config_suffix[i].type);
1082 graphic_info[graphic].bitmap = src_bitmap;
1084 /* always start with reliable default values */
1085 graphic_info[graphic].src_image_width = 0;
1086 graphic_info[graphic].src_image_height = 0;
1087 graphic_info[graphic].src_x = 0;
1088 graphic_info[graphic].src_y = 0;
1089 graphic_info[graphic].width = TILEX; /* default for element graphics */
1090 graphic_info[graphic].height = TILEY; /* default for element graphics */
1091 graphic_info[graphic].offset_x = 0; /* one or both of these values ... */
1092 graphic_info[graphic].offset_y = 0; /* ... will be corrected later */
1093 graphic_info[graphic].offset2_x = 0; /* one or both of these values ... */
1094 graphic_info[graphic].offset2_y = 0; /* ... will be corrected later */
1095 graphic_info[graphic].swap_double_tiles = -1; /* auto-detect tile swapping */
1096 graphic_info[graphic].crumbled_like = -1; /* do not use clone element */
1097 graphic_info[graphic].diggable_like = -1; /* do not use clone element */
1098 graphic_info[graphic].border_size = TILEX / 8; /* "CRUMBLED" border size */
1099 graphic_info[graphic].scale_up_factor = 1; /* default: no scaling up */
1100 graphic_info[graphic].clone_from = -1; /* do not use clone graphic */
1101 graphic_info[graphic].anim_delay_fixed = 0;
1102 graphic_info[graphic].anim_delay_random = 0;
1103 graphic_info[graphic].post_delay_fixed = 0;
1104 graphic_info[graphic].post_delay_random = 0;
1105 graphic_info[graphic].fade_mode = FADE_MODE_DEFAULT;
1106 graphic_info[graphic].fade_delay = -1;
1107 graphic_info[graphic].post_delay = -1;
1108 graphic_info[graphic].auto_delay = -1;
1109 graphic_info[graphic].align = ALIGN_CENTER; /* default for title screens */
1110 graphic_info[graphic].valign = VALIGN_MIDDLE; /* default for title screens */
1111 graphic_info[graphic].sort_priority = 0; /* default for title screens */
1114 /* optional zoom factor for scaling up the image to a larger size */
1115 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1116 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1117 if (graphic_info[graphic].scale_up_factor < 1)
1118 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
1122 if (graphic_info[graphic].use_image_size)
1124 /* set new default bitmap size (with scaling, but without small images) */
1125 graphic_info[graphic].width = get_scaled_graphic_width(graphic);
1126 graphic_info[graphic].height = get_scaled_graphic_height(graphic);
1130 /* optional x and y tile position of animation frame sequence */
1131 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1132 graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
1133 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1134 graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
1136 /* optional x and y pixel position of animation frame sequence */
1137 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1138 graphic_info[graphic].src_x = parameter[GFX_ARG_X];
1139 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1140 graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
1142 /* optional width and height of each animation frame */
1143 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1144 graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
1145 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1146 graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
1149 /* optional zoom factor for scaling up the image to a larger size */
1150 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1151 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1152 if (graphic_info[graphic].scale_up_factor < 1)
1153 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
1158 /* get final bitmap size (with scaling, but without small images) */
1159 int src_image_width = get_scaled_graphic_width(graphic);
1160 int src_image_height = get_scaled_graphic_height(graphic);
1162 anim_frames_per_row = src_image_width / graphic_info[graphic].width;
1163 anim_frames_per_col = src_image_height / graphic_info[graphic].height;
1165 graphic_info[graphic].src_image_width = src_image_width;
1166 graphic_info[graphic].src_image_height = src_image_height;
1169 /* correct x or y offset dependent of vertical or horizontal frame order */
1170 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1172 graphic_info[graphic].offset_y =
1173 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1174 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
1175 anim_frames_per_line = anim_frames_per_col;
1177 else /* frames are ordered horizontally */
1179 graphic_info[graphic].offset_x =
1180 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1181 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
1182 anim_frames_per_line = anim_frames_per_row;
1185 /* optionally, the x and y offset of frames can be specified directly */
1186 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1187 graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
1188 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1189 graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
1191 /* optionally, moving animations may have separate start and end graphics */
1192 graphic_info[graphic].double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1194 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1195 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1197 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1198 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1199 graphic_info[graphic].offset2_y =
1200 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1201 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].height);
1202 else /* frames are ordered horizontally */
1203 graphic_info[graphic].offset2_x =
1204 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1205 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].width);
1207 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1208 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1209 graphic_info[graphic].offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1210 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1211 graphic_info[graphic].offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1213 /* optionally, the second movement tile can be specified as start tile */
1214 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1215 graphic_info[graphic].swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1217 /* automatically determine correct number of frames, if not defined */
1218 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1219 graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
1220 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1221 graphic_info[graphic].anim_frames = anim_frames_per_row;
1222 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1223 graphic_info[graphic].anim_frames = anim_frames_per_col;
1225 graphic_info[graphic].anim_frames = 1;
1227 if (graphic_info[graphic].anim_frames == 0) /* frames must be at least 1 */
1228 graphic_info[graphic].anim_frames = 1;
1230 graphic_info[graphic].anim_frames_per_line =
1231 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1232 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1234 graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
1235 if (graphic_info[graphic].anim_delay == 0) /* delay must be at least 1 */
1236 graphic_info[graphic].anim_delay = 1;
1238 graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
1240 if (graphic_info[graphic].anim_frames == 1)
1241 graphic_info[graphic].anim_mode = ANIM_NONE;
1244 /* automatically determine correct start frame, if not defined */
1245 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1246 graphic_info[graphic].anim_start_frame = 0;
1247 else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
1248 graphic_info[graphic].anim_start_frame =
1249 graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1251 graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
1253 /* animation synchronized with global frame counter, not move position */
1254 graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1256 /* optional element for cloning crumble graphics */
1257 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1258 graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1260 /* optional element for cloning digging graphics */
1261 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1262 graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1264 /* optional border size for "crumbling" diggable graphics */
1265 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1266 graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
1268 /* this is only used for player "boring" and "sleeping" actions */
1269 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1270 graphic_info[graphic].anim_delay_fixed =
1271 parameter[GFX_ARG_ANIM_DELAY_FIXED];
1272 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1273 graphic_info[graphic].anim_delay_random =
1274 parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1275 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1276 graphic_info[graphic].post_delay_fixed =
1277 parameter[GFX_ARG_POST_DELAY_FIXED];
1278 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1279 graphic_info[graphic].post_delay_random =
1280 parameter[GFX_ARG_POST_DELAY_RANDOM];
1282 /* this is only used for toon animations */
1283 graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
1284 graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY];
1286 /* this is only used for drawing font characters */
1287 graphic_info[graphic].draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1288 graphic_info[graphic].draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1290 /* this is only used for drawing envelope graphics */
1291 graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1293 /* optional graphic for cloning all graphics settings */
1294 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1295 graphic_info[graphic].clone_from = parameter[GFX_ARG_CLONE_FROM];
1297 /* optional settings for drawing title screens and title messages */
1298 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1299 graphic_info[graphic].fade_mode = parameter[GFX_ARG_FADE_MODE];
1300 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1301 graphic_info[graphic].fade_delay = parameter[GFX_ARG_FADE_DELAY];
1302 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1303 graphic_info[graphic].post_delay = parameter[GFX_ARG_POST_DELAY];
1304 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1305 graphic_info[graphic].auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1306 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1307 graphic_info[graphic].align = parameter[GFX_ARG_ALIGN];
1308 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1309 graphic_info[graphic].valign = parameter[GFX_ARG_VALIGN];
1310 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1311 graphic_info[graphic].sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1314 static void set_cloned_graphic_parameters(int graphic)
1316 int fallback_graphic = IMG_CHAR_EXCLAM;
1317 int max_num_images = getImageListSize();
1318 int clone_graphic = graphic_info[graphic].clone_from;
1319 int num_references_followed = 1;
1321 while (graphic_info[clone_graphic].clone_from != -1 &&
1322 num_references_followed < max_num_images)
1324 clone_graphic = graphic_info[clone_graphic].clone_from;
1326 num_references_followed++;
1329 if (num_references_followed >= max_num_images)
1331 Error(ERR_INFO_LINE, "-");
1332 Error(ERR_INFO, "warning: error found in config file:");
1333 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1334 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1335 Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1336 Error(ERR_INFO, "custom graphic rejected for this element/action");
1338 if (graphic == fallback_graphic)
1339 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1341 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1342 Error(ERR_INFO_LINE, "-");
1344 graphic_info[graphic] = graphic_info[fallback_graphic];
1348 graphic_info[graphic] = graphic_info[clone_graphic];
1349 graphic_info[graphic].clone_from = clone_graphic;
1353 static void InitGraphicInfo()
1355 int fallback_graphic = IMG_CHAR_EXCLAM;
1356 int num_images = getImageListSize();
1359 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1360 static boolean clipmasks_initialized = FALSE;
1362 XGCValues clip_gc_values;
1363 unsigned long clip_gc_valuemask;
1364 GC copy_clipmask_gc = None;
1367 /* use image size as default values for width and height for these images */
1368 static int full_size_graphics[] =
1373 IMG_BACKGROUND_ENVELOPE_1,
1374 IMG_BACKGROUND_ENVELOPE_2,
1375 IMG_BACKGROUND_ENVELOPE_3,
1376 IMG_BACKGROUND_ENVELOPE_4,
1379 IMG_BACKGROUND_TITLE_INITIAL,
1380 IMG_BACKGROUND_TITLE,
1381 IMG_BACKGROUND_MAIN,
1382 IMG_BACKGROUND_LEVELS,
1383 IMG_BACKGROUND_SCORES,
1384 IMG_BACKGROUND_EDITOR,
1385 IMG_BACKGROUND_INFO,
1386 IMG_BACKGROUND_INFO_ELEMENTS,
1387 IMG_BACKGROUND_INFO_MUSIC,
1388 IMG_BACKGROUND_INFO_CREDITS,
1389 IMG_BACKGROUND_INFO_PROGRAM,
1390 IMG_BACKGROUND_INFO_LEVELSET,
1391 IMG_BACKGROUND_SETUP,
1392 IMG_BACKGROUND_DOOR,
1394 IMG_TITLESCREEN_INITIAL_1,
1395 IMG_TITLESCREEN_INITIAL_2,
1396 IMG_TITLESCREEN_INITIAL_3,
1397 IMG_TITLESCREEN_INITIAL_4,
1398 IMG_TITLESCREEN_INITIAL_5,
1408 checked_free(graphic_info);
1410 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1413 /* initialize "use_image_size" flag with default value */
1414 for (i = 0; i < num_images; i++)
1415 graphic_info[i].use_image_size = FALSE;
1417 /* initialize "use_image_size" flag from static configuration above */
1418 for (i = 0; full_size_graphics[i] != -1; i++)
1419 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1422 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1423 if (clipmasks_initialized)
1425 for (i = 0; i < num_images; i++)
1427 if (graphic_info[i].clip_mask)
1428 XFreePixmap(display, graphic_info[i].clip_mask);
1429 if (graphic_info[i].clip_gc)
1430 XFreeGC(display, graphic_info[i].clip_gc);
1432 graphic_info[i].clip_mask = None;
1433 graphic_info[i].clip_gc = None;
1438 /* first set all graphic paramaters ... */
1439 for (i = 0; i < num_images; i++)
1440 set_graphic_parameters(i);
1442 /* ... then copy these parameters for cloned graphics */
1443 for (i = 0; i < num_images; i++)
1444 if (graphic_info[i].clone_from != -1)
1445 set_cloned_graphic_parameters(i);
1447 for (i = 0; i < num_images; i++)
1452 int first_frame, last_frame;
1453 int src_bitmap_width, src_bitmap_height;
1455 /* now check if no animation frames are outside of the loaded image */
1457 if (graphic_info[i].bitmap == NULL)
1458 continue; /* skip check for optional images that are undefined */
1460 /* get image size (this can differ from the standard element tile size!) */
1461 width = graphic_info[i].width;
1462 height = graphic_info[i].height;
1464 /* get final bitmap size (with scaling, but without small images) */
1465 src_bitmap_width = graphic_info[i].src_image_width;
1466 src_bitmap_height = graphic_info[i].src_image_height;
1468 /* check if first animation frame is inside specified bitmap */
1471 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1474 /* this avoids calculating wrong start position for out-of-bounds frame */
1475 src_x = graphic_info[i].src_x;
1476 src_y = graphic_info[i].src_y;
1479 if (src_x < 0 || src_y < 0 ||
1480 src_x + width > src_bitmap_width ||
1481 src_y + height > src_bitmap_height)
1483 Error(ERR_INFO_LINE, "-");
1484 Error(ERR_INFO, "warning: error found in config file:");
1485 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1486 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1487 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1489 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1490 src_x, src_y, src_bitmap_width, src_bitmap_height);
1491 Error(ERR_INFO, "custom graphic rejected for this element/action");
1493 if (i == fallback_graphic)
1494 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1496 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1497 Error(ERR_INFO_LINE, "-");
1499 graphic_info[i] = graphic_info[fallback_graphic];
1502 /* check if last animation frame is inside specified bitmap */
1504 last_frame = graphic_info[i].anim_frames - 1;
1505 getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1507 if (src_x < 0 || src_y < 0 ||
1508 src_x + width > src_bitmap_width ||
1509 src_y + height > src_bitmap_height)
1511 Error(ERR_INFO_LINE, "-");
1512 Error(ERR_INFO, "warning: error found in config file:");
1513 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1514 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1515 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1517 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1518 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1519 Error(ERR_INFO, "custom graphic rejected for this element/action");
1521 if (i == fallback_graphic)
1522 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1524 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1525 Error(ERR_INFO_LINE, "-");
1527 graphic_info[i] = graphic_info[fallback_graphic];
1530 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1531 /* currently we only need a tile clip mask from the first frame */
1532 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1534 if (copy_clipmask_gc == None)
1536 clip_gc_values.graphics_exposures = False;
1537 clip_gc_valuemask = GCGraphicsExposures;
1538 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
1539 clip_gc_valuemask, &clip_gc_values);
1542 graphic_info[i].clip_mask =
1543 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
1545 src_pixmap = src_bitmap->clip_mask;
1546 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
1547 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
1549 clip_gc_values.graphics_exposures = False;
1550 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
1551 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
1553 graphic_info[i].clip_gc =
1554 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
1558 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1559 if (copy_clipmask_gc)
1560 XFreeGC(display, copy_clipmask_gc);
1562 clipmasks_initialized = TRUE;
1566 static void InitElementSoundInfo()
1568 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1569 int num_property_mappings = getSoundListPropertyMappingSize();
1572 /* set values to -1 to identify later as "uninitialized" values */
1573 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1574 for (act = 0; act < NUM_ACTIONS; act++)
1575 element_info[i].sound[act] = -1;
1577 /* initialize element/sound mapping from static configuration */
1578 for (i = 0; element_to_sound[i].element > -1; i++)
1580 int element = element_to_sound[i].element;
1581 int action = element_to_sound[i].action;
1582 int sound = element_to_sound[i].sound;
1583 boolean is_class = element_to_sound[i].is_class;
1586 action = ACTION_DEFAULT;
1589 element_info[element].sound[action] = sound;
1591 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1592 if (strEqual(element_info[j].class_name,
1593 element_info[element].class_name))
1594 element_info[j].sound[action] = sound;
1597 /* initialize element class/sound mapping from dynamic configuration */
1598 for (i = 0; i < num_property_mappings; i++)
1600 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1601 int action = property_mapping[i].ext1_index;
1602 int sound = property_mapping[i].artwork_index;
1604 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1608 action = ACTION_DEFAULT;
1610 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1611 if (strEqual(element_info[j].class_name,
1612 element_info[element_class].class_name))
1613 element_info[j].sound[action] = sound;
1616 /* initialize element/sound mapping from dynamic configuration */
1617 for (i = 0; i < num_property_mappings; i++)
1619 int element = property_mapping[i].base_index;
1620 int action = property_mapping[i].ext1_index;
1621 int sound = property_mapping[i].artwork_index;
1623 if (element >= MAX_NUM_ELEMENTS)
1627 action = ACTION_DEFAULT;
1629 element_info[element].sound[action] = sound;
1632 /* now set all '-1' values to element specific default values */
1633 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1635 for (act = 0; act < NUM_ACTIONS; act++)
1637 /* generic default action sound (defined by "[default]" directive) */
1638 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1640 /* look for special default action sound (classic game specific) */
1641 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1642 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1643 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1644 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1645 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1646 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1648 /* !!! there's no such thing as a "default action sound" !!! */
1650 /* look for element specific default sound (independent from action) */
1651 if (element_info[i].sound[ACTION_DEFAULT] != -1)
1652 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
1656 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1657 /* !!! make this better !!! */
1658 if (i == EL_EMPTY_SPACE)
1659 default_action_sound = element_info[EL_DEFAULT].sound[act];
1662 /* no sound for this specific action -- use default action sound */
1663 if (element_info[i].sound[act] == -1)
1664 element_info[i].sound[act] = default_action_sound;
1668 /* copy sound settings to some elements that are only stored in level file
1669 in native R'n'D levels, but are used by game engine in native EM levels */
1670 for (i = 0; copy_properties[i][0] != -1; i++)
1671 for (j = 1; j <= 4; j++)
1672 for (act = 0; act < NUM_ACTIONS; act++)
1673 element_info[copy_properties[i][j]].sound[act] =
1674 element_info[copy_properties[i][0]].sound[act];
1677 static void InitGameModeSoundInfo()
1681 /* set values to -1 to identify later as "uninitialized" values */
1682 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1685 /* initialize gamemode/sound mapping from static configuration */
1686 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1688 int gamemode = gamemode_to_sound[i].gamemode;
1689 int sound = gamemode_to_sound[i].sound;
1692 gamemode = GAME_MODE_DEFAULT;
1694 menu.sound[gamemode] = sound;
1697 /* now set all '-1' values to levelset specific default values */
1698 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1699 if (menu.sound[i] == -1)
1700 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1703 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1704 if (menu.sound[i] != -1)
1705 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
1709 static void set_sound_parameters(int sound, char **parameter_raw)
1711 int parameter[NUM_SND_ARGS];
1714 /* get integer values from string parameters */
1715 for (i = 0; i < NUM_SND_ARGS; i++)
1717 get_parameter_value(parameter_raw[i],
1718 sound_config_suffix[i].token,
1719 sound_config_suffix[i].type);
1721 /* explicit loop mode setting in configuration overrides default value */
1722 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1723 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1725 /* sound volume to change the original volume when loading the sound file */
1726 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1728 /* sound priority to give certain sounds a higher or lower priority */
1729 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
1732 static void InitSoundInfo()
1734 int *sound_effect_properties;
1735 int num_sounds = getSoundListSize();
1738 checked_free(sound_info);
1740 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1741 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1743 /* initialize sound effect for all elements to "no sound" */
1744 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1745 for (j = 0; j < NUM_ACTIONS; j++)
1746 element_info[i].sound[j] = SND_UNDEFINED;
1748 for (i = 0; i < num_sounds; i++)
1750 struct FileInfo *sound = getSoundListEntry(i);
1751 int len_effect_text = strlen(sound->token);
1753 sound_effect_properties[i] = ACTION_OTHER;
1754 sound_info[i].loop = FALSE; /* default: play sound only once */
1757 printf("::: sound %d: '%s'\n", i, sound->token);
1760 /* determine all loop sounds and identify certain sound classes */
1762 for (j = 0; element_action_info[j].suffix; j++)
1764 int len_action_text = strlen(element_action_info[j].suffix);
1766 if (len_action_text < len_effect_text &&
1767 strEqual(&sound->token[len_effect_text - len_action_text],
1768 element_action_info[j].suffix))
1770 sound_effect_properties[i] = element_action_info[j].value;
1771 sound_info[i].loop = element_action_info[j].is_loop_sound;
1777 /* associate elements and some selected sound actions */
1779 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1781 if (element_info[j].class_name)
1783 int len_class_text = strlen(element_info[j].class_name);
1785 if (len_class_text + 1 < len_effect_text &&
1786 strncmp(sound->token,
1787 element_info[j].class_name, len_class_text) == 0 &&
1788 sound->token[len_class_text] == '.')
1790 int sound_action_value = sound_effect_properties[i];
1792 element_info[j].sound[sound_action_value] = i;
1797 set_sound_parameters(i, sound->parameter);
1800 free(sound_effect_properties);
1803 static void InitGameModeMusicInfo()
1805 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1806 int num_property_mappings = getMusicListPropertyMappingSize();
1807 int default_levelset_music = -1;
1810 /* set values to -1 to identify later as "uninitialized" values */
1811 for (i = 0; i < MAX_LEVELS; i++)
1812 levelset.music[i] = -1;
1813 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1816 /* initialize gamemode/music mapping from static configuration */
1817 for (i = 0; gamemode_to_music[i].music > -1; i++)
1819 int gamemode = gamemode_to_music[i].gamemode;
1820 int music = gamemode_to_music[i].music;
1823 printf("::: gamemode == %d, music == %d\n", gamemode, music);
1827 gamemode = GAME_MODE_DEFAULT;
1829 menu.music[gamemode] = music;
1832 /* initialize gamemode/music mapping from dynamic configuration */
1833 for (i = 0; i < num_property_mappings; i++)
1835 int prefix = property_mapping[i].base_index;
1836 int gamemode = property_mapping[i].ext1_index;
1837 int level = property_mapping[i].ext2_index;
1838 int music = property_mapping[i].artwork_index;
1841 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
1842 prefix, gamemode, level, music);
1845 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1849 gamemode = GAME_MODE_DEFAULT;
1851 /* level specific music only allowed for in-game music */
1852 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1853 gamemode = GAME_MODE_PLAYING;
1858 default_levelset_music = music;
1861 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1862 levelset.music[level] = music;
1863 if (gamemode != GAME_MODE_PLAYING)
1864 menu.music[gamemode] = music;
1867 /* now set all '-1' values to menu specific default values */
1868 /* (undefined values of "levelset.music[]" might stay at "-1" to
1869 allow dynamic selection of music files from music directory!) */
1870 for (i = 0; i < MAX_LEVELS; i++)
1871 if (levelset.music[i] == -1)
1872 levelset.music[i] = default_levelset_music;
1873 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1874 if (menu.music[i] == -1)
1875 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1878 for (i = 0; i < MAX_LEVELS; i++)
1879 if (levelset.music[i] != -1)
1880 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
1881 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1882 if (menu.music[i] != -1)
1883 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
1887 static void set_music_parameters(int music, char **parameter_raw)
1889 int parameter[NUM_MUS_ARGS];
1892 /* get integer values from string parameters */
1893 for (i = 0; i < NUM_MUS_ARGS; i++)
1895 get_parameter_value(parameter_raw[i],
1896 music_config_suffix[i].token,
1897 music_config_suffix[i].type);
1899 /* explicit loop mode setting in configuration overrides default value */
1900 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1901 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1904 static void InitMusicInfo()
1906 int num_music = getMusicListSize();
1909 checked_free(music_info);
1911 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1913 for (i = 0; i < num_music; i++)
1915 struct FileInfo *music = getMusicListEntry(i);
1916 int len_music_text = strlen(music->token);
1918 music_info[i].loop = TRUE; /* default: play music in loop mode */
1920 /* determine all loop music */
1922 for (j = 0; music_prefix_info[j].prefix; j++)
1924 int len_prefix_text = strlen(music_prefix_info[j].prefix);
1926 if (len_prefix_text < len_music_text &&
1927 strncmp(music->token,
1928 music_prefix_info[j].prefix, len_prefix_text) == 0)
1930 music_info[i].loop = music_prefix_info[j].is_loop_music;
1936 set_music_parameters(i, music->parameter);
1940 static void ReinitializeGraphics()
1942 InitGraphicInfo(); /* graphic properties mapping */
1943 InitElementGraphicInfo(); /* element game graphic mapping */
1944 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
1946 InitElementSmallImages(); /* scale elements to all needed sizes */
1947 InitScaledImages(); /* scale all other images, if needed */
1948 InitFontGraphicInfo(); /* initialize text drawing functions */
1950 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
1952 SetMainBackgroundImage(IMG_BACKGROUND);
1953 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1959 static void ReinitializeSounds()
1961 InitSoundInfo(); /* sound properties mapping */
1962 InitElementSoundInfo(); /* element game sound mapping */
1963 InitGameModeSoundInfo(); /* game mode sound mapping */
1965 InitPlayLevelSound(); /* internal game sound settings */
1968 static void ReinitializeMusic()
1970 InitMusicInfo(); /* music properties mapping */
1971 InitGameModeMusicInfo(); /* game mode music mapping */
1974 static int get_special_property_bit(int element, int property_bit_nr)
1976 struct PropertyBitInfo
1982 static struct PropertyBitInfo pb_can_move_into_acid[] =
1984 /* the player may be able fall into acid when gravity is activated */
1989 { EL_SP_MURPHY, 0 },
1990 { EL_SOKOBAN_FIELD_PLAYER, 0 },
1992 /* all elements that can move may be able to also move into acid */
1995 { EL_BUG_RIGHT, 1 },
1998 { EL_SPACESHIP, 2 },
1999 { EL_SPACESHIP_LEFT, 2 },
2000 { EL_SPACESHIP_RIGHT, 2 },
2001 { EL_SPACESHIP_UP, 2 },
2002 { EL_SPACESHIP_DOWN, 2 },
2003 { EL_BD_BUTTERFLY, 3 },
2004 { EL_BD_BUTTERFLY_LEFT, 3 },
2005 { EL_BD_BUTTERFLY_RIGHT, 3 },
2006 { EL_BD_BUTTERFLY_UP, 3 },
2007 { EL_BD_BUTTERFLY_DOWN, 3 },
2008 { EL_BD_FIREFLY, 4 },
2009 { EL_BD_FIREFLY_LEFT, 4 },
2010 { EL_BD_FIREFLY_RIGHT, 4 },
2011 { EL_BD_FIREFLY_UP, 4 },
2012 { EL_BD_FIREFLY_DOWN, 4 },
2014 { EL_YAMYAM_LEFT, 5 },
2015 { EL_YAMYAM_RIGHT, 5 },
2016 { EL_YAMYAM_UP, 5 },
2017 { EL_YAMYAM_DOWN, 5 },
2018 { EL_DARK_YAMYAM, 6 },
2021 { EL_PACMAN_LEFT, 8 },
2022 { EL_PACMAN_RIGHT, 8 },
2023 { EL_PACMAN_UP, 8 },
2024 { EL_PACMAN_DOWN, 8 },
2026 { EL_MOLE_LEFT, 9 },
2027 { EL_MOLE_RIGHT, 9 },
2029 { EL_MOLE_DOWN, 9 },
2033 { EL_SATELLITE, 13 },
2034 { EL_SP_SNIKSNAK, 14 },
2035 { EL_SP_ELECTRON, 15 },
2038 { EL_EMC_ANDROID, 18 },
2043 static struct PropertyBitInfo pb_dont_collide_with[] =
2045 { EL_SP_SNIKSNAK, 0 },
2046 { EL_SP_ELECTRON, 1 },
2054 struct PropertyBitInfo *pb_info;
2057 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2058 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2063 struct PropertyBitInfo *pb_info = NULL;
2066 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2067 if (pb_definition[i].bit_nr == property_bit_nr)
2068 pb_info = pb_definition[i].pb_info;
2070 if (pb_info == NULL)
2073 for (i = 0; pb_info[i].element != -1; i++)
2074 if (pb_info[i].element == element)
2075 return pb_info[i].bit_nr;
2080 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2081 boolean property_value)
2083 int bit_nr = get_special_property_bit(element, property_bit_nr);
2088 *bitfield |= (1 << bit_nr);
2090 *bitfield &= ~(1 << bit_nr);
2094 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2096 int bit_nr = get_special_property_bit(element, property_bit_nr);
2099 return ((*bitfield & (1 << bit_nr)) != 0);
2104 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2106 static int group_nr;
2107 static struct ElementGroupInfo *group;
2108 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2111 if (actual_group == NULL) /* not yet initialized */
2114 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
2116 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2117 group_element - EL_GROUP_START + 1);
2119 /* replace element which caused too deep recursion by question mark */
2120 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2125 if (recursion_depth == 0) /* initialization */
2127 group = actual_group;
2128 group_nr = GROUP_NR(group_element);
2130 group->num_elements_resolved = 0;
2131 group->choice_pos = 0;
2133 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2134 element_info[i].in_group[group_nr] = FALSE;
2137 for (i = 0; i < actual_group->num_elements; i++)
2139 int element = actual_group->element[i];
2141 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2144 if (IS_GROUP_ELEMENT(element))
2145 ResolveGroupElementExt(element, recursion_depth + 1);
2148 group->element_resolved[group->num_elements_resolved++] = element;
2149 element_info[element].in_group[group_nr] = TRUE;
2154 void ResolveGroupElement(int group_element)
2156 ResolveGroupElementExt(group_element, 0);
2159 void InitElementPropertiesStatic()
2161 static int ep_diggable[] =
2166 EL_SP_BUGGY_BASE_ACTIVATING,
2169 EL_INVISIBLE_SAND_ACTIVE,
2172 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2173 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2178 EL_SP_BUGGY_BASE_ACTIVE,
2185 static int ep_collectible_only[] =
2207 EL_DYNABOMB_INCREASE_NUMBER,
2208 EL_DYNABOMB_INCREASE_SIZE,
2209 EL_DYNABOMB_INCREASE_POWER,
2227 /* !!! handle separately !!! */
2228 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2234 static int ep_dont_run_into[] =
2236 /* same elements as in 'ep_dont_touch' */
2242 /* same elements as in 'ep_dont_collide_with' */
2254 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2259 EL_SP_BUGGY_BASE_ACTIVE,
2266 static int ep_dont_collide_with[] =
2268 /* same elements as in 'ep_dont_touch' */
2285 static int ep_dont_touch[] =
2295 static int ep_indestructible[] =
2299 EL_ACID_POOL_TOPLEFT,
2300 EL_ACID_POOL_TOPRIGHT,
2301 EL_ACID_POOL_BOTTOMLEFT,
2302 EL_ACID_POOL_BOTTOM,
2303 EL_ACID_POOL_BOTTOMRIGHT,
2304 EL_SP_HARDWARE_GRAY,
2305 EL_SP_HARDWARE_GREEN,
2306 EL_SP_HARDWARE_BLUE,
2308 EL_SP_HARDWARE_YELLOW,
2309 EL_SP_HARDWARE_BASE_1,
2310 EL_SP_HARDWARE_BASE_2,
2311 EL_SP_HARDWARE_BASE_3,
2312 EL_SP_HARDWARE_BASE_4,
2313 EL_SP_HARDWARE_BASE_5,
2314 EL_SP_HARDWARE_BASE_6,
2315 EL_INVISIBLE_STEELWALL,
2316 EL_INVISIBLE_STEELWALL_ACTIVE,
2317 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2318 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2319 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2320 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2321 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2322 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2323 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2324 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2325 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2326 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2327 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2328 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2330 EL_LIGHT_SWITCH_ACTIVE,
2331 EL_SIGN_EXCLAMATION,
2332 EL_SIGN_RADIOACTIVITY,
2339 EL_SIGN_ENTRY_FORBIDDEN,
2340 EL_SIGN_EMERGENCY_EXIT,
2348 EL_STEEL_EXIT_CLOSED,
2350 EL_EM_STEEL_EXIT_CLOSED,
2351 EL_EM_STEEL_EXIT_OPEN,
2352 EL_DC_STEELWALL_1_LEFT,
2353 EL_DC_STEELWALL_1_RIGHT,
2354 EL_DC_STEELWALL_1_TOP,
2355 EL_DC_STEELWALL_1_BOTTOM,
2356 EL_DC_STEELWALL_1_HORIZONTAL,
2357 EL_DC_STEELWALL_1_VERTICAL,
2358 EL_DC_STEELWALL_1_TOPLEFT,
2359 EL_DC_STEELWALL_1_TOPRIGHT,
2360 EL_DC_STEELWALL_1_BOTTOMLEFT,
2361 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2362 EL_DC_STEELWALL_1_TOPLEFT_2,
2363 EL_DC_STEELWALL_1_TOPRIGHT_2,
2364 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2365 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2366 EL_DC_STEELWALL_2_LEFT,
2367 EL_DC_STEELWALL_2_RIGHT,
2368 EL_DC_STEELWALL_2_TOP,
2369 EL_DC_STEELWALL_2_BOTTOM,
2370 EL_DC_STEELWALL_2_HORIZONTAL,
2371 EL_DC_STEELWALL_2_VERTICAL,
2372 EL_DC_STEELWALL_2_MIDDLE,
2373 EL_DC_STEELWALL_2_SINGLE,
2374 EL_STEELWALL_SLIPPERY,
2388 EL_GATE_1_GRAY_ACTIVE,
2389 EL_GATE_2_GRAY_ACTIVE,
2390 EL_GATE_3_GRAY_ACTIVE,
2391 EL_GATE_4_GRAY_ACTIVE,
2400 EL_EM_GATE_1_GRAY_ACTIVE,
2401 EL_EM_GATE_2_GRAY_ACTIVE,
2402 EL_EM_GATE_3_GRAY_ACTIVE,
2403 EL_EM_GATE_4_GRAY_ACTIVE,
2412 EL_EMC_GATE_5_GRAY_ACTIVE,
2413 EL_EMC_GATE_6_GRAY_ACTIVE,
2414 EL_EMC_GATE_7_GRAY_ACTIVE,
2415 EL_EMC_GATE_8_GRAY_ACTIVE,
2417 EL_DC_GATE_WHITE_GRAY,
2418 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2419 EL_DC_GATE_FAKE_GRAY,
2421 EL_SWITCHGATE_OPENING,
2422 EL_SWITCHGATE_CLOSED,
2423 EL_SWITCHGATE_CLOSING,
2425 EL_DC_SWITCHGATE_SWITCH_UP,
2426 EL_DC_SWITCHGATE_SWITCH_DOWN,
2429 EL_TIMEGATE_OPENING,
2431 EL_TIMEGATE_CLOSING,
2433 EL_DC_TIMEGATE_SWITCH,
2434 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2439 EL_TUBE_VERTICAL_LEFT,
2440 EL_TUBE_VERTICAL_RIGHT,
2441 EL_TUBE_HORIZONTAL_UP,
2442 EL_TUBE_HORIZONTAL_DOWN,
2447 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2448 EL_EXPANDABLE_STEELWALL_VERTICAL,
2449 EL_EXPANDABLE_STEELWALL_ANY,
2454 static int ep_slippery[] =
2468 EL_ROBOT_WHEEL_ACTIVE,
2474 EL_ACID_POOL_TOPLEFT,
2475 EL_ACID_POOL_TOPRIGHT,
2485 EL_STEELWALL_SLIPPERY,
2488 EL_EMC_WALL_SLIPPERY_1,
2489 EL_EMC_WALL_SLIPPERY_2,
2490 EL_EMC_WALL_SLIPPERY_3,
2491 EL_EMC_WALL_SLIPPERY_4,
2493 EL_EMC_MAGIC_BALL_ACTIVE,
2498 static int ep_can_change[] =
2503 static int ep_can_move[] =
2505 /* same elements as in 'pb_can_move_into_acid' */
2528 static int ep_can_fall[] =
2542 EL_QUICKSAND_FAST_FULL,
2544 EL_BD_MAGIC_WALL_FULL,
2545 EL_DC_MAGIC_WALL_FULL,
2559 static int ep_can_smash_player[] =
2585 static int ep_can_smash_enemies[] =
2594 static int ep_can_smash_everything[] =
2603 static int ep_explodes_by_fire[] =
2605 /* same elements as in 'ep_explodes_impact' */
2610 /* same elements as in 'ep_explodes_smashed' */
2620 EL_EM_DYNAMITE_ACTIVE,
2621 EL_DYNABOMB_PLAYER_1_ACTIVE,
2622 EL_DYNABOMB_PLAYER_2_ACTIVE,
2623 EL_DYNABOMB_PLAYER_3_ACTIVE,
2624 EL_DYNABOMB_PLAYER_4_ACTIVE,
2625 EL_DYNABOMB_INCREASE_NUMBER,
2626 EL_DYNABOMB_INCREASE_SIZE,
2627 EL_DYNABOMB_INCREASE_POWER,
2628 EL_SP_DISK_RED_ACTIVE,
2642 static int ep_explodes_smashed[] =
2644 /* same elements as in 'ep_explodes_impact' */
2658 static int ep_explodes_impact[] =
2667 static int ep_walkable_over[] =
2671 EL_SOKOBAN_FIELD_EMPTY,
2677 EL_EM_STEEL_EXIT_OPEN,
2686 EL_GATE_1_GRAY_ACTIVE,
2687 EL_GATE_2_GRAY_ACTIVE,
2688 EL_GATE_3_GRAY_ACTIVE,
2689 EL_GATE_4_GRAY_ACTIVE,
2697 static int ep_walkable_inside[] =
2702 EL_TUBE_VERTICAL_LEFT,
2703 EL_TUBE_VERTICAL_RIGHT,
2704 EL_TUBE_HORIZONTAL_UP,
2705 EL_TUBE_HORIZONTAL_DOWN,
2714 static int ep_walkable_under[] =
2719 static int ep_passable_over[] =
2729 EL_EM_GATE_1_GRAY_ACTIVE,
2730 EL_EM_GATE_2_GRAY_ACTIVE,
2731 EL_EM_GATE_3_GRAY_ACTIVE,
2732 EL_EM_GATE_4_GRAY_ACTIVE,
2741 EL_EMC_GATE_5_GRAY_ACTIVE,
2742 EL_EMC_GATE_6_GRAY_ACTIVE,
2743 EL_EMC_GATE_7_GRAY_ACTIVE,
2744 EL_EMC_GATE_8_GRAY_ACTIVE,
2746 EL_DC_GATE_WHITE_GRAY,
2747 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2754 static int ep_passable_inside[] =
2760 EL_SP_PORT_HORIZONTAL,
2761 EL_SP_PORT_VERTICAL,
2763 EL_SP_GRAVITY_PORT_LEFT,
2764 EL_SP_GRAVITY_PORT_RIGHT,
2765 EL_SP_GRAVITY_PORT_UP,
2766 EL_SP_GRAVITY_PORT_DOWN,
2767 EL_SP_GRAVITY_ON_PORT_LEFT,
2768 EL_SP_GRAVITY_ON_PORT_RIGHT,
2769 EL_SP_GRAVITY_ON_PORT_UP,
2770 EL_SP_GRAVITY_ON_PORT_DOWN,
2771 EL_SP_GRAVITY_OFF_PORT_LEFT,
2772 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2773 EL_SP_GRAVITY_OFF_PORT_UP,
2774 EL_SP_GRAVITY_OFF_PORT_DOWN,
2779 static int ep_passable_under[] =
2784 static int ep_droppable[] =
2789 static int ep_explodes_1x1_old[] =
2794 static int ep_pushable[] =
2806 EL_SOKOBAN_FIELD_FULL,
2815 static int ep_explodes_cross_old[] =
2820 static int ep_protected[] =
2822 /* same elements as in 'ep_walkable_inside' */
2826 EL_TUBE_VERTICAL_LEFT,
2827 EL_TUBE_VERTICAL_RIGHT,
2828 EL_TUBE_HORIZONTAL_UP,
2829 EL_TUBE_HORIZONTAL_DOWN,
2835 /* same elements as in 'ep_passable_over' */
2844 EL_EM_GATE_1_GRAY_ACTIVE,
2845 EL_EM_GATE_2_GRAY_ACTIVE,
2846 EL_EM_GATE_3_GRAY_ACTIVE,
2847 EL_EM_GATE_4_GRAY_ACTIVE,
2856 EL_EMC_GATE_5_GRAY_ACTIVE,
2857 EL_EMC_GATE_6_GRAY_ACTIVE,
2858 EL_EMC_GATE_7_GRAY_ACTIVE,
2859 EL_EMC_GATE_8_GRAY_ACTIVE,
2861 EL_DC_GATE_WHITE_GRAY,
2862 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2866 /* same elements as in 'ep_passable_inside' */
2871 EL_SP_PORT_HORIZONTAL,
2872 EL_SP_PORT_VERTICAL,
2874 EL_SP_GRAVITY_PORT_LEFT,
2875 EL_SP_GRAVITY_PORT_RIGHT,
2876 EL_SP_GRAVITY_PORT_UP,
2877 EL_SP_GRAVITY_PORT_DOWN,
2878 EL_SP_GRAVITY_ON_PORT_LEFT,
2879 EL_SP_GRAVITY_ON_PORT_RIGHT,
2880 EL_SP_GRAVITY_ON_PORT_UP,
2881 EL_SP_GRAVITY_ON_PORT_DOWN,
2882 EL_SP_GRAVITY_OFF_PORT_LEFT,
2883 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2884 EL_SP_GRAVITY_OFF_PORT_UP,
2885 EL_SP_GRAVITY_OFF_PORT_DOWN,
2890 static int ep_throwable[] =
2895 static int ep_can_explode[] =
2897 /* same elements as in 'ep_explodes_impact' */
2902 /* same elements as in 'ep_explodes_smashed' */
2908 /* elements that can explode by explosion or by dragonfire */
2912 EL_EM_DYNAMITE_ACTIVE,
2913 EL_DYNABOMB_PLAYER_1_ACTIVE,
2914 EL_DYNABOMB_PLAYER_2_ACTIVE,
2915 EL_DYNABOMB_PLAYER_3_ACTIVE,
2916 EL_DYNABOMB_PLAYER_4_ACTIVE,
2917 EL_DYNABOMB_INCREASE_NUMBER,
2918 EL_DYNABOMB_INCREASE_SIZE,
2919 EL_DYNABOMB_INCREASE_POWER,
2920 EL_SP_DISK_RED_ACTIVE,
2928 /* elements that can explode only by explosion */
2934 static int ep_gravity_reachable[] =
2940 EL_INVISIBLE_SAND_ACTIVE,
2945 EL_SP_PORT_HORIZONTAL,
2946 EL_SP_PORT_VERTICAL,
2948 EL_SP_GRAVITY_PORT_LEFT,
2949 EL_SP_GRAVITY_PORT_RIGHT,
2950 EL_SP_GRAVITY_PORT_UP,
2951 EL_SP_GRAVITY_PORT_DOWN,
2952 EL_SP_GRAVITY_ON_PORT_LEFT,
2953 EL_SP_GRAVITY_ON_PORT_RIGHT,
2954 EL_SP_GRAVITY_ON_PORT_UP,
2955 EL_SP_GRAVITY_ON_PORT_DOWN,
2956 EL_SP_GRAVITY_OFF_PORT_LEFT,
2957 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2958 EL_SP_GRAVITY_OFF_PORT_UP,
2959 EL_SP_GRAVITY_OFF_PORT_DOWN,
2965 static int ep_player[] =
2972 EL_SOKOBAN_FIELD_PLAYER,
2978 static int ep_can_pass_magic_wall[] =
2992 static int ep_can_pass_dc_magic_wall[] =
3008 static int ep_switchable[] =
3012 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3013 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3014 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3015 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3016 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3017 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3018 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3019 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3020 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3021 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3022 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3023 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3024 EL_SWITCHGATE_SWITCH_UP,
3025 EL_SWITCHGATE_SWITCH_DOWN,
3026 EL_DC_SWITCHGATE_SWITCH_UP,
3027 EL_DC_SWITCHGATE_SWITCH_DOWN,
3029 EL_LIGHT_SWITCH_ACTIVE,
3031 EL_DC_TIMEGATE_SWITCH,
3032 EL_BALLOON_SWITCH_LEFT,
3033 EL_BALLOON_SWITCH_RIGHT,
3034 EL_BALLOON_SWITCH_UP,
3035 EL_BALLOON_SWITCH_DOWN,
3036 EL_BALLOON_SWITCH_ANY,
3037 EL_BALLOON_SWITCH_NONE,
3040 EL_EMC_MAGIC_BALL_SWITCH,
3041 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3046 static int ep_bd_element[] =
3080 static int ep_sp_element[] =
3082 /* should always be valid */
3085 /* standard classic Supaplex elements */
3092 EL_SP_HARDWARE_GRAY,
3100 EL_SP_GRAVITY_PORT_RIGHT,
3101 EL_SP_GRAVITY_PORT_DOWN,
3102 EL_SP_GRAVITY_PORT_LEFT,
3103 EL_SP_GRAVITY_PORT_UP,
3108 EL_SP_PORT_VERTICAL,
3109 EL_SP_PORT_HORIZONTAL,
3115 EL_SP_HARDWARE_BASE_1,
3116 EL_SP_HARDWARE_GREEN,
3117 EL_SP_HARDWARE_BLUE,
3119 EL_SP_HARDWARE_YELLOW,
3120 EL_SP_HARDWARE_BASE_2,
3121 EL_SP_HARDWARE_BASE_3,
3122 EL_SP_HARDWARE_BASE_4,
3123 EL_SP_HARDWARE_BASE_5,
3124 EL_SP_HARDWARE_BASE_6,
3128 /* additional elements that appeared in newer Supaplex levels */
3131 /* additional gravity port elements (not switching, but setting gravity) */
3132 EL_SP_GRAVITY_ON_PORT_LEFT,
3133 EL_SP_GRAVITY_ON_PORT_RIGHT,
3134 EL_SP_GRAVITY_ON_PORT_UP,
3135 EL_SP_GRAVITY_ON_PORT_DOWN,
3136 EL_SP_GRAVITY_OFF_PORT_LEFT,
3137 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3138 EL_SP_GRAVITY_OFF_PORT_UP,
3139 EL_SP_GRAVITY_OFF_PORT_DOWN,
3141 /* more than one Murphy in a level results in an inactive clone */
3144 /* runtime Supaplex elements */
3145 EL_SP_DISK_RED_ACTIVE,
3146 EL_SP_TERMINAL_ACTIVE,
3147 EL_SP_BUGGY_BASE_ACTIVATING,
3148 EL_SP_BUGGY_BASE_ACTIVE,
3155 static int ep_sb_element[] =
3160 EL_SOKOBAN_FIELD_EMPTY,
3161 EL_SOKOBAN_FIELD_FULL,
3162 EL_SOKOBAN_FIELD_PLAYER,
3167 EL_INVISIBLE_STEELWALL,
3172 static int ep_gem[] =
3184 static int ep_food_dark_yamyam[] =
3212 static int ep_food_penguin[] =
3226 static int ep_food_pig[] =
3238 static int ep_historic_wall[] =
3249 EL_GATE_1_GRAY_ACTIVE,
3250 EL_GATE_2_GRAY_ACTIVE,
3251 EL_GATE_3_GRAY_ACTIVE,
3252 EL_GATE_4_GRAY_ACTIVE,
3261 EL_EM_GATE_1_GRAY_ACTIVE,
3262 EL_EM_GATE_2_GRAY_ACTIVE,
3263 EL_EM_GATE_3_GRAY_ACTIVE,
3264 EL_EM_GATE_4_GRAY_ACTIVE,
3271 EL_EXPANDABLE_WALL_HORIZONTAL,
3272 EL_EXPANDABLE_WALL_VERTICAL,
3273 EL_EXPANDABLE_WALL_ANY,
3274 EL_EXPANDABLE_WALL_GROWING,
3275 EL_BD_EXPANDABLE_WALL,
3282 EL_SP_HARDWARE_GRAY,
3283 EL_SP_HARDWARE_GREEN,
3284 EL_SP_HARDWARE_BLUE,
3286 EL_SP_HARDWARE_YELLOW,
3287 EL_SP_HARDWARE_BASE_1,
3288 EL_SP_HARDWARE_BASE_2,
3289 EL_SP_HARDWARE_BASE_3,
3290 EL_SP_HARDWARE_BASE_4,
3291 EL_SP_HARDWARE_BASE_5,
3292 EL_SP_HARDWARE_BASE_6,
3294 EL_SP_TERMINAL_ACTIVE,
3297 EL_INVISIBLE_STEELWALL,
3298 EL_INVISIBLE_STEELWALL_ACTIVE,
3300 EL_INVISIBLE_WALL_ACTIVE,
3301 EL_STEELWALL_SLIPPERY,
3318 static int ep_historic_solid[] =
3322 EL_EXPANDABLE_WALL_HORIZONTAL,
3323 EL_EXPANDABLE_WALL_VERTICAL,
3324 EL_EXPANDABLE_WALL_ANY,
3325 EL_BD_EXPANDABLE_WALL,
3338 EL_QUICKSAND_FILLING,
3339 EL_QUICKSAND_EMPTYING,
3341 EL_MAGIC_WALL_ACTIVE,
3342 EL_MAGIC_WALL_EMPTYING,
3343 EL_MAGIC_WALL_FILLING,
3347 EL_BD_MAGIC_WALL_ACTIVE,
3348 EL_BD_MAGIC_WALL_EMPTYING,
3349 EL_BD_MAGIC_WALL_FULL,
3350 EL_BD_MAGIC_WALL_FILLING,
3351 EL_BD_MAGIC_WALL_DEAD,
3360 EL_SP_TERMINAL_ACTIVE,
3364 EL_INVISIBLE_WALL_ACTIVE,
3365 EL_SWITCHGATE_SWITCH_UP,
3366 EL_SWITCHGATE_SWITCH_DOWN,
3367 EL_DC_SWITCHGATE_SWITCH_UP,
3368 EL_DC_SWITCHGATE_SWITCH_DOWN,
3370 EL_TIMEGATE_SWITCH_ACTIVE,
3371 EL_DC_TIMEGATE_SWITCH,
3372 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3384 /* the following elements are a direct copy of "indestructible" elements,
3385 except "EL_ACID", which is "indestructible", but not "solid"! */
3390 EL_ACID_POOL_TOPLEFT,
3391 EL_ACID_POOL_TOPRIGHT,
3392 EL_ACID_POOL_BOTTOMLEFT,
3393 EL_ACID_POOL_BOTTOM,
3394 EL_ACID_POOL_BOTTOMRIGHT,
3395 EL_SP_HARDWARE_GRAY,
3396 EL_SP_HARDWARE_GREEN,
3397 EL_SP_HARDWARE_BLUE,
3399 EL_SP_HARDWARE_YELLOW,
3400 EL_SP_HARDWARE_BASE_1,
3401 EL_SP_HARDWARE_BASE_2,
3402 EL_SP_HARDWARE_BASE_3,
3403 EL_SP_HARDWARE_BASE_4,
3404 EL_SP_HARDWARE_BASE_5,
3405 EL_SP_HARDWARE_BASE_6,
3406 EL_INVISIBLE_STEELWALL,
3407 EL_INVISIBLE_STEELWALL_ACTIVE,
3408 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3409 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3410 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3411 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3412 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3413 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3414 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3415 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3416 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3417 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3418 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3419 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3421 EL_LIGHT_SWITCH_ACTIVE,
3422 EL_SIGN_EXCLAMATION,
3423 EL_SIGN_RADIOACTIVITY,
3430 EL_SIGN_ENTRY_FORBIDDEN,
3431 EL_SIGN_EMERGENCY_EXIT,
3439 EL_STEEL_EXIT_CLOSED,
3441 EL_DC_STEELWALL_1_LEFT,
3442 EL_DC_STEELWALL_1_RIGHT,
3443 EL_DC_STEELWALL_1_TOP,
3444 EL_DC_STEELWALL_1_BOTTOM,
3445 EL_DC_STEELWALL_1_HORIZONTAL,
3446 EL_DC_STEELWALL_1_VERTICAL,
3447 EL_DC_STEELWALL_1_TOPLEFT,
3448 EL_DC_STEELWALL_1_TOPRIGHT,
3449 EL_DC_STEELWALL_1_BOTTOMLEFT,
3450 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3451 EL_DC_STEELWALL_1_TOPLEFT_2,
3452 EL_DC_STEELWALL_1_TOPRIGHT_2,
3453 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3454 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3455 EL_DC_STEELWALL_2_LEFT,
3456 EL_DC_STEELWALL_2_RIGHT,
3457 EL_DC_STEELWALL_2_TOP,
3458 EL_DC_STEELWALL_2_BOTTOM,
3459 EL_DC_STEELWALL_2_HORIZONTAL,
3460 EL_DC_STEELWALL_2_VERTICAL,
3461 EL_DC_STEELWALL_2_MIDDLE,
3462 EL_DC_STEELWALL_2_SINGLE,
3463 EL_STEELWALL_SLIPPERY,
3477 EL_GATE_1_GRAY_ACTIVE,
3478 EL_GATE_2_GRAY_ACTIVE,
3479 EL_GATE_3_GRAY_ACTIVE,
3480 EL_GATE_4_GRAY_ACTIVE,
3489 EL_EM_GATE_1_GRAY_ACTIVE,
3490 EL_EM_GATE_2_GRAY_ACTIVE,
3491 EL_EM_GATE_3_GRAY_ACTIVE,
3492 EL_EM_GATE_4_GRAY_ACTIVE,
3494 EL_SWITCHGATE_OPENING,
3495 EL_SWITCHGATE_CLOSED,
3496 EL_SWITCHGATE_CLOSING,
3498 EL_TIMEGATE_OPENING,
3500 EL_TIMEGATE_CLOSING,
3504 EL_TUBE_VERTICAL_LEFT,
3505 EL_TUBE_VERTICAL_RIGHT,
3506 EL_TUBE_HORIZONTAL_UP,
3507 EL_TUBE_HORIZONTAL_DOWN,
3516 static int ep_classic_enemy[] =
3533 static int ep_belt[] =
3535 EL_CONVEYOR_BELT_1_LEFT,
3536 EL_CONVEYOR_BELT_1_MIDDLE,
3537 EL_CONVEYOR_BELT_1_RIGHT,
3538 EL_CONVEYOR_BELT_2_LEFT,
3539 EL_CONVEYOR_BELT_2_MIDDLE,
3540 EL_CONVEYOR_BELT_2_RIGHT,
3541 EL_CONVEYOR_BELT_3_LEFT,
3542 EL_CONVEYOR_BELT_3_MIDDLE,
3543 EL_CONVEYOR_BELT_3_RIGHT,
3544 EL_CONVEYOR_BELT_4_LEFT,
3545 EL_CONVEYOR_BELT_4_MIDDLE,
3546 EL_CONVEYOR_BELT_4_RIGHT,
3551 static int ep_belt_active[] =
3553 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3554 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3555 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3556 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3557 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3558 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3559 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3560 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3561 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3562 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3563 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3564 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3569 static int ep_belt_switch[] =
3571 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3572 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3573 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3574 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3575 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3576 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3577 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3578 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3579 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3580 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3581 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3582 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3587 static int ep_tube[] =
3594 EL_TUBE_HORIZONTAL_UP,
3595 EL_TUBE_HORIZONTAL_DOWN,
3597 EL_TUBE_VERTICAL_LEFT,
3598 EL_TUBE_VERTICAL_RIGHT,
3604 static int ep_acid_pool[] =
3606 EL_ACID_POOL_TOPLEFT,
3607 EL_ACID_POOL_TOPRIGHT,
3608 EL_ACID_POOL_BOTTOMLEFT,
3609 EL_ACID_POOL_BOTTOM,
3610 EL_ACID_POOL_BOTTOMRIGHT,
3615 static int ep_keygate[] =
3625 EL_GATE_1_GRAY_ACTIVE,
3626 EL_GATE_2_GRAY_ACTIVE,
3627 EL_GATE_3_GRAY_ACTIVE,
3628 EL_GATE_4_GRAY_ACTIVE,
3637 EL_EM_GATE_1_GRAY_ACTIVE,
3638 EL_EM_GATE_2_GRAY_ACTIVE,
3639 EL_EM_GATE_3_GRAY_ACTIVE,
3640 EL_EM_GATE_4_GRAY_ACTIVE,
3649 EL_EMC_GATE_5_GRAY_ACTIVE,
3650 EL_EMC_GATE_6_GRAY_ACTIVE,
3651 EL_EMC_GATE_7_GRAY_ACTIVE,
3652 EL_EMC_GATE_8_GRAY_ACTIVE,
3654 EL_DC_GATE_WHITE_GRAY,
3655 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3660 static int ep_amoeboid[] =
3672 static int ep_amoebalive[] =
3683 static int ep_has_editor_content[] =
3705 static int ep_can_turn_each_move[] =
3707 /* !!! do something with this one !!! */
3711 static int ep_can_grow[] =
3725 static int ep_active_bomb[] =
3728 EL_EM_DYNAMITE_ACTIVE,
3729 EL_DYNABOMB_PLAYER_1_ACTIVE,
3730 EL_DYNABOMB_PLAYER_2_ACTIVE,
3731 EL_DYNABOMB_PLAYER_3_ACTIVE,
3732 EL_DYNABOMB_PLAYER_4_ACTIVE,
3733 EL_SP_DISK_RED_ACTIVE,
3738 static int ep_inactive[] =
3748 EL_QUICKSAND_FAST_EMPTY,
3771 EL_GATE_1_GRAY_ACTIVE,
3772 EL_GATE_2_GRAY_ACTIVE,
3773 EL_GATE_3_GRAY_ACTIVE,
3774 EL_GATE_4_GRAY_ACTIVE,
3783 EL_EM_GATE_1_GRAY_ACTIVE,
3784 EL_EM_GATE_2_GRAY_ACTIVE,
3785 EL_EM_GATE_3_GRAY_ACTIVE,
3786 EL_EM_GATE_4_GRAY_ACTIVE,
3795 EL_EMC_GATE_5_GRAY_ACTIVE,
3796 EL_EMC_GATE_6_GRAY_ACTIVE,
3797 EL_EMC_GATE_7_GRAY_ACTIVE,
3798 EL_EMC_GATE_8_GRAY_ACTIVE,
3800 EL_DC_GATE_WHITE_GRAY,
3801 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3802 EL_DC_GATE_FAKE_GRAY,
3805 EL_INVISIBLE_STEELWALL,
3813 EL_WALL_EMERALD_YELLOW,
3814 EL_DYNABOMB_INCREASE_NUMBER,
3815 EL_DYNABOMB_INCREASE_SIZE,
3816 EL_DYNABOMB_INCREASE_POWER,
3820 EL_SOKOBAN_FIELD_EMPTY,
3821 EL_SOKOBAN_FIELD_FULL,
3822 EL_WALL_EMERALD_RED,
3823 EL_WALL_EMERALD_PURPLE,
3824 EL_ACID_POOL_TOPLEFT,
3825 EL_ACID_POOL_TOPRIGHT,
3826 EL_ACID_POOL_BOTTOMLEFT,
3827 EL_ACID_POOL_BOTTOM,
3828 EL_ACID_POOL_BOTTOMRIGHT,
3832 EL_BD_MAGIC_WALL_DEAD,
3834 EL_DC_MAGIC_WALL_DEAD,
3835 EL_AMOEBA_TO_DIAMOND,
3843 EL_SP_GRAVITY_PORT_RIGHT,
3844 EL_SP_GRAVITY_PORT_DOWN,
3845 EL_SP_GRAVITY_PORT_LEFT,
3846 EL_SP_GRAVITY_PORT_UP,
3847 EL_SP_PORT_HORIZONTAL,
3848 EL_SP_PORT_VERTICAL,
3859 EL_SP_HARDWARE_GRAY,
3860 EL_SP_HARDWARE_GREEN,
3861 EL_SP_HARDWARE_BLUE,
3863 EL_SP_HARDWARE_YELLOW,
3864 EL_SP_HARDWARE_BASE_1,
3865 EL_SP_HARDWARE_BASE_2,
3866 EL_SP_HARDWARE_BASE_3,
3867 EL_SP_HARDWARE_BASE_4,
3868 EL_SP_HARDWARE_BASE_5,
3869 EL_SP_HARDWARE_BASE_6,
3870 EL_SP_GRAVITY_ON_PORT_LEFT,
3871 EL_SP_GRAVITY_ON_PORT_RIGHT,
3872 EL_SP_GRAVITY_ON_PORT_UP,
3873 EL_SP_GRAVITY_ON_PORT_DOWN,
3874 EL_SP_GRAVITY_OFF_PORT_LEFT,
3875 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3876 EL_SP_GRAVITY_OFF_PORT_UP,
3877 EL_SP_GRAVITY_OFF_PORT_DOWN,
3878 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3879 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3880 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3881 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3882 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3883 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3884 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3885 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3886 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3887 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3888 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3889 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3890 EL_SIGN_EXCLAMATION,
3891 EL_SIGN_RADIOACTIVITY,
3898 EL_SIGN_ENTRY_FORBIDDEN,
3899 EL_SIGN_EMERGENCY_EXIT,
3907 EL_DC_STEELWALL_1_LEFT,
3908 EL_DC_STEELWALL_1_RIGHT,
3909 EL_DC_STEELWALL_1_TOP,
3910 EL_DC_STEELWALL_1_BOTTOM,
3911 EL_DC_STEELWALL_1_HORIZONTAL,
3912 EL_DC_STEELWALL_1_VERTICAL,
3913 EL_DC_STEELWALL_1_TOPLEFT,
3914 EL_DC_STEELWALL_1_TOPRIGHT,
3915 EL_DC_STEELWALL_1_BOTTOMLEFT,
3916 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3917 EL_DC_STEELWALL_1_TOPLEFT_2,
3918 EL_DC_STEELWALL_1_TOPRIGHT_2,
3919 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3920 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3921 EL_DC_STEELWALL_2_LEFT,
3922 EL_DC_STEELWALL_2_RIGHT,
3923 EL_DC_STEELWALL_2_TOP,
3924 EL_DC_STEELWALL_2_BOTTOM,
3925 EL_DC_STEELWALL_2_HORIZONTAL,
3926 EL_DC_STEELWALL_2_VERTICAL,
3927 EL_DC_STEELWALL_2_MIDDLE,
3928 EL_DC_STEELWALL_2_SINGLE,
3929 EL_STEELWALL_SLIPPERY,
3934 EL_EMC_WALL_SLIPPERY_1,
3935 EL_EMC_WALL_SLIPPERY_2,
3936 EL_EMC_WALL_SLIPPERY_3,
3937 EL_EMC_WALL_SLIPPERY_4,
3958 static int ep_em_slippery_wall[] =
3963 static int ep_gfx_crumbled[] =
3974 static int ep_editor_cascade_active[] =
3976 EL_INTERNAL_CASCADE_BD_ACTIVE,
3977 EL_INTERNAL_CASCADE_EM_ACTIVE,
3978 EL_INTERNAL_CASCADE_EMC_ACTIVE,
3979 EL_INTERNAL_CASCADE_RND_ACTIVE,
3980 EL_INTERNAL_CASCADE_SB_ACTIVE,
3981 EL_INTERNAL_CASCADE_SP_ACTIVE,
3982 EL_INTERNAL_CASCADE_DC_ACTIVE,
3983 EL_INTERNAL_CASCADE_DX_ACTIVE,
3984 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
3985 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
3986 EL_INTERNAL_CASCADE_CE_ACTIVE,
3987 EL_INTERNAL_CASCADE_GE_ACTIVE,
3988 EL_INTERNAL_CASCADE_REF_ACTIVE,
3989 EL_INTERNAL_CASCADE_USER_ACTIVE,
3990 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
3995 static int ep_editor_cascade_inactive[] =
3997 EL_INTERNAL_CASCADE_BD,
3998 EL_INTERNAL_CASCADE_EM,
3999 EL_INTERNAL_CASCADE_EMC,
4000 EL_INTERNAL_CASCADE_RND,
4001 EL_INTERNAL_CASCADE_SB,
4002 EL_INTERNAL_CASCADE_SP,
4003 EL_INTERNAL_CASCADE_DC,
4004 EL_INTERNAL_CASCADE_DX,
4005 EL_INTERNAL_CASCADE_CHARS,
4006 EL_INTERNAL_CASCADE_STEEL_CHARS,
4007 EL_INTERNAL_CASCADE_CE,
4008 EL_INTERNAL_CASCADE_GE,
4009 EL_INTERNAL_CASCADE_REF,
4010 EL_INTERNAL_CASCADE_USER,
4011 EL_INTERNAL_CASCADE_DYNAMIC,
4016 static int ep_obsolete[] =
4020 EL_EM_KEY_1_FILE_OBSOLETE,
4021 EL_EM_KEY_2_FILE_OBSOLETE,
4022 EL_EM_KEY_3_FILE_OBSOLETE,
4023 EL_EM_KEY_4_FILE_OBSOLETE,
4024 EL_ENVELOPE_OBSOLETE,
4033 } element_properties[] =
4035 { ep_diggable, EP_DIGGABLE },
4036 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4037 { ep_dont_run_into, EP_DONT_RUN_INTO },
4038 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4039 { ep_dont_touch, EP_DONT_TOUCH },
4040 { ep_indestructible, EP_INDESTRUCTIBLE },
4041 { ep_slippery, EP_SLIPPERY },
4042 { ep_can_change, EP_CAN_CHANGE },
4043 { ep_can_move, EP_CAN_MOVE },
4044 { ep_can_fall, EP_CAN_FALL },
4045 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4046 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4047 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4048 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4049 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4050 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4051 { ep_walkable_over, EP_WALKABLE_OVER },
4052 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4053 { ep_walkable_under, EP_WALKABLE_UNDER },
4054 { ep_passable_over, EP_PASSABLE_OVER },
4055 { ep_passable_inside, EP_PASSABLE_INSIDE },
4056 { ep_passable_under, EP_PASSABLE_UNDER },
4057 { ep_droppable, EP_DROPPABLE },
4058 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4059 { ep_pushable, EP_PUSHABLE },
4060 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4061 { ep_protected, EP_PROTECTED },
4062 { ep_throwable, EP_THROWABLE },
4063 { ep_can_explode, EP_CAN_EXPLODE },
4064 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4066 { ep_player, EP_PLAYER },
4067 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4068 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4069 { ep_switchable, EP_SWITCHABLE },
4070 { ep_bd_element, EP_BD_ELEMENT },
4071 { ep_sp_element, EP_SP_ELEMENT },
4072 { ep_sb_element, EP_SB_ELEMENT },
4074 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4075 { ep_food_penguin, EP_FOOD_PENGUIN },
4076 { ep_food_pig, EP_FOOD_PIG },
4077 { ep_historic_wall, EP_HISTORIC_WALL },
4078 { ep_historic_solid, EP_HISTORIC_SOLID },
4079 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4080 { ep_belt, EP_BELT },
4081 { ep_belt_active, EP_BELT_ACTIVE },
4082 { ep_belt_switch, EP_BELT_SWITCH },
4083 { ep_tube, EP_TUBE },
4084 { ep_acid_pool, EP_ACID_POOL },
4085 { ep_keygate, EP_KEYGATE },
4086 { ep_amoeboid, EP_AMOEBOID },
4087 { ep_amoebalive, EP_AMOEBALIVE },
4088 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4089 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4090 { ep_can_grow, EP_CAN_GROW },
4091 { ep_active_bomb, EP_ACTIVE_BOMB },
4092 { ep_inactive, EP_INACTIVE },
4094 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4096 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4098 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4099 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4101 { ep_obsolete, EP_OBSOLETE },
4108 /* always start with reliable default values (element has no properties) */
4109 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4110 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4111 SET_PROPERTY(i, j, FALSE);
4113 /* set all base element properties from above array definitions */
4114 for (i = 0; element_properties[i].elements != NULL; i++)
4115 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4116 SET_PROPERTY((element_properties[i].elements)[j],
4117 element_properties[i].property, TRUE);
4119 /* copy properties to some elements that are only stored in level file */
4120 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4121 for (j = 0; copy_properties[j][0] != -1; j++)
4122 if (HAS_PROPERTY(copy_properties[j][0], i))
4123 for (k = 1; k <= 4; k++)
4124 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4126 /* set static element properties that are not listed in array definitions */
4127 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4128 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4131 void InitElementPropertiesEngine(int engine_version)
4133 static int no_wall_properties[] =
4136 EP_COLLECTIBLE_ONLY,
4138 EP_DONT_COLLIDE_WITH,
4141 EP_CAN_SMASH_PLAYER,
4142 EP_CAN_SMASH_ENEMIES,
4143 EP_CAN_SMASH_EVERYTHING,
4148 EP_FOOD_DARK_YAMYAM,
4164 /* important: after initialization in InitElementPropertiesStatic(), the
4165 elements are not again initialized to a default value; therefore all
4166 changes have to make sure that they leave the element with a defined
4167 property (which means that conditional property changes must be set to
4168 a reliable default value before) */
4170 /* resolve group elements */
4171 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4172 ResolveGroupElement(EL_GROUP_START + i);
4174 /* set all special, combined or engine dependent element properties */
4175 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4177 /* ---------- INACTIVE ------------------------------------------------- */
4178 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4179 i <= EL_CHAR_END) ||
4180 (i >= EL_STEEL_CHAR_START &&
4181 i <= EL_STEEL_CHAR_END)));
4183 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4184 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4185 IS_WALKABLE_INSIDE(i) ||
4186 IS_WALKABLE_UNDER(i)));
4188 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4189 IS_PASSABLE_INSIDE(i) ||
4190 IS_PASSABLE_UNDER(i)));
4192 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4193 IS_PASSABLE_OVER(i)));
4195 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4196 IS_PASSABLE_INSIDE(i)));
4198 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4199 IS_PASSABLE_UNDER(i)));
4201 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4204 /* ---------- COLLECTIBLE ---------------------------------------------- */
4205 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4209 /* ---------- SNAPPABLE ------------------------------------------------ */
4210 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4211 IS_COLLECTIBLE(i) ||
4215 /* ---------- WALL ----------------------------------------------------- */
4216 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4218 for (j = 0; no_wall_properties[j] != -1; j++)
4219 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4220 i >= EL_FIRST_RUNTIME_UNREAL)
4221 SET_PROPERTY(i, EP_WALL, FALSE);
4223 if (IS_HISTORIC_WALL(i))
4224 SET_PROPERTY(i, EP_WALL, TRUE);
4226 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4227 if (engine_version < VERSION_IDENT(2,2,0,0))
4228 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4230 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4232 !IS_COLLECTIBLE(i)));
4234 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4235 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4236 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4238 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4239 IS_INDESTRUCTIBLE(i)));
4241 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4243 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4244 else if (engine_version < VERSION_IDENT(2,2,0,0))
4245 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4247 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4251 if (IS_CUSTOM_ELEMENT(i))
4253 /* these are additional properties which are initially false when set */
4255 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4257 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4258 if (DONT_COLLIDE_WITH(i))
4259 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4261 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4262 if (CAN_SMASH_EVERYTHING(i))
4263 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4264 if (CAN_SMASH_ENEMIES(i))
4265 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4268 /* ---------- CAN_SMASH ------------------------------------------------ */
4269 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4270 CAN_SMASH_ENEMIES(i) ||
4271 CAN_SMASH_EVERYTHING(i)));
4273 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4274 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4275 EXPLODES_BY_FIRE(i)));
4277 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4278 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4279 EXPLODES_SMASHED(i)));
4281 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4282 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4283 EXPLODES_IMPACT(i)));
4285 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4286 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4288 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4289 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4290 i == EL_BLACK_ORB));
4292 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4293 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4295 IS_CUSTOM_ELEMENT(i)));
4297 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4298 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4299 i == EL_SP_ELECTRON));
4301 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4302 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4303 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4304 getMoveIntoAcidProperty(&level, i));
4306 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4307 if (MAYBE_DONT_COLLIDE_WITH(i))
4308 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4309 getDontCollideWithProperty(&level, i));
4311 /* ---------- SP_PORT -------------------------------------------------- */
4312 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4313 IS_PASSABLE_INSIDE(i)));
4315 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4316 for (j = 0; j < level.num_android_clone_elements; j++)
4317 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4319 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4321 /* ---------- CAN_CHANGE ----------------------------------------------- */
4322 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4323 for (j = 0; j < element_info[i].num_change_pages; j++)
4324 if (element_info[i].change_page[j].can_change)
4325 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4327 /* ---------- HAS_ACTION ----------------------------------------------- */
4328 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4329 for (j = 0; j < element_info[i].num_change_pages; j++)
4330 if (element_info[i].change_page[j].has_action)
4331 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4333 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4334 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4337 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4339 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4340 element_info[i].crumbled[ACTION_DEFAULT] !=
4341 element_info[i].graphic[ACTION_DEFAULT]);
4343 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
4344 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4345 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
4348 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4349 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4350 IS_EDITOR_CASCADE_INACTIVE(i)));
4353 /* dynamically adjust element properties according to game engine version */
4355 static int ep_em_slippery_wall[] =
4360 EL_EXPANDABLE_WALL_HORIZONTAL,
4361 EL_EXPANDABLE_WALL_VERTICAL,
4362 EL_EXPANDABLE_WALL_ANY,
4363 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4364 EL_EXPANDABLE_STEELWALL_VERTICAL,
4365 EL_EXPANDABLE_STEELWALL_ANY,
4366 EL_EXPANDABLE_STEELWALL_GROWING,
4370 /* special EM style gems behaviour */
4371 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4372 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4373 level.em_slippery_gems);
4375 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4376 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4377 (level.em_slippery_gems &&
4378 engine_version > VERSION_IDENT(2,0,1,0)));
4381 /* this is needed because some graphics depend on element properties */
4382 if (game_status == GAME_MODE_PLAYING)
4383 InitElementGraphicInfo();
4386 void InitElementPropertiesAfterLoading(int engine_version)
4390 /* set some other uninitialized values of custom elements in older levels */
4391 if (engine_version < VERSION_IDENT(3,1,0,0))
4393 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4395 int element = EL_CUSTOM_START + i;
4397 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4399 element_info[element].explosion_delay = 17;
4400 element_info[element].ignition_delay = 8;
4405 static void InitGlobal()
4409 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4411 /* check if element_name_info entry defined for each element in "main.h" */
4412 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4413 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4415 element_info[i].token_name = element_name_info[i].token_name;
4416 element_info[i].class_name = element_name_info[i].class_name;
4417 element_info[i].editor_description= element_name_info[i].editor_description;
4420 printf("%04d: %s\n", i, element_name_info[i].token_name);
4424 /* always start with reliable default values (all elements) */
4425 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4426 ActiveElement[i] = i;
4428 /* now add all entries that have an active state (active elements) */
4429 for (i = 0; element_with_active_state[i].element != -1; i++)
4431 int element = element_with_active_state[i].element;
4432 int element_active = element_with_active_state[i].element_active;
4434 ActiveElement[element] = element_active;
4437 /* always start with reliable default values (all buttons) */
4438 for (i = 0; i < NUM_IMAGE_FILES; i++)
4439 ActiveButton[i] = i;
4441 /* now add all entries that have an active state (active buttons) */
4442 for (i = 0; button_with_active_state[i].button != -1; i++)
4444 int button = button_with_active_state[i].button;
4445 int button_active = button_with_active_state[i].button_active;
4447 ActiveButton[button] = button_active;
4450 /* always start with reliable default values (all fonts) */
4451 for (i = 0; i < NUM_FONTS; i++)
4454 /* now add all entries that have an active state (active fonts) */
4455 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4457 int font = font_with_active_state[i].font_nr;
4458 int font_active = font_with_active_state[i].font_nr_active;
4460 ActiveFont[font] = font_active;
4463 global.autoplay_leveldir = NULL;
4464 global.convert_leveldir = NULL;
4466 global.frames_per_second = 0;
4467 global.fps_slowdown = FALSE;
4468 global.fps_slowdown_factor = 1;
4470 global.border_status = GAME_MODE_MAIN;
4472 global.fading_status = GAME_MODE_MAIN;
4473 global.fading_type = TYPE_ENTER_MENU;
4477 void Execute_Command(char *command)
4481 if (strEqual(command, "print graphicsinfo.conf"))
4483 printf("# You can configure additional/alternative image files here.\n");
4484 printf("# (The entries below are default and therefore commented out.)\n");
4486 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4488 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4491 for (i = 0; image_config[i].token != NULL; i++)
4492 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
4493 image_config[i].value));
4497 else if (strEqual(command, "print soundsinfo.conf"))
4499 printf("# You can configure additional/alternative sound files here.\n");
4500 printf("# (The entries below are default and therefore commented out.)\n");
4502 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4504 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4507 for (i = 0; sound_config[i].token != NULL; i++)
4508 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4509 sound_config[i].value));
4513 else if (strEqual(command, "print musicinfo.conf"))
4515 printf("# You can configure additional/alternative music files here.\n");
4516 printf("# (The entries below are default and therefore commented out.)\n");
4518 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4520 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4523 for (i = 0; music_config[i].token != NULL; i++)
4524 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
4525 music_config[i].value));
4529 else if (strEqual(command, "print editorsetup.conf"))
4531 printf("# You can configure your personal editor element list here.\n");
4532 printf("# (The entries below are default and therefore commented out.)\n");
4535 /* this is needed to be able to check element list for cascade elements */
4536 InitElementPropertiesStatic();
4537 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4539 PrintEditorElementList();
4543 else if (strEqual(command, "print helpanim.conf"))
4545 printf("# You can configure different element help animations here.\n");
4546 printf("# (The entries below are default and therefore commented out.)\n");
4549 for (i = 0; helpanim_config[i].token != NULL; i++)
4551 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4552 helpanim_config[i].value));
4554 if (strEqual(helpanim_config[i].token, "end"))
4560 else if (strEqual(command, "print helptext.conf"))
4562 printf("# You can configure different element help text here.\n");
4563 printf("# (The entries below are default and therefore commented out.)\n");
4566 for (i = 0; helptext_config[i].token != NULL; i++)
4567 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4568 helptext_config[i].value));
4572 else if (strncmp(command, "dump level ", 11) == 0)
4574 char *filename = &command[11];
4576 if (!fileExists(filename))
4577 Error(ERR_EXIT, "cannot open file '%s'", filename);
4579 LoadLevelFromFilename(&level, filename);
4584 else if (strncmp(command, "dump tape ", 10) == 0)
4586 char *filename = &command[10];
4588 if (!fileExists(filename))
4589 Error(ERR_EXIT, "cannot open file '%s'", filename);
4591 LoadTapeFromFilename(filename);
4596 else if (strncmp(command, "autoplay ", 9) == 0)
4598 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
4600 while (*str_ptr != '\0') /* continue parsing string */
4602 /* cut leading whitespace from string, replace it by string terminator */
4603 while (*str_ptr == ' ' || *str_ptr == '\t')
4606 if (*str_ptr == '\0') /* end of string reached */
4609 if (global.autoplay_leveldir == NULL) /* read level set string */
4611 global.autoplay_leveldir = str_ptr;
4612 global.autoplay_all = TRUE; /* default: play all tapes */
4614 for (i = 0; i < MAX_TAPES_PER_SET; i++)
4615 global.autoplay_level[i] = FALSE;
4617 else /* read level number string */
4619 int level_nr = atoi(str_ptr); /* get level_nr value */
4621 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
4622 global.autoplay_level[level_nr] = TRUE;
4624 global.autoplay_all = FALSE;
4627 /* advance string pointer to the next whitespace (or end of string) */
4628 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
4632 else if (strncmp(command, "convert ", 8) == 0)
4634 char *str_copy = getStringCopy(&command[8]);
4635 char *str_ptr = strchr(str_copy, ' ');
4637 global.convert_leveldir = str_copy;
4638 global.convert_level_nr = -1;
4640 if (str_ptr != NULL) /* level number follows */
4642 *str_ptr++ = '\0'; /* terminate leveldir string */
4643 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
4648 #if defined(TARGET_SDL)
4649 else if (strEqual(command, "SDL_ListModes"))
4654 SDL_Init(SDL_INIT_VIDEO);
4656 /* get available fullscreen/hardware modes */
4657 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
4659 /* check if there are any modes available */
4662 printf("No modes available!\n");
4667 /* check if our resolution is restricted */
4668 if (modes == (SDL_Rect **)-1)
4670 printf("All resolutions available.\n");
4674 printf("Available Modes:\n");
4676 for(i = 0; modes[i]; i++)
4677 printf(" %d x %d\n", modes[i]->w, modes[i]->h);
4687 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4691 static void InitSetup()
4693 LoadSetup(); /* global setup info */
4695 /* set some options from setup file */
4697 if (setup.options.verbose)
4698 options.verbose = TRUE;
4701 static void InitGameInfo()
4703 game.restart_level = FALSE;
4706 static void InitPlayerInfo()
4710 /* choose default local player */
4711 local_player = &stored_player[0];
4713 for (i = 0; i < MAX_PLAYERS; i++)
4714 stored_player[i].connected = FALSE;
4716 local_player->connected = TRUE;
4719 static void InitArtworkInfo()
4724 static char *get_string_in_brackets(char *string)
4726 char *string_in_brackets = checked_malloc(strlen(string) + 3);
4728 sprintf(string_in_brackets, "[%s]", string);
4730 return string_in_brackets;
4733 static char *get_level_id_suffix(int id_nr)
4735 char *id_suffix = checked_malloc(1 + 3 + 1);
4737 if (id_nr < 0 || id_nr > 999)
4740 sprintf(id_suffix, ".%03d", id_nr);
4746 static char *get_element_class_token(int element)
4748 char *element_class_name = element_info[element].class_name;
4749 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
4751 sprintf(element_class_token, "[%s]", element_class_name);
4753 return element_class_token;
4756 static char *get_action_class_token(int action)
4758 char *action_class_name = &element_action_info[action].suffix[1];
4759 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
4761 sprintf(action_class_token, "[%s]", action_class_name);
4763 return action_class_token;
4767 static void InitArtworkConfig()
4769 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
4770 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
4771 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
4772 static char *action_id_suffix[NUM_ACTIONS + 1];
4773 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
4774 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
4775 static char *level_id_suffix[MAX_LEVELS + 1];
4776 static char *dummy[1] = { NULL };
4777 static char *ignore_generic_tokens[] =
4783 static char **ignore_image_tokens;
4784 static char **ignore_sound_tokens;
4785 static char **ignore_music_tokens;
4786 int num_ignore_generic_tokens;
4787 int num_ignore_image_tokens;
4788 int num_ignore_sound_tokens;
4789 int num_ignore_music_tokens;
4792 /* dynamically determine list of generic tokens to be ignored */
4793 num_ignore_generic_tokens = 0;
4794 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
4795 num_ignore_generic_tokens++;
4797 /* dynamically determine list of image tokens to be ignored */
4798 num_ignore_image_tokens = num_ignore_generic_tokens;
4799 for (i = 0; image_config_vars[i].token != NULL; i++)
4800 num_ignore_image_tokens++;
4801 ignore_image_tokens =
4802 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
4803 for (i = 0; i < num_ignore_generic_tokens; i++)
4804 ignore_image_tokens[i] = ignore_generic_tokens[i];
4805 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
4806 ignore_image_tokens[num_ignore_generic_tokens + i] =
4807 image_config_vars[i].token;
4808 ignore_image_tokens[num_ignore_image_tokens] = NULL;
4810 /* dynamically determine list of sound tokens to be ignored */
4811 num_ignore_sound_tokens = num_ignore_generic_tokens;
4812 ignore_sound_tokens =
4813 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
4814 for (i = 0; i < num_ignore_generic_tokens; i++)
4815 ignore_sound_tokens[i] = ignore_generic_tokens[i];
4816 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
4818 /* dynamically determine list of music tokens to be ignored */
4819 num_ignore_music_tokens = num_ignore_generic_tokens;
4820 ignore_music_tokens =
4821 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
4822 for (i = 0; i < num_ignore_generic_tokens; i++)
4823 ignore_music_tokens[i] = ignore_generic_tokens[i];
4824 ignore_music_tokens[num_ignore_music_tokens] = NULL;
4826 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4827 image_id_prefix[i] = element_info[i].token_name;
4828 for (i = 0; i < NUM_FONTS; i++)
4829 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
4830 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
4832 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4833 sound_id_prefix[i] = element_info[i].token_name;
4834 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4835 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
4836 get_string_in_brackets(element_info[i].class_name);
4837 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
4839 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
4840 music_id_prefix[i] = music_prefix_info[i].prefix;
4841 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
4843 for (i = 0; i < NUM_ACTIONS; i++)
4844 action_id_suffix[i] = element_action_info[i].suffix;
4845 action_id_suffix[NUM_ACTIONS] = NULL;
4847 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
4848 direction_id_suffix[i] = element_direction_info[i].suffix;
4849 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
4851 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
4852 special_id_suffix[i] = special_suffix_info[i].suffix;
4853 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
4855 for (i = 0; i < MAX_LEVELS; i++)
4856 level_id_suffix[i] = get_level_id_suffix(i);
4857 level_id_suffix[MAX_LEVELS] = NULL;
4859 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
4860 image_id_prefix, action_id_suffix, direction_id_suffix,
4861 special_id_suffix, ignore_image_tokens);
4862 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
4863 sound_id_prefix, action_id_suffix, dummy,
4864 special_id_suffix, ignore_sound_tokens);
4865 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
4866 music_id_prefix, special_id_suffix, level_id_suffix,
4867 dummy, ignore_music_tokens);
4870 static void InitMixer()
4878 char *filename_font_initial = NULL;
4879 Bitmap *bitmap_font_initial = NULL;
4883 /* determine settings for initial font (for displaying startup messages) */
4884 for (i = 0; image_config[i].token != NULL; i++)
4886 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4888 char font_token[128];
4891 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
4892 len_font_token = strlen(font_token);
4894 if (strEqual(image_config[i].token, font_token))
4895 filename_font_initial = image_config[i].value;
4896 else if (strlen(image_config[i].token) > len_font_token &&
4897 strncmp(image_config[i].token, font_token, len_font_token) == 0)
4899 if (strEqual(&image_config[i].token[len_font_token], ".x"))
4900 font_initial[j].src_x = atoi(image_config[i].value);
4901 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
4902 font_initial[j].src_y = atoi(image_config[i].value);
4903 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
4904 font_initial[j].width = atoi(image_config[i].value);
4905 else if (strEqual(&image_config[i].token[len_font_token],".height"))
4906 font_initial[j].height = atoi(image_config[i].value);
4911 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4913 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
4914 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
4917 if (filename_font_initial == NULL) /* should not happen */
4918 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
4920 /* create additional image buffers for double-buffering and cross-fading */
4921 bitmap_db_cross = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
4922 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
4923 bitmap_db_panel = CreateBitmap(DXSIZE, DYSIZE, DEFAULT_DEPTH);
4924 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
4926 /* initialize screen properties */
4927 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
4928 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
4930 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
4931 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
4932 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
4934 bitmap_font_initial = LoadCustomImage(filename_font_initial);
4936 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4937 font_initial[j].bitmap = bitmap_font_initial;
4939 InitFontGraphicInfo();
4941 font_height = getFontHeight(FC_RED);
4944 DrawInitText(getWindowTitleString(), 20, FC_YELLOW);
4946 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
4948 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
4949 DrawInitText(PROGRAM_WEBSITE_STRING, WIN_YSIZE - 20 - font_height, FC_RED);
4951 DrawInitText("Loading graphics", 120, FC_GREEN);
4954 void RedrawBackground()
4956 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
4957 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
4959 redraw_mask = REDRAW_ALL;
4962 void InitGfxBackground()
4966 fieldbuffer = bitmap_db_field;
4967 SetDrawtoField(DRAW_BACKBUFFER);
4970 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
4974 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
4975 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
4978 for (x = 0; x < MAX_BUF_XSIZE; x++)
4979 for (y = 0; y < MAX_BUF_YSIZE; y++)
4982 redraw_mask = REDRAW_ALL;
4985 static void InitLevelInfo()
4987 LoadLevelInfo(); /* global level info */
4988 LoadLevelSetup_LastSeries(); /* last played series info */
4989 LoadLevelSetup_SeriesInfo(); /* last played level info */
4992 void InitLevelArtworkInfo()
4994 LoadLevelArtworkInfo();
4997 static void InitImages()
4999 setLevelArtworkDir(artwork.gfx_first);
5002 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5003 leveldir_current->identifier,
5004 artwork.gfx_current_identifier,
5005 artwork.gfx_current->identifier,
5006 leveldir_current->graphics_set,
5007 leveldir_current->graphics_path);
5010 ReloadCustomImages();
5012 LoadCustomElementDescriptions();
5013 LoadSpecialMenuDesignSettings();
5015 ReinitializeGraphics();
5018 static void InitSound(char *identifier)
5020 if (identifier == NULL)
5021 identifier = artwork.snd_current->identifier;
5023 /* set artwork path to send it to the sound server process */
5024 setLevelArtworkDir(artwork.snd_first);
5026 InitReloadCustomSounds(identifier);
5027 ReinitializeSounds();
5030 static void InitMusic(char *identifier)
5032 if (identifier == NULL)
5033 identifier = artwork.mus_current->identifier;
5035 /* set artwork path to send it to the sound server process */
5036 setLevelArtworkDir(artwork.mus_first);
5038 InitReloadCustomMusic(identifier);
5039 ReinitializeMusic();
5042 void InitNetworkServer()
5044 #if defined(NETWORK_AVALIABLE)
5048 if (!options.network)
5051 #if defined(NETWORK_AVALIABLE)
5052 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5054 if (!ConnectToServer(options.server_host, options.server_port))
5055 Error(ERR_EXIT, "cannot connect to network game server");
5057 SendToServer_PlayerName(setup.player_name);
5058 SendToServer_ProtocolVersion();
5061 SendToServer_NrWanted(nr_wanted);
5065 static char *getNewArtworkIdentifier(int type)
5067 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5068 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5069 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5070 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5071 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5072 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
5073 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5074 char *leveldir_identifier = leveldir_current->identifier;
5076 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
5077 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5079 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
5081 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5082 char *artwork_current_identifier;
5083 char *artwork_new_identifier = NULL; /* default: nothing has changed */
5085 /* leveldir_current may be invalid (level group, parent link) */
5086 if (!validLevelSeries(leveldir_current))
5089 /* 1st step: determine artwork set to be activated in descending order:
5090 --------------------------------------------------------------------
5091 1. setup artwork (when configured to override everything else)
5092 2. artwork set configured in "levelinfo.conf" of current level set
5093 (artwork in level directory will have priority when loading later)
5094 3. artwork in level directory (stored in artwork sub-directory)
5095 4. setup artwork (currently configured in setup menu) */
5097 if (setup_override_artwork)
5098 artwork_current_identifier = setup_artwork_set;
5099 else if (leveldir_artwork_set != NULL)
5100 artwork_current_identifier = leveldir_artwork_set;
5101 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5102 artwork_current_identifier = leveldir_identifier;
5104 artwork_current_identifier = setup_artwork_set;
5107 /* 2nd step: check if it is really needed to reload artwork set
5108 ------------------------------------------------------------ */
5111 if (type == ARTWORK_TYPE_GRAPHICS)
5112 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
5113 artwork_new_identifier,
5114 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5115 artwork_current_identifier,
5116 leveldir_current->graphics_set,
5117 leveldir_current->identifier);
5120 /* ---------- reload if level set and also artwork set has changed ------- */
5121 if (leveldir_current_identifier[type] != leveldir_identifier &&
5122 (last_has_level_artwork_set[type] || has_level_artwork_set))
5123 artwork_new_identifier = artwork_current_identifier;
5125 leveldir_current_identifier[type] = leveldir_identifier;
5126 last_has_level_artwork_set[type] = has_level_artwork_set;
5129 if (type == ARTWORK_TYPE_GRAPHICS)
5130 printf("::: 1: '%s'\n", artwork_new_identifier);
5133 /* ---------- reload if "override artwork" setting has changed ----------- */
5134 if (last_override_level_artwork[type] != setup_override_artwork)
5135 artwork_new_identifier = artwork_current_identifier;
5137 last_override_level_artwork[type] = setup_override_artwork;
5140 if (type == ARTWORK_TYPE_GRAPHICS)
5141 printf("::: 2: '%s'\n", artwork_new_identifier);
5144 /* ---------- reload if current artwork identifier has changed ----------- */
5145 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5146 artwork_current_identifier))
5147 artwork_new_identifier = artwork_current_identifier;
5149 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5152 if (type == ARTWORK_TYPE_GRAPHICS)
5153 printf("::: 3: '%s'\n", artwork_new_identifier);
5156 /* ---------- do not reload directly after starting ---------------------- */
5157 if (!initialized[type])
5158 artwork_new_identifier = NULL;
5160 initialized[type] = TRUE;
5163 if (type == ARTWORK_TYPE_GRAPHICS)
5164 printf("::: 4: '%s'\n", artwork_new_identifier);
5168 if (type == ARTWORK_TYPE_GRAPHICS)
5169 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
5170 artwork.gfx_current_identifier, artwork_current_identifier,
5171 artwork.gfx_current->identifier, leveldir_current->graphics_set,
5172 artwork_new_identifier);
5175 return artwork_new_identifier;
5178 void ReloadCustomArtwork(int force_reload)
5180 char *gfx_new_identifier;
5181 char *snd_new_identifier;
5182 char *mus_new_identifier;
5183 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5184 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5185 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5186 boolean redraw_screen = FALSE;
5188 force_reload_gfx |= AdjustGraphicsForEMC();
5190 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5191 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5192 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5194 if (gfx_new_identifier != NULL || force_reload_gfx)
5197 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5198 artwork.gfx_current_identifier,
5200 artwork.gfx_current->identifier,
5201 leveldir_current->graphics_set);
5204 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
5208 redraw_screen = TRUE;
5211 if (snd_new_identifier != NULL || force_reload_snd)
5213 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
5215 InitSound(snd_new_identifier);
5217 redraw_screen = TRUE;
5220 if (mus_new_identifier != NULL || force_reload_mus)
5222 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
5224 InitMusic(mus_new_identifier);
5226 redraw_screen = TRUE;
5233 /* force redraw of (open or closed) door graphics */
5234 SetDoorState(DOOR_OPEN_ALL);
5235 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5239 FadeSetEnterScreen();
5240 // FadeSkipNextFadeOut();
5241 // FadeSetDisabled();
5246 fading = fading_none;
5251 void KeyboardAutoRepeatOffUnlessAutoplay()
5253 if (global.autoplay_leveldir == NULL)
5254 KeyboardAutoRepeatOff();
5258 /* ========================================================================= */
5260 /* ========================================================================= */
5264 InitGlobal(); /* initialize some global variables */
5266 if (options.execute_command)
5267 Execute_Command(options.execute_command);
5269 if (options.serveronly)
5271 #if defined(PLATFORM_UNIX)
5272 NetworkServer(options.server_port, options.serveronly);
5274 Error(ERR_WARN, "networking only supported in Unix version");
5277 exit(0); /* never reached, server loops forever */
5284 InitArtworkInfo(); /* needed before loading gfx, sound & music */
5285 InitArtworkConfig(); /* needed before forking sound child process */
5290 InitRND(NEW_RANDOMIZE);
5291 InitSimpleRandom(NEW_RANDOMIZE);
5296 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
5298 InitEventFilter(FilterMouseMotionEvents);
5300 InitElementPropertiesStatic();
5301 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5305 // debug_print_timestamp(0, "INIT");
5307 // debug_print_timestamp(0, "TIME InitLevelInfo: ");
5308 InitLevelArtworkInfo();
5309 // debug_print_timestamp(0, "TIME InitLevelArtworkInfo: ");
5311 InitImages(); /* needs to know current level directory */
5312 InitSound(NULL); /* needs to know current level directory */
5313 InitMusic(NULL); /* needs to know current level directory */
5315 InitGfxBackground();
5321 if (global.autoplay_leveldir)
5326 else if (global.convert_leveldir)
5332 game_status = GAME_MODE_MAIN;
5335 FadeSetEnterScreen();
5336 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
5337 FadeSkipNextFadeOut();
5338 // FadeSetDisabled();
5340 fading = fading_none;
5345 InitNetworkServer();
5348 void CloseAllAndExit(int exit_value)
5353 CloseAudio(); /* called after freeing sounds (needed for SDL) */
5361 #if defined(TARGET_SDL)
5362 if (network_server) /* terminate network server */
5363 SDL_KillThread(server_thread);
5366 CloseVideoDisplay();
5367 ClosePlatformDependentStuff();
5369 if (exit_value != 0)
5370 NotifyUserAboutErrorFile();