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)
115 CreateImageWithSmallImages(graphic, graphic_info[graphic].scale_up_factor);
118 void InitElementSmallImages()
120 static int special_graphics[] =
122 IMG_EDITOR_ELEMENT_BORDER,
123 IMG_EDITOR_ELEMENT_BORDER_INPUT,
124 IMG_EDITOR_CASCADE_LIST,
125 IMG_EDITOR_CASCADE_LIST_ACTIVE,
128 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
129 int num_property_mappings = getImageListPropertyMappingSize();
132 /* initialize normal images from static configuration */
133 for (i = 0; element_to_graphic[i].element > -1; i++)
134 InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
136 /* initialize special images from static configuration */
137 for (i = 0; element_to_special_graphic[i].element > -1; i++)
138 InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
140 /* initialize images from dynamic configuration (may be elements or other) */
141 for (i = 0; i < num_property_mappings; i++)
142 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
144 /* initialize special images from above list (non-element images) */
145 for (i = 0; special_graphics[i] > -1; i++)
146 InitElementSmallImagesScaledUp(special_graphics[i]);
149 void InitScaledImages()
153 /* scale normal images from static configuration, if not already scaled */
154 for (i = 0; i < NUM_IMAGE_FILES; i++)
155 ScaleImage(i, graphic_info[i].scale_up_factor);
159 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
160 void SetBitmaps_EM(Bitmap **em_bitmap)
162 em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
163 em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].bitmap;
167 static int getFontBitmapID(int font_nr)
171 if (game_status >= GAME_MODE_TITLE_INITIAL &&
172 game_status <= GAME_MODE_PSEUDO_PREVIEW)
173 special = game_status;
174 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
175 special = GFX_SPECIAL_ARG_MAIN;
177 else if (game_status == GAME_MODE_PLAYING)
178 special = GFX_SPECIAL_ARG_DOOR;
182 return font_info[font_nr].special_bitmap_id[special];
187 static int getFontFromToken(char *token)
191 /* !!! OPTIMIZE THIS BY USING HASH !!! */
192 for (i = 0; i < NUM_FONTS; i++)
193 if (strEqual(token, font_info[i].token_name))
196 /* if font not found, use reliable default value */
197 return FONT_INITIAL_1;
200 void InitFontGraphicInfo()
202 static struct FontBitmapInfo *font_bitmap_info = NULL;
203 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
204 int num_property_mappings = getImageListPropertyMappingSize();
205 int num_font_bitmaps = NUM_FONTS;
208 if (graphic_info == NULL) /* still at startup phase */
210 InitFontInfo(font_initial, NUM_INITIAL_FONTS,
211 getFontBitmapID, getFontFromToken);
216 /* ---------- initialize font graphic definitions ---------- */
218 /* always start with reliable default values (normal font graphics) */
219 for (i = 0; i < NUM_FONTS; i++)
220 font_info[i].graphic = IMG_FONT_INITIAL_1;
222 /* initialize normal font/graphic mapping from static configuration */
223 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
225 int font_nr = font_to_graphic[i].font_nr;
226 int special = font_to_graphic[i].special;
227 int graphic = font_to_graphic[i].graphic;
232 font_info[font_nr].graphic = graphic;
235 /* always start with reliable default values (special font graphics) */
236 for (i = 0; i < NUM_FONTS; i++)
238 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
240 font_info[i].special_graphic[j] = font_info[i].graphic;
241 font_info[i].special_bitmap_id[j] = i;
245 /* initialize special font/graphic mapping from static configuration */
246 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
248 int font_nr = font_to_graphic[i].font_nr;
249 int special = font_to_graphic[i].special;
250 int graphic = font_to_graphic[i].graphic;
251 int base_graphic = font2baseimg(font_nr);
253 if (IS_SPECIAL_GFX_ARG(special))
255 boolean base_redefined =
256 getImageListEntryFromImageID(base_graphic)->redefined;
257 boolean special_redefined =
258 getImageListEntryFromImageID(graphic)->redefined;
259 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
261 /* if the base font ("font.title_1", for example) has been redefined,
262 but not the special font ("font.title_1.LEVELS", for example), do not
263 use an existing (in this case considered obsolete) special font
264 anymore, but use the automatically determined default font */
265 /* special case: cloned special fonts must be explicitly redefined,
266 but are not automatically redefined by redefining base font */
267 if (base_redefined && !special_redefined && !special_cloned)
270 font_info[font_nr].special_graphic[special] = graphic;
271 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
276 /* initialize special font/graphic mapping from dynamic configuration */
277 for (i = 0; i < num_property_mappings; i++)
279 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
280 int special = property_mapping[i].ext3_index;
281 int graphic = property_mapping[i].artwork_index;
286 if (IS_SPECIAL_GFX_ARG(special))
288 font_info[font_nr].special_graphic[special] = graphic;
289 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
294 /* correct special font/graphic mapping for cloned fonts for downwards
295 compatibility of PREVIEW fonts -- this is only needed for implicit
296 redefinition of special font by redefined base font, and only if other
297 fonts are cloned from this special font (like in the "Zelda" level set) */
298 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
300 int font_nr = font_to_graphic[i].font_nr;
301 int special = font_to_graphic[i].special;
302 int graphic = font_to_graphic[i].graphic;
304 if (IS_SPECIAL_GFX_ARG(special))
306 boolean special_redefined =
307 getImageListEntryFromImageID(graphic)->redefined;
308 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
310 if (special_cloned && !special_redefined)
314 for (j = 0; font_to_graphic[j].font_nr > -1; j++)
316 int font_nr2 = font_to_graphic[j].font_nr;
317 int special2 = font_to_graphic[j].special;
318 int graphic2 = font_to_graphic[j].graphic;
320 if (IS_SPECIAL_GFX_ARG(special2) &&
321 graphic2 == graphic_info[graphic].clone_from)
323 font_info[font_nr].special_graphic[special] =
324 font_info[font_nr2].special_graphic[special2];
325 font_info[font_nr].special_bitmap_id[special] =
326 font_info[font_nr2].special_bitmap_id[special2];
333 /* reset non-redefined ".active" font graphics if normal font is redefined */
334 /* (this different treatment is needed because normal and active fonts are
335 independently defined ("active" is not a property of font definitions!) */
336 for (i = 0; i < NUM_FONTS; i++)
338 int font_nr_base = i;
339 int font_nr_active = FONT_ACTIVE(font_nr_base);
341 /* check only those fonts with exist as normal and ".active" variant */
342 if (font_nr_base != font_nr_active)
344 int base_graphic = font_info[font_nr_base].graphic;
345 int active_graphic = font_info[font_nr_active].graphic;
346 boolean base_redefined =
347 getImageListEntryFromImageID(base_graphic)->redefined;
348 boolean active_redefined =
349 getImageListEntryFromImageID(active_graphic)->redefined;
351 /* if the base font ("font.menu_1", for example) has been redefined,
352 but not the active font ("font.menu_1.active", for example), do not
353 use an existing (in this case considered obsolete) active font
354 anymore, but use the automatically determined default font */
355 if (base_redefined && !active_redefined)
356 font_info[font_nr_active].graphic = base_graphic;
358 /* now also check each "special" font (which may be the same as above) */
359 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
361 int base_graphic = font_info[font_nr_base].special_graphic[j];
362 int active_graphic = font_info[font_nr_active].special_graphic[j];
363 boolean base_redefined =
364 getImageListEntryFromImageID(base_graphic)->redefined;
365 boolean active_redefined =
366 getImageListEntryFromImageID(active_graphic)->redefined;
368 /* same as above, but check special graphic definitions, for example:
369 redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN" */
370 if (base_redefined && !active_redefined)
372 font_info[font_nr_active].special_graphic[j] =
373 font_info[font_nr_base].special_graphic[j];
374 font_info[font_nr_active].special_bitmap_id[j] =
375 font_info[font_nr_base].special_bitmap_id[j];
381 /* ---------- initialize font bitmap array ---------- */
383 if (font_bitmap_info != NULL)
384 FreeFontInfo(font_bitmap_info);
387 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
389 /* ---------- initialize font bitmap definitions ---------- */
391 for (i = 0; i < NUM_FONTS; i++)
393 if (i < NUM_INITIAL_FONTS)
395 font_bitmap_info[i] = font_initial[i];
399 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
401 int font_bitmap_id = font_info[i].special_bitmap_id[j];
402 int graphic = font_info[i].special_graphic[j];
404 /* set 'graphic_info' for font entries, if uninitialized (guessed) */
405 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
407 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
408 graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
411 /* copy font relevant information from graphics information */
412 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
413 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
414 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
415 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
416 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
418 font_bitmap_info[font_bitmap_id].draw_xoffset =
419 graphic_info[graphic].draw_xoffset;
420 font_bitmap_info[font_bitmap_id].draw_yoffset =
421 graphic_info[graphic].draw_yoffset;
423 font_bitmap_info[font_bitmap_id].num_chars =
424 graphic_info[graphic].anim_frames;
425 font_bitmap_info[font_bitmap_id].num_chars_per_line =
426 graphic_info[graphic].anim_frames_per_line;
430 InitFontInfo(font_bitmap_info, num_font_bitmaps,
431 getFontBitmapID, getFontFromToken);
434 void InitElementGraphicInfo()
436 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
437 int num_property_mappings = getImageListPropertyMappingSize();
440 if (graphic_info == NULL) /* still at startup phase */
443 /* set values to -1 to identify later as "uninitialized" values */
444 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
446 for (act = 0; act < NUM_ACTIONS; act++)
448 element_info[i].graphic[act] = -1;
449 element_info[i].crumbled[act] = -1;
451 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
453 element_info[i].direction_graphic[act][dir] = -1;
454 element_info[i].direction_crumbled[act][dir] = -1;
459 /* initialize normal element/graphic mapping from static configuration */
460 for (i = 0; element_to_graphic[i].element > -1; i++)
462 int element = element_to_graphic[i].element;
463 int action = element_to_graphic[i].action;
464 int direction = element_to_graphic[i].direction;
465 boolean crumbled = element_to_graphic[i].crumbled;
466 int graphic = element_to_graphic[i].graphic;
467 int base_graphic = el2baseimg(element);
469 if (graphic_info[graphic].bitmap == NULL)
472 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
475 boolean base_redefined =
476 getImageListEntryFromImageID(base_graphic)->redefined;
477 boolean act_dir_redefined =
478 getImageListEntryFromImageID(graphic)->redefined;
480 /* if the base graphic ("emerald", for example) has been redefined,
481 but not the action graphic ("emerald.falling", for example), do not
482 use an existing (in this case considered obsolete) action graphic
483 anymore, but use the automatically determined default graphic */
484 if (base_redefined && !act_dir_redefined)
489 action = ACTION_DEFAULT;
494 element_info[element].direction_crumbled[action][direction] = graphic;
496 element_info[element].crumbled[action] = graphic;
501 element_info[element].direction_graphic[action][direction] = graphic;
503 element_info[element].graphic[action] = graphic;
507 /* initialize normal element/graphic mapping from dynamic configuration */
508 for (i = 0; i < num_property_mappings; i++)
510 int element = property_mapping[i].base_index;
511 int action = property_mapping[i].ext1_index;
512 int direction = property_mapping[i].ext2_index;
513 int special = property_mapping[i].ext3_index;
514 int graphic = property_mapping[i].artwork_index;
515 boolean crumbled = FALSE;
518 if ((element == EL_EM_DYNAMITE ||
519 element == EL_EM_DYNAMITE_ACTIVE) &&
520 action == ACTION_ACTIVE &&
521 (special == GFX_SPECIAL_ARG_EDITOR ||
522 special == GFX_SPECIAL_ARG_PANEL))
523 printf("::: DYNAMIC: %d, %d, %d -> %d\n",
524 element, action, special, graphic);
527 if (special == GFX_SPECIAL_ARG_CRUMBLED)
533 if (graphic_info[graphic].bitmap == NULL)
536 if (element >= MAX_NUM_ELEMENTS || special != -1)
540 action = ACTION_DEFAULT;
545 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
546 element_info[element].direction_crumbled[action][dir] = -1;
549 element_info[element].direction_crumbled[action][direction] = graphic;
551 element_info[element].crumbled[action] = graphic;
556 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
557 element_info[element].direction_graphic[action][dir] = -1;
560 element_info[element].direction_graphic[action][direction] = graphic;
562 element_info[element].graphic[action] = graphic;
566 /* now copy all graphics that are defined to be cloned from other graphics */
567 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
569 int graphic = element_info[i].graphic[ACTION_DEFAULT];
570 int crumbled_like, diggable_like;
575 crumbled_like = graphic_info[graphic].crumbled_like;
576 diggable_like = graphic_info[graphic].diggable_like;
578 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
580 for (act = 0; act < NUM_ACTIONS; act++)
581 element_info[i].crumbled[act] =
582 element_info[crumbled_like].crumbled[act];
583 for (act = 0; act < NUM_ACTIONS; act++)
584 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
585 element_info[i].direction_crumbled[act][dir] =
586 element_info[crumbled_like].direction_crumbled[act][dir];
589 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
591 element_info[i].graphic[ACTION_DIGGING] =
592 element_info[diggable_like].graphic[ACTION_DIGGING];
593 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
594 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
595 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
600 /* set hardcoded definitions for some runtime elements without graphic */
601 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
605 /* set hardcoded definitions for some internal elements without graphic */
606 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
608 if (IS_EDITOR_CASCADE_INACTIVE(i))
609 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
610 else if (IS_EDITOR_CASCADE_ACTIVE(i))
611 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
615 /* now set all undefined/invalid graphics to -1 to set to default after it */
616 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
618 for (act = 0; act < NUM_ACTIONS; act++)
622 graphic = element_info[i].graphic[act];
623 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
624 element_info[i].graphic[act] = -1;
626 graphic = element_info[i].crumbled[act];
627 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
628 element_info[i].crumbled[act] = -1;
630 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
632 graphic = element_info[i].direction_graphic[act][dir];
633 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
634 element_info[i].direction_graphic[act][dir] = -1;
636 graphic = element_info[i].direction_crumbled[act][dir];
637 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
638 element_info[i].direction_crumbled[act][dir] = -1;
643 /* adjust graphics with 2nd tile for movement according to direction
644 (do this before correcting '-1' values to minimize calculations) */
645 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
647 for (act = 0; act < NUM_ACTIONS; act++)
649 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
651 int graphic = element_info[i].direction_graphic[act][dir];
652 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
654 if (act == ACTION_FALLING) /* special case */
655 graphic = element_info[i].graphic[act];
658 graphic_info[graphic].double_movement &&
659 graphic_info[graphic].swap_double_tiles != 0)
661 struct GraphicInfo *g = &graphic_info[graphic];
662 int src_x_front = g->src_x;
663 int src_y_front = g->src_y;
664 int src_x_back = g->src_x + g->offset2_x;
665 int src_y_back = g->src_y + g->offset2_y;
666 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
668 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
669 src_y_front < src_y_back);
670 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
671 boolean swap_movement_tiles_autodetected =
672 (!frames_are_ordered_diagonally &&
673 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
674 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
675 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
676 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
679 /* swap frontside and backside graphic tile coordinates, if needed */
680 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
682 /* get current (wrong) backside tile coordinates */
683 getGraphicSourceExt(graphic, 0, &dummy, &src_x_back, &src_y_back,
686 /* set frontside tile coordinates to backside tile coordinates */
687 g->src_x = src_x_back;
688 g->src_y = src_y_back;
690 /* invert tile offset to point to new backside tile coordinates */
694 /* do not swap front and backside tiles again after correction */
695 g->swap_double_tiles = 0;
702 /* now set all '-1' values to element specific default values */
703 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
705 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
706 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
707 int default_direction_graphic[NUM_DIRECTIONS_FULL];
708 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
710 if (default_graphic == -1)
711 default_graphic = IMG_UNKNOWN;
713 if (default_crumbled == -1)
714 default_crumbled = default_graphic;
716 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
717 if (default_crumbled == -1)
718 default_crumbled = IMG_EMPTY;
721 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
723 default_direction_graphic[dir] =
724 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
725 default_direction_crumbled[dir] =
726 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
728 if (default_direction_graphic[dir] == -1)
729 default_direction_graphic[dir] = default_graphic;
731 if (default_direction_crumbled[dir] == -1)
732 default_direction_crumbled[dir] = default_direction_graphic[dir];
734 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
735 if (default_direction_crumbled[dir] == -1)
736 default_direction_crumbled[dir] = default_crumbled;
740 for (act = 0; act < NUM_ACTIONS; act++)
742 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
743 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
744 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
745 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
746 act == ACTION_TURNING_FROM_RIGHT ||
747 act == ACTION_TURNING_FROM_UP ||
748 act == ACTION_TURNING_FROM_DOWN);
750 /* generic default action graphic (defined by "[default]" directive) */
751 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
752 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
753 int default_remove_graphic = IMG_EMPTY;
755 if (act_remove && default_action_graphic != -1)
756 default_remove_graphic = default_action_graphic;
758 /* look for special default action graphic (classic game specific) */
759 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
760 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
761 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
762 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
763 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
764 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
766 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
767 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
768 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
769 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
770 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
771 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
774 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
775 /* !!! make this better !!! */
776 if (i == EL_EMPTY_SPACE)
778 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
779 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
783 if (default_action_graphic == -1)
784 default_action_graphic = default_graphic;
786 if (default_action_crumbled == -1)
787 default_action_crumbled = default_action_graphic;
789 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
790 if (default_action_crumbled == -1)
791 default_action_crumbled = default_crumbled;
794 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
796 /* use action graphic as the default direction graphic, if undefined */
797 int default_action_direction_graphic = element_info[i].graphic[act];
798 int default_action_direction_crumbled = element_info[i].crumbled[act];
800 /* no graphic for current action -- use default direction graphic */
801 if (default_action_direction_graphic == -1)
802 default_action_direction_graphic =
803 (act_remove ? default_remove_graphic :
805 element_info[i].direction_graphic[ACTION_TURNING][dir] :
806 default_action_graphic != default_graphic ?
807 default_action_graphic :
808 default_direction_graphic[dir]);
810 if (element_info[i].direction_graphic[act][dir] == -1)
811 element_info[i].direction_graphic[act][dir] =
812 default_action_direction_graphic;
815 if (default_action_direction_crumbled == -1)
816 default_action_direction_crumbled =
817 element_info[i].direction_graphic[act][dir];
819 if (default_action_direction_crumbled == -1)
820 default_action_direction_crumbled =
821 (act_remove ? default_remove_graphic :
823 element_info[i].direction_crumbled[ACTION_TURNING][dir] :
824 default_action_crumbled != default_crumbled ?
825 default_action_crumbled :
826 default_direction_crumbled[dir]);
829 if (element_info[i].direction_crumbled[act][dir] == -1)
830 element_info[i].direction_crumbled[act][dir] =
831 default_action_direction_crumbled;
834 /* no graphic for this specific action -- use default action graphic */
835 if (element_info[i].graphic[act] == -1)
836 element_info[i].graphic[act] =
837 (act_remove ? default_remove_graphic :
838 act_turning ? element_info[i].graphic[ACTION_TURNING] :
839 default_action_graphic);
841 if (element_info[i].crumbled[act] == -1)
842 element_info[i].crumbled[act] = element_info[i].graphic[act];
844 if (element_info[i].crumbled[act] == -1)
845 element_info[i].crumbled[act] =
846 (act_remove ? default_remove_graphic :
847 act_turning ? element_info[i].crumbled[ACTION_TURNING] :
848 default_action_crumbled);
854 /* !!! THIS ALSO CLEARS SPECIAL FLAGS (AND IS NOT NEEDED ANYWAY) !!! */
855 /* set animation mode to "none" for each graphic with only 1 frame */
856 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
858 for (act = 0; act < NUM_ACTIONS; act++)
860 int graphic = element_info[i].graphic[act];
861 int crumbled = element_info[i].crumbled[act];
863 if (graphic_info[graphic].anim_frames == 1)
864 graphic_info[graphic].anim_mode = ANIM_NONE;
865 if (graphic_info[crumbled].anim_frames == 1)
866 graphic_info[crumbled].anim_mode = ANIM_NONE;
868 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
870 graphic = element_info[i].direction_graphic[act][dir];
871 crumbled = element_info[i].direction_crumbled[act][dir];
873 if (graphic_info[graphic].anim_frames == 1)
874 graphic_info[graphic].anim_mode = ANIM_NONE;
875 if (graphic_info[crumbled].anim_frames == 1)
876 graphic_info[crumbled].anim_mode = ANIM_NONE;
886 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
887 if (element_info[i].graphic[ACTION_DEFAULT] == IMG_UNKNOWN &&
889 Error(ERR_INFO, "warning: no graphic for element '%s' (%d)",
890 element_info[i].token_name, i);
896 void InitElementSpecialGraphicInfo()
898 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
899 int num_property_mappings = getImageListPropertyMappingSize();
902 /* always start with reliable default values */
903 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
904 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
905 element_info[i].special_graphic[j] =
906 element_info[i].graphic[ACTION_DEFAULT];
908 /* initialize special element/graphic mapping from static configuration */
909 for (i = 0; element_to_special_graphic[i].element > -1; i++)
911 int element = element_to_special_graphic[i].element;
912 int special = element_to_special_graphic[i].special;
913 int graphic = element_to_special_graphic[i].graphic;
914 int base_graphic = el2baseimg(element);
915 boolean base_redefined =
916 getImageListEntryFromImageID(base_graphic)->redefined;
917 boolean special_redefined =
918 getImageListEntryFromImageID(graphic)->redefined;
921 if ((element == EL_EM_DYNAMITE ||
922 element == EL_EM_DYNAMITE_ACTIVE) &&
923 (special == GFX_SPECIAL_ARG_EDITOR ||
924 special == GFX_SPECIAL_ARG_PANEL))
925 printf("::: SPECIAL STATIC: %d, %d -> %d\n",
926 element, special, graphic);
929 /* if the base graphic ("emerald", for example) has been redefined,
930 but not the special graphic ("emerald.EDITOR", for example), do not
931 use an existing (in this case considered obsolete) special graphic
932 anymore, but use the automatically created (down-scaled) graphic */
933 if (base_redefined && !special_redefined)
936 element_info[element].special_graphic[special] = graphic;
939 /* initialize special element/graphic mapping from dynamic configuration */
940 for (i = 0; i < num_property_mappings; i++)
942 int element = property_mapping[i].base_index;
943 int action = property_mapping[i].ext1_index;
944 int direction = property_mapping[i].ext2_index;
945 int special = property_mapping[i].ext3_index;
946 int graphic = property_mapping[i].artwork_index;
949 if ((element == EL_EM_DYNAMITE ||
950 element == EL_EM_DYNAMITE_ACTIVE ||
951 element == EL_CONVEYOR_BELT_1_MIDDLE ||
952 element == EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE) &&
953 (special == GFX_SPECIAL_ARG_EDITOR ||
954 special == GFX_SPECIAL_ARG_PANEL))
955 printf("::: SPECIAL DYNAMIC: %d, %d -> %d [%d]\n",
956 element, special, graphic, property_mapping[i].ext1_index);
960 if (element == EL_CONVEYOR_BELT_1_MIDDLE &&
961 action == ACTION_ACTIVE)
963 element = EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE;
969 if (element == EL_MAGIC_WALL &&
970 action == ACTION_ACTIVE)
972 element = EL_MAGIC_WALL_ACTIVE;
978 /* for action ".active", replace element with active element, if exists */
979 if (action == ACTION_ACTIVE && element != ELEMENT_ACTIVE(element))
981 element = ELEMENT_ACTIVE(element);
986 if (element >= MAX_NUM_ELEMENTS)
989 /* do not change special graphic if action or direction was specified */
990 if (action != -1 || direction != -1)
993 if (IS_SPECIAL_GFX_ARG(special))
994 element_info[element].special_graphic[special] = graphic;
997 /* now set all undefined/invalid graphics to default */
998 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
999 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1000 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
1001 element_info[i].special_graphic[j] =
1002 element_info[i].graphic[ACTION_DEFAULT];
1005 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
1010 if (type != TYPE_TOKEN)
1011 return get_parameter_value(value_raw, suffix, type);
1013 if (strEqual(value_raw, ARG_UNDEFINED))
1014 return ARG_UNDEFINED_VALUE;
1016 /* !!! OPTIMIZE THIS BY USING HASH !!! */
1017 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1018 if (strEqual(element_info[i].token_name, value_raw))
1021 /* !!! OPTIMIZE THIS BY USING HASH !!! */
1022 for (i = 0; image_config[i].token != NULL; i++)
1024 int len_config_value = strlen(image_config[i].value);
1026 if (!strEqual(&image_config[i].value[len_config_value - 4], ".pcx") &&
1027 !strEqual(&image_config[i].value[len_config_value - 4], ".wav") &&
1028 !strEqual(image_config[i].value, UNDEFINED_FILENAME))
1031 if (strEqual(image_config[i].token, value_raw))
1040 static int get_scaled_graphic_width(int graphic)
1042 int original_width = getOriginalImageWidthFromImageID(graphic);
1043 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1045 return original_width * scale_up_factor;
1048 static int get_scaled_graphic_height(int graphic)
1050 int original_height = getOriginalImageHeightFromImageID(graphic);
1051 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1053 return original_height * scale_up_factor;
1056 static void set_graphic_parameters(int graphic)
1058 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1059 char **parameter_raw = image->parameter;
1060 Bitmap *src_bitmap = getBitmapFromImageID(graphic);
1061 int parameter[NUM_GFX_ARGS];
1062 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1063 int anim_frames_per_line = 1;
1066 /* if fallback to default artwork is done, also use the default parameters */
1067 if (image->fallback_to_default)
1068 parameter_raw = image->default_parameter;
1070 /* get integer values from string parameters */
1071 for (i = 0; i < NUM_GFX_ARGS; i++)
1072 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1073 image_config_suffix[i].token,
1074 image_config_suffix[i].type);
1076 graphic_info[graphic].bitmap = src_bitmap;
1078 /* always start with reliable default values */
1079 graphic_info[graphic].src_image_width = 0;
1080 graphic_info[graphic].src_image_height = 0;
1081 graphic_info[graphic].src_x = 0;
1082 graphic_info[graphic].src_y = 0;
1083 graphic_info[graphic].width = TILEX; /* default for element graphics */
1084 graphic_info[graphic].height = TILEY; /* default for element graphics */
1085 graphic_info[graphic].offset_x = 0; /* one or both of these values ... */
1086 graphic_info[graphic].offset_y = 0; /* ... will be corrected later */
1087 graphic_info[graphic].offset2_x = 0; /* one or both of these values ... */
1088 graphic_info[graphic].offset2_y = 0; /* ... will be corrected later */
1089 graphic_info[graphic].swap_double_tiles = -1; /* auto-detect tile swapping */
1090 graphic_info[graphic].crumbled_like = -1; /* do not use clone element */
1091 graphic_info[graphic].diggable_like = -1; /* do not use clone element */
1092 graphic_info[graphic].border_size = TILEX / 8; /* "CRUMBLED" border size */
1093 graphic_info[graphic].scale_up_factor = 1; /* default: no scaling up */
1094 graphic_info[graphic].clone_from = -1; /* do not use clone graphic */
1095 graphic_info[graphic].anim_delay_fixed = 0;
1096 graphic_info[graphic].anim_delay_random = 0;
1097 graphic_info[graphic].post_delay_fixed = 0;
1098 graphic_info[graphic].post_delay_random = 0;
1099 graphic_info[graphic].fade_mode = FADE_MODE_DEFAULT;
1100 graphic_info[graphic].fade_delay = -1;
1101 graphic_info[graphic].post_delay = -1;
1102 graphic_info[graphic].auto_delay = -1;
1103 graphic_info[graphic].align = ALIGN_CENTER; /* default for title screens */
1104 graphic_info[graphic].valign = VALIGN_MIDDLE; /* default for title screens */
1105 graphic_info[graphic].sort_priority = 0; /* default for title screens */
1108 /* optional zoom factor for scaling up the image to a larger size */
1109 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1110 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1111 if (graphic_info[graphic].scale_up_factor < 1)
1112 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
1116 if (graphic_info[graphic].use_image_size)
1118 /* set new default bitmap size (with scaling, but without small images) */
1119 graphic_info[graphic].width = get_scaled_graphic_width(graphic);
1120 graphic_info[graphic].height = get_scaled_graphic_height(graphic);
1124 /* optional x and y tile position of animation frame sequence */
1125 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1126 graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
1127 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1128 graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
1130 /* optional x and y pixel position of animation frame sequence */
1131 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1132 graphic_info[graphic].src_x = parameter[GFX_ARG_X];
1133 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1134 graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
1136 /* optional width and height of each animation frame */
1137 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1138 graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
1139 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1140 graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
1143 /* optional zoom factor for scaling up the image to a larger size */
1144 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1145 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1146 if (graphic_info[graphic].scale_up_factor < 1)
1147 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
1152 /* get final bitmap size (with scaling, but without small images) */
1153 int src_image_width = get_scaled_graphic_width(graphic);
1154 int src_image_height = get_scaled_graphic_height(graphic);
1156 anim_frames_per_row = src_image_width / graphic_info[graphic].width;
1157 anim_frames_per_col = src_image_height / graphic_info[graphic].height;
1159 graphic_info[graphic].src_image_width = src_image_width;
1160 graphic_info[graphic].src_image_height = src_image_height;
1163 /* correct x or y offset dependent of vertical or horizontal frame order */
1164 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1166 graphic_info[graphic].offset_y =
1167 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1168 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
1169 anim_frames_per_line = anim_frames_per_col;
1171 else /* frames are ordered horizontally */
1173 graphic_info[graphic].offset_x =
1174 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1175 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
1176 anim_frames_per_line = anim_frames_per_row;
1179 /* optionally, the x and y offset of frames can be specified directly */
1180 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1181 graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
1182 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1183 graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
1185 /* optionally, moving animations may have separate start and end graphics */
1186 graphic_info[graphic].double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1188 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1189 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1191 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1192 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1193 graphic_info[graphic].offset2_y =
1194 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1195 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].height);
1196 else /* frames are ordered horizontally */
1197 graphic_info[graphic].offset2_x =
1198 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1199 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].width);
1201 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1202 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1203 graphic_info[graphic].offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1204 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1205 graphic_info[graphic].offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1207 /* optionally, the second movement tile can be specified as start tile */
1208 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1209 graphic_info[graphic].swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1211 /* automatically determine correct number of frames, if not defined */
1212 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1213 graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
1214 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1215 graphic_info[graphic].anim_frames = anim_frames_per_row;
1216 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1217 graphic_info[graphic].anim_frames = anim_frames_per_col;
1219 graphic_info[graphic].anim_frames = 1;
1221 if (graphic_info[graphic].anim_frames == 0) /* frames must be at least 1 */
1222 graphic_info[graphic].anim_frames = 1;
1224 graphic_info[graphic].anim_frames_per_line =
1225 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1226 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1228 graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
1229 if (graphic_info[graphic].anim_delay == 0) /* delay must be at least 1 */
1230 graphic_info[graphic].anim_delay = 1;
1232 graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
1234 if (graphic_info[graphic].anim_frames == 1)
1235 graphic_info[graphic].anim_mode = ANIM_NONE;
1238 /* automatically determine correct start frame, if not defined */
1239 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1240 graphic_info[graphic].anim_start_frame = 0;
1241 else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
1242 graphic_info[graphic].anim_start_frame =
1243 graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1245 graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
1247 /* animation synchronized with global frame counter, not move position */
1248 graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1250 /* optional element for cloning crumble graphics */
1251 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1252 graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1254 /* optional element for cloning digging graphics */
1255 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1256 graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1258 /* optional border size for "crumbling" diggable graphics */
1259 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1260 graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
1262 /* this is only used for player "boring" and "sleeping" actions */
1263 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1264 graphic_info[graphic].anim_delay_fixed =
1265 parameter[GFX_ARG_ANIM_DELAY_FIXED];
1266 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1267 graphic_info[graphic].anim_delay_random =
1268 parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1269 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1270 graphic_info[graphic].post_delay_fixed =
1271 parameter[GFX_ARG_POST_DELAY_FIXED];
1272 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1273 graphic_info[graphic].post_delay_random =
1274 parameter[GFX_ARG_POST_DELAY_RANDOM];
1276 /* this is only used for toon animations */
1277 graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
1278 graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY];
1280 /* this is only used for drawing font characters */
1281 graphic_info[graphic].draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1282 graphic_info[graphic].draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1284 /* this is only used for drawing envelope graphics */
1285 graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1287 /* optional graphic for cloning all graphics settings */
1288 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1289 graphic_info[graphic].clone_from = parameter[GFX_ARG_CLONE_FROM];
1291 /* optional settings for drawing title screens and title messages */
1292 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1293 graphic_info[graphic].fade_mode = parameter[GFX_ARG_FADE_MODE];
1294 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1295 graphic_info[graphic].fade_delay = parameter[GFX_ARG_FADE_DELAY];
1296 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1297 graphic_info[graphic].post_delay = parameter[GFX_ARG_POST_DELAY];
1298 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1299 graphic_info[graphic].auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1300 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1301 graphic_info[graphic].align = parameter[GFX_ARG_ALIGN];
1302 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1303 graphic_info[graphic].valign = parameter[GFX_ARG_VALIGN];
1304 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1305 graphic_info[graphic].sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1308 static void set_cloned_graphic_parameters(int graphic)
1310 int fallback_graphic = IMG_CHAR_EXCLAM;
1311 int max_num_images = getImageListSize();
1312 int clone_graphic = graphic_info[graphic].clone_from;
1313 int num_references_followed = 1;
1315 while (graphic_info[clone_graphic].clone_from != -1 &&
1316 num_references_followed < max_num_images)
1318 clone_graphic = graphic_info[clone_graphic].clone_from;
1320 num_references_followed++;
1323 if (num_references_followed >= max_num_images)
1325 Error(ERR_INFO_LINE, "-");
1326 Error(ERR_INFO, "warning: error found in config file:");
1327 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1328 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1329 Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1330 Error(ERR_INFO, "custom graphic rejected for this element/action");
1332 if (graphic == fallback_graphic)
1333 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1335 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1336 Error(ERR_INFO_LINE, "-");
1338 graphic_info[graphic] = graphic_info[fallback_graphic];
1342 graphic_info[graphic] = graphic_info[clone_graphic];
1343 graphic_info[graphic].clone_from = clone_graphic;
1347 static void InitGraphicInfo()
1349 int fallback_graphic = IMG_CHAR_EXCLAM;
1350 int num_images = getImageListSize();
1353 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1354 static boolean clipmasks_initialized = FALSE;
1356 XGCValues clip_gc_values;
1357 unsigned long clip_gc_valuemask;
1358 GC copy_clipmask_gc = None;
1361 /* use image size as default values for width and height for these images */
1362 static int full_size_graphics[] =
1367 IMG_BACKGROUND_ENVELOPE_1,
1368 IMG_BACKGROUND_ENVELOPE_2,
1369 IMG_BACKGROUND_ENVELOPE_3,
1370 IMG_BACKGROUND_ENVELOPE_4,
1373 IMG_BACKGROUND_TITLE_INITIAL,
1374 IMG_BACKGROUND_TITLE,
1375 IMG_BACKGROUND_MAIN,
1376 IMG_BACKGROUND_LEVELS,
1377 IMG_BACKGROUND_SCORES,
1378 IMG_BACKGROUND_EDITOR,
1379 IMG_BACKGROUND_INFO,
1380 IMG_BACKGROUND_INFO_ELEMENTS,
1381 IMG_BACKGROUND_INFO_MUSIC,
1382 IMG_BACKGROUND_INFO_CREDITS,
1383 IMG_BACKGROUND_INFO_PROGRAM,
1384 IMG_BACKGROUND_INFO_LEVELSET,
1385 IMG_BACKGROUND_SETUP,
1386 IMG_BACKGROUND_DOOR,
1388 IMG_TITLESCREEN_INITIAL_1,
1389 IMG_TITLESCREEN_INITIAL_2,
1390 IMG_TITLESCREEN_INITIAL_3,
1391 IMG_TITLESCREEN_INITIAL_4,
1392 IMG_TITLESCREEN_INITIAL_5,
1402 checked_free(graphic_info);
1404 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1407 /* initialize "use_image_size" flag with default value */
1408 for (i = 0; i < num_images; i++)
1409 graphic_info[i].use_image_size = FALSE;
1411 /* initialize "use_image_size" flag from static configuration above */
1412 for (i = 0; full_size_graphics[i] != -1; i++)
1413 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1416 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1417 if (clipmasks_initialized)
1419 for (i = 0; i < num_images; i++)
1421 if (graphic_info[i].clip_mask)
1422 XFreePixmap(display, graphic_info[i].clip_mask);
1423 if (graphic_info[i].clip_gc)
1424 XFreeGC(display, graphic_info[i].clip_gc);
1426 graphic_info[i].clip_mask = None;
1427 graphic_info[i].clip_gc = None;
1432 /* first set all graphic paramaters ... */
1433 for (i = 0; i < num_images; i++)
1434 set_graphic_parameters(i);
1436 /* ... then copy these parameters for cloned graphics */
1437 for (i = 0; i < num_images; i++)
1438 if (graphic_info[i].clone_from != -1)
1439 set_cloned_graphic_parameters(i);
1441 for (i = 0; i < num_images; i++)
1446 int first_frame, last_frame;
1447 int src_bitmap_width, src_bitmap_height;
1449 /* now check if no animation frames are outside of the loaded image */
1451 if (graphic_info[i].bitmap == NULL)
1452 continue; /* skip check for optional images that are undefined */
1454 /* get image size (this can differ from the standard element tile size!) */
1455 width = graphic_info[i].width;
1456 height = graphic_info[i].height;
1458 /* get final bitmap size (with scaling, but without small images) */
1459 src_bitmap_width = graphic_info[i].src_image_width;
1460 src_bitmap_height = graphic_info[i].src_image_height;
1462 /* check if first animation frame is inside specified bitmap */
1465 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1468 /* this avoids calculating wrong start position for out-of-bounds frame */
1469 src_x = graphic_info[i].src_x;
1470 src_y = graphic_info[i].src_y;
1473 if (src_x < 0 || src_y < 0 ||
1474 src_x + width > src_bitmap_width ||
1475 src_y + height > src_bitmap_height)
1477 Error(ERR_INFO_LINE, "-");
1478 Error(ERR_INFO, "warning: error found in config file:");
1479 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1480 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1481 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1483 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1484 src_x, src_y, src_bitmap_width, src_bitmap_height);
1485 Error(ERR_INFO, "custom graphic rejected for this element/action");
1487 if (i == fallback_graphic)
1488 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1490 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1491 Error(ERR_INFO_LINE, "-");
1493 graphic_info[i] = graphic_info[fallback_graphic];
1496 /* check if last animation frame is inside specified bitmap */
1498 last_frame = graphic_info[i].anim_frames - 1;
1499 getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1501 if (src_x < 0 || src_y < 0 ||
1502 src_x + width > src_bitmap_width ||
1503 src_y + height > src_bitmap_height)
1505 Error(ERR_INFO_LINE, "-");
1506 Error(ERR_INFO, "warning: error found in config file:");
1507 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1508 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1509 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1511 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1512 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1513 Error(ERR_INFO, "custom graphic rejected for this element/action");
1515 if (i == fallback_graphic)
1516 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1518 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1519 Error(ERR_INFO_LINE, "-");
1521 graphic_info[i] = graphic_info[fallback_graphic];
1524 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1525 /* currently we only need a tile clip mask from the first frame */
1526 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1528 if (copy_clipmask_gc == None)
1530 clip_gc_values.graphics_exposures = False;
1531 clip_gc_valuemask = GCGraphicsExposures;
1532 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
1533 clip_gc_valuemask, &clip_gc_values);
1536 graphic_info[i].clip_mask =
1537 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
1539 src_pixmap = src_bitmap->clip_mask;
1540 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
1541 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
1543 clip_gc_values.graphics_exposures = False;
1544 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
1545 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
1547 graphic_info[i].clip_gc =
1548 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
1552 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1553 if (copy_clipmask_gc)
1554 XFreeGC(display, copy_clipmask_gc);
1556 clipmasks_initialized = TRUE;
1560 static void InitElementSoundInfo()
1562 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1563 int num_property_mappings = getSoundListPropertyMappingSize();
1566 /* set values to -1 to identify later as "uninitialized" values */
1567 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1568 for (act = 0; act < NUM_ACTIONS; act++)
1569 element_info[i].sound[act] = -1;
1571 /* initialize element/sound mapping from static configuration */
1572 for (i = 0; element_to_sound[i].element > -1; i++)
1574 int element = element_to_sound[i].element;
1575 int action = element_to_sound[i].action;
1576 int sound = element_to_sound[i].sound;
1577 boolean is_class = element_to_sound[i].is_class;
1580 action = ACTION_DEFAULT;
1583 element_info[element].sound[action] = sound;
1585 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1586 if (strEqual(element_info[j].class_name,
1587 element_info[element].class_name))
1588 element_info[j].sound[action] = sound;
1591 /* initialize element class/sound mapping from dynamic configuration */
1592 for (i = 0; i < num_property_mappings; i++)
1594 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1595 int action = property_mapping[i].ext1_index;
1596 int sound = property_mapping[i].artwork_index;
1598 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1602 action = ACTION_DEFAULT;
1604 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1605 if (strEqual(element_info[j].class_name,
1606 element_info[element_class].class_name))
1607 element_info[j].sound[action] = sound;
1610 /* initialize element/sound mapping from dynamic configuration */
1611 for (i = 0; i < num_property_mappings; i++)
1613 int element = property_mapping[i].base_index;
1614 int action = property_mapping[i].ext1_index;
1615 int sound = property_mapping[i].artwork_index;
1617 if (element >= MAX_NUM_ELEMENTS)
1621 action = ACTION_DEFAULT;
1623 element_info[element].sound[action] = sound;
1626 /* now set all '-1' values to element specific default values */
1627 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1629 for (act = 0; act < NUM_ACTIONS; act++)
1631 /* generic default action sound (defined by "[default]" directive) */
1632 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1634 /* look for special default action sound (classic game specific) */
1635 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1636 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1637 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1638 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1639 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1640 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1642 /* !!! there's no such thing as a "default action sound" !!! */
1644 /* look for element specific default sound (independent from action) */
1645 if (element_info[i].sound[ACTION_DEFAULT] != -1)
1646 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
1650 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1651 /* !!! make this better !!! */
1652 if (i == EL_EMPTY_SPACE)
1653 default_action_sound = element_info[EL_DEFAULT].sound[act];
1656 /* no sound for this specific action -- use default action sound */
1657 if (element_info[i].sound[act] == -1)
1658 element_info[i].sound[act] = default_action_sound;
1662 /* copy sound settings to some elements that are only stored in level file
1663 in native R'n'D levels, but are used by game engine in native EM levels */
1664 for (i = 0; copy_properties[i][0] != -1; i++)
1665 for (j = 1; j <= 4; j++)
1666 for (act = 0; act < NUM_ACTIONS; act++)
1667 element_info[copy_properties[i][j]].sound[act] =
1668 element_info[copy_properties[i][0]].sound[act];
1671 static void InitGameModeSoundInfo()
1675 /* set values to -1 to identify later as "uninitialized" values */
1676 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1679 /* initialize gamemode/sound mapping from static configuration */
1680 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1682 int gamemode = gamemode_to_sound[i].gamemode;
1683 int sound = gamemode_to_sound[i].sound;
1686 gamemode = GAME_MODE_DEFAULT;
1688 menu.sound[gamemode] = sound;
1691 /* now set all '-1' values to levelset specific default values */
1692 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1693 if (menu.sound[i] == -1)
1694 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1697 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1698 if (menu.sound[i] != -1)
1699 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
1703 static void set_sound_parameters(int sound, char **parameter_raw)
1705 int parameter[NUM_SND_ARGS];
1708 /* get integer values from string parameters */
1709 for (i = 0; i < NUM_SND_ARGS; i++)
1711 get_parameter_value(parameter_raw[i],
1712 sound_config_suffix[i].token,
1713 sound_config_suffix[i].type);
1715 /* explicit loop mode setting in configuration overrides default value */
1716 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1717 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1719 /* sound volume to change the original volume when loading the sound file */
1720 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1722 /* sound priority to give certain sounds a higher or lower priority */
1723 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
1726 static void InitSoundInfo()
1728 int *sound_effect_properties;
1729 int num_sounds = getSoundListSize();
1732 checked_free(sound_info);
1734 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1735 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1737 /* initialize sound effect for all elements to "no sound" */
1738 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1739 for (j = 0; j < NUM_ACTIONS; j++)
1740 element_info[i].sound[j] = SND_UNDEFINED;
1742 for (i = 0; i < num_sounds; i++)
1744 struct FileInfo *sound = getSoundListEntry(i);
1745 int len_effect_text = strlen(sound->token);
1747 sound_effect_properties[i] = ACTION_OTHER;
1748 sound_info[i].loop = FALSE; /* default: play sound only once */
1751 printf("::: sound %d: '%s'\n", i, sound->token);
1754 /* determine all loop sounds and identify certain sound classes */
1756 for (j = 0; element_action_info[j].suffix; j++)
1758 int len_action_text = strlen(element_action_info[j].suffix);
1760 if (len_action_text < len_effect_text &&
1761 strEqual(&sound->token[len_effect_text - len_action_text],
1762 element_action_info[j].suffix))
1764 sound_effect_properties[i] = element_action_info[j].value;
1765 sound_info[i].loop = element_action_info[j].is_loop_sound;
1771 /* associate elements and some selected sound actions */
1773 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1775 if (element_info[j].class_name)
1777 int len_class_text = strlen(element_info[j].class_name);
1779 if (len_class_text + 1 < len_effect_text &&
1780 strncmp(sound->token,
1781 element_info[j].class_name, len_class_text) == 0 &&
1782 sound->token[len_class_text] == '.')
1784 int sound_action_value = sound_effect_properties[i];
1786 element_info[j].sound[sound_action_value] = i;
1791 set_sound_parameters(i, sound->parameter);
1794 free(sound_effect_properties);
1797 static void InitGameModeMusicInfo()
1799 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1800 int num_property_mappings = getMusicListPropertyMappingSize();
1801 int default_levelset_music = -1;
1804 /* set values to -1 to identify later as "uninitialized" values */
1805 for (i = 0; i < MAX_LEVELS; i++)
1806 levelset.music[i] = -1;
1807 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1810 /* initialize gamemode/music mapping from static configuration */
1811 for (i = 0; gamemode_to_music[i].music > -1; i++)
1813 int gamemode = gamemode_to_music[i].gamemode;
1814 int music = gamemode_to_music[i].music;
1817 printf("::: gamemode == %d, music == %d\n", gamemode, music);
1821 gamemode = GAME_MODE_DEFAULT;
1823 menu.music[gamemode] = music;
1826 /* initialize gamemode/music mapping from dynamic configuration */
1827 for (i = 0; i < num_property_mappings; i++)
1829 int prefix = property_mapping[i].base_index;
1830 int gamemode = property_mapping[i].ext1_index;
1831 int level = property_mapping[i].ext2_index;
1832 int music = property_mapping[i].artwork_index;
1835 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
1836 prefix, gamemode, level, music);
1839 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1843 gamemode = GAME_MODE_DEFAULT;
1845 /* level specific music only allowed for in-game music */
1846 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1847 gamemode = GAME_MODE_PLAYING;
1852 default_levelset_music = music;
1855 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1856 levelset.music[level] = music;
1857 if (gamemode != GAME_MODE_PLAYING)
1858 menu.music[gamemode] = music;
1861 /* now set all '-1' values to menu specific default values */
1862 /* (undefined values of "levelset.music[]" might stay at "-1" to
1863 allow dynamic selection of music files from music directory!) */
1864 for (i = 0; i < MAX_LEVELS; i++)
1865 if (levelset.music[i] == -1)
1866 levelset.music[i] = default_levelset_music;
1867 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1868 if (menu.music[i] == -1)
1869 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1872 for (i = 0; i < MAX_LEVELS; i++)
1873 if (levelset.music[i] != -1)
1874 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
1875 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1876 if (menu.music[i] != -1)
1877 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
1881 static void set_music_parameters(int music, char **parameter_raw)
1883 int parameter[NUM_MUS_ARGS];
1886 /* get integer values from string parameters */
1887 for (i = 0; i < NUM_MUS_ARGS; i++)
1889 get_parameter_value(parameter_raw[i],
1890 music_config_suffix[i].token,
1891 music_config_suffix[i].type);
1893 /* explicit loop mode setting in configuration overrides default value */
1894 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1895 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1898 static void InitMusicInfo()
1900 int num_music = getMusicListSize();
1903 checked_free(music_info);
1905 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1907 for (i = 0; i < num_music; i++)
1909 struct FileInfo *music = getMusicListEntry(i);
1910 int len_music_text = strlen(music->token);
1912 music_info[i].loop = TRUE; /* default: play music in loop mode */
1914 /* determine all loop music */
1916 for (j = 0; music_prefix_info[j].prefix; j++)
1918 int len_prefix_text = strlen(music_prefix_info[j].prefix);
1920 if (len_prefix_text < len_music_text &&
1921 strncmp(music->token,
1922 music_prefix_info[j].prefix, len_prefix_text) == 0)
1924 music_info[i].loop = music_prefix_info[j].is_loop_music;
1930 set_music_parameters(i, music->parameter);
1934 static void ReinitializeGraphics()
1936 InitGraphicInfo(); /* graphic properties mapping */
1937 InitElementGraphicInfo(); /* element game graphic mapping */
1938 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
1940 InitElementSmallImages(); /* scale elements to all needed sizes */
1941 InitScaledImages(); /* scale all other images, if needed */
1942 InitFontGraphicInfo(); /* initialize text drawing functions */
1944 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
1946 SetMainBackgroundImage(IMG_BACKGROUND);
1947 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1953 static void ReinitializeSounds()
1955 InitSoundInfo(); /* sound properties mapping */
1956 InitElementSoundInfo(); /* element game sound mapping */
1957 InitGameModeSoundInfo(); /* game mode sound mapping */
1959 InitPlayLevelSound(); /* internal game sound settings */
1962 static void ReinitializeMusic()
1964 InitMusicInfo(); /* music properties mapping */
1965 InitGameModeMusicInfo(); /* game mode music mapping */
1968 static int get_special_property_bit(int element, int property_bit_nr)
1970 struct PropertyBitInfo
1976 static struct PropertyBitInfo pb_can_move_into_acid[] =
1978 /* the player may be able fall into acid when gravity is activated */
1983 { EL_SP_MURPHY, 0 },
1984 { EL_SOKOBAN_FIELD_PLAYER, 0 },
1986 /* all elements that can move may be able to also move into acid */
1989 { EL_BUG_RIGHT, 1 },
1992 { EL_SPACESHIP, 2 },
1993 { EL_SPACESHIP_LEFT, 2 },
1994 { EL_SPACESHIP_RIGHT, 2 },
1995 { EL_SPACESHIP_UP, 2 },
1996 { EL_SPACESHIP_DOWN, 2 },
1997 { EL_BD_BUTTERFLY, 3 },
1998 { EL_BD_BUTTERFLY_LEFT, 3 },
1999 { EL_BD_BUTTERFLY_RIGHT, 3 },
2000 { EL_BD_BUTTERFLY_UP, 3 },
2001 { EL_BD_BUTTERFLY_DOWN, 3 },
2002 { EL_BD_FIREFLY, 4 },
2003 { EL_BD_FIREFLY_LEFT, 4 },
2004 { EL_BD_FIREFLY_RIGHT, 4 },
2005 { EL_BD_FIREFLY_UP, 4 },
2006 { EL_BD_FIREFLY_DOWN, 4 },
2008 { EL_YAMYAM_LEFT, 5 },
2009 { EL_YAMYAM_RIGHT, 5 },
2010 { EL_YAMYAM_UP, 5 },
2011 { EL_YAMYAM_DOWN, 5 },
2012 { EL_DARK_YAMYAM, 6 },
2015 { EL_PACMAN_LEFT, 8 },
2016 { EL_PACMAN_RIGHT, 8 },
2017 { EL_PACMAN_UP, 8 },
2018 { EL_PACMAN_DOWN, 8 },
2020 { EL_MOLE_LEFT, 9 },
2021 { EL_MOLE_RIGHT, 9 },
2023 { EL_MOLE_DOWN, 9 },
2027 { EL_SATELLITE, 13 },
2028 { EL_SP_SNIKSNAK, 14 },
2029 { EL_SP_ELECTRON, 15 },
2032 { EL_EMC_ANDROID, 18 },
2037 static struct PropertyBitInfo pb_dont_collide_with[] =
2039 { EL_SP_SNIKSNAK, 0 },
2040 { EL_SP_ELECTRON, 1 },
2048 struct PropertyBitInfo *pb_info;
2051 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2052 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2057 struct PropertyBitInfo *pb_info = NULL;
2060 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2061 if (pb_definition[i].bit_nr == property_bit_nr)
2062 pb_info = pb_definition[i].pb_info;
2064 if (pb_info == NULL)
2067 for (i = 0; pb_info[i].element != -1; i++)
2068 if (pb_info[i].element == element)
2069 return pb_info[i].bit_nr;
2074 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2075 boolean property_value)
2077 int bit_nr = get_special_property_bit(element, property_bit_nr);
2082 *bitfield |= (1 << bit_nr);
2084 *bitfield &= ~(1 << bit_nr);
2088 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2090 int bit_nr = get_special_property_bit(element, property_bit_nr);
2093 return ((*bitfield & (1 << bit_nr)) != 0);
2098 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2100 static int group_nr;
2101 static struct ElementGroupInfo *group;
2102 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2105 if (actual_group == NULL) /* not yet initialized */
2108 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
2110 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2111 group_element - EL_GROUP_START + 1);
2113 /* replace element which caused too deep recursion by question mark */
2114 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2119 if (recursion_depth == 0) /* initialization */
2121 group = actual_group;
2122 group_nr = GROUP_NR(group_element);
2124 group->num_elements_resolved = 0;
2125 group->choice_pos = 0;
2127 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2128 element_info[i].in_group[group_nr] = FALSE;
2131 for (i = 0; i < actual_group->num_elements; i++)
2133 int element = actual_group->element[i];
2135 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2138 if (IS_GROUP_ELEMENT(element))
2139 ResolveGroupElementExt(element, recursion_depth + 1);
2142 group->element_resolved[group->num_elements_resolved++] = element;
2143 element_info[element].in_group[group_nr] = TRUE;
2148 void ResolveGroupElement(int group_element)
2150 ResolveGroupElementExt(group_element, 0);
2153 void InitElementPropertiesStatic()
2155 static int ep_diggable[] =
2160 EL_SP_BUGGY_BASE_ACTIVATING,
2163 EL_INVISIBLE_SAND_ACTIVE,
2166 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2167 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2172 EL_SP_BUGGY_BASE_ACTIVE,
2179 static int ep_collectible_only[] =
2201 EL_DYNABOMB_INCREASE_NUMBER,
2202 EL_DYNABOMB_INCREASE_SIZE,
2203 EL_DYNABOMB_INCREASE_POWER,
2221 /* !!! handle separately !!! */
2222 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2228 static int ep_dont_run_into[] =
2230 /* same elements as in 'ep_dont_touch' */
2236 /* same elements as in 'ep_dont_collide_with' */
2248 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2253 EL_SP_BUGGY_BASE_ACTIVE,
2260 static int ep_dont_collide_with[] =
2262 /* same elements as in 'ep_dont_touch' */
2279 static int ep_dont_touch[] =
2289 static int ep_indestructible[] =
2293 EL_ACID_POOL_TOPLEFT,
2294 EL_ACID_POOL_TOPRIGHT,
2295 EL_ACID_POOL_BOTTOMLEFT,
2296 EL_ACID_POOL_BOTTOM,
2297 EL_ACID_POOL_BOTTOMRIGHT,
2298 EL_SP_HARDWARE_GRAY,
2299 EL_SP_HARDWARE_GREEN,
2300 EL_SP_HARDWARE_BLUE,
2302 EL_SP_HARDWARE_YELLOW,
2303 EL_SP_HARDWARE_BASE_1,
2304 EL_SP_HARDWARE_BASE_2,
2305 EL_SP_HARDWARE_BASE_3,
2306 EL_SP_HARDWARE_BASE_4,
2307 EL_SP_HARDWARE_BASE_5,
2308 EL_SP_HARDWARE_BASE_6,
2309 EL_INVISIBLE_STEELWALL,
2310 EL_INVISIBLE_STEELWALL_ACTIVE,
2311 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2312 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2313 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2314 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2315 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2316 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2317 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2318 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2319 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2320 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2321 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2322 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2324 EL_LIGHT_SWITCH_ACTIVE,
2325 EL_SIGN_EXCLAMATION,
2326 EL_SIGN_RADIOACTIVITY,
2333 EL_SIGN_ENTRY_FORBIDDEN,
2334 EL_SIGN_EMERGENCY_EXIT,
2342 EL_STEEL_EXIT_CLOSED,
2344 EL_EM_STEEL_EXIT_CLOSED,
2345 EL_EM_STEEL_EXIT_OPEN,
2346 EL_DC_STEELWALL_1_LEFT,
2347 EL_DC_STEELWALL_1_RIGHT,
2348 EL_DC_STEELWALL_1_TOP,
2349 EL_DC_STEELWALL_1_BOTTOM,
2350 EL_DC_STEELWALL_1_HORIZONTAL,
2351 EL_DC_STEELWALL_1_VERTICAL,
2352 EL_DC_STEELWALL_1_TOPLEFT,
2353 EL_DC_STEELWALL_1_TOPRIGHT,
2354 EL_DC_STEELWALL_1_BOTTOMLEFT,
2355 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2356 EL_DC_STEELWALL_1_TOPLEFT_2,
2357 EL_DC_STEELWALL_1_TOPRIGHT_2,
2358 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2359 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2360 EL_DC_STEELWALL_2_LEFT,
2361 EL_DC_STEELWALL_2_RIGHT,
2362 EL_DC_STEELWALL_2_TOP,
2363 EL_DC_STEELWALL_2_BOTTOM,
2364 EL_DC_STEELWALL_2_HORIZONTAL,
2365 EL_DC_STEELWALL_2_VERTICAL,
2366 EL_DC_STEELWALL_2_MIDDLE,
2367 EL_DC_STEELWALL_2_SINGLE,
2368 EL_STEELWALL_SLIPPERY,
2382 EL_GATE_1_GRAY_ACTIVE,
2383 EL_GATE_2_GRAY_ACTIVE,
2384 EL_GATE_3_GRAY_ACTIVE,
2385 EL_GATE_4_GRAY_ACTIVE,
2394 EL_EM_GATE_1_GRAY_ACTIVE,
2395 EL_EM_GATE_2_GRAY_ACTIVE,
2396 EL_EM_GATE_3_GRAY_ACTIVE,
2397 EL_EM_GATE_4_GRAY_ACTIVE,
2406 EL_EMC_GATE_5_GRAY_ACTIVE,
2407 EL_EMC_GATE_6_GRAY_ACTIVE,
2408 EL_EMC_GATE_7_GRAY_ACTIVE,
2409 EL_EMC_GATE_8_GRAY_ACTIVE,
2411 EL_DC_GATE_WHITE_GRAY,
2412 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2413 EL_DC_GATE_FAKE_GRAY,
2415 EL_SWITCHGATE_OPENING,
2416 EL_SWITCHGATE_CLOSED,
2417 EL_SWITCHGATE_CLOSING,
2419 EL_DC_SWITCHGATE_SWITCH_UP,
2420 EL_DC_SWITCHGATE_SWITCH_DOWN,
2423 EL_TIMEGATE_OPENING,
2425 EL_TIMEGATE_CLOSING,
2427 EL_DC_TIMEGATE_SWITCH,
2428 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2433 EL_TUBE_VERTICAL_LEFT,
2434 EL_TUBE_VERTICAL_RIGHT,
2435 EL_TUBE_HORIZONTAL_UP,
2436 EL_TUBE_HORIZONTAL_DOWN,
2441 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2442 EL_EXPANDABLE_STEELWALL_VERTICAL,
2443 EL_EXPANDABLE_STEELWALL_ANY,
2448 static int ep_slippery[] =
2462 EL_ROBOT_WHEEL_ACTIVE,
2468 EL_ACID_POOL_TOPLEFT,
2469 EL_ACID_POOL_TOPRIGHT,
2479 EL_STEELWALL_SLIPPERY,
2482 EL_EMC_WALL_SLIPPERY_1,
2483 EL_EMC_WALL_SLIPPERY_2,
2484 EL_EMC_WALL_SLIPPERY_3,
2485 EL_EMC_WALL_SLIPPERY_4,
2487 EL_EMC_MAGIC_BALL_ACTIVE,
2492 static int ep_can_change[] =
2497 static int ep_can_move[] =
2499 /* same elements as in 'pb_can_move_into_acid' */
2522 static int ep_can_fall[] =
2536 EL_QUICKSAND_FAST_FULL,
2538 EL_BD_MAGIC_WALL_FULL,
2539 EL_DC_MAGIC_WALL_FULL,
2553 static int ep_can_smash_player[] =
2579 static int ep_can_smash_enemies[] =
2588 static int ep_can_smash_everything[] =
2597 static int ep_explodes_by_fire[] =
2599 /* same elements as in 'ep_explodes_impact' */
2604 /* same elements as in 'ep_explodes_smashed' */
2614 EL_EM_DYNAMITE_ACTIVE,
2615 EL_DYNABOMB_PLAYER_1_ACTIVE,
2616 EL_DYNABOMB_PLAYER_2_ACTIVE,
2617 EL_DYNABOMB_PLAYER_3_ACTIVE,
2618 EL_DYNABOMB_PLAYER_4_ACTIVE,
2619 EL_DYNABOMB_INCREASE_NUMBER,
2620 EL_DYNABOMB_INCREASE_SIZE,
2621 EL_DYNABOMB_INCREASE_POWER,
2622 EL_SP_DISK_RED_ACTIVE,
2636 static int ep_explodes_smashed[] =
2638 /* same elements as in 'ep_explodes_impact' */
2652 static int ep_explodes_impact[] =
2661 static int ep_walkable_over[] =
2665 EL_SOKOBAN_FIELD_EMPTY,
2671 EL_EM_STEEL_EXIT_OPEN,
2680 EL_GATE_1_GRAY_ACTIVE,
2681 EL_GATE_2_GRAY_ACTIVE,
2682 EL_GATE_3_GRAY_ACTIVE,
2683 EL_GATE_4_GRAY_ACTIVE,
2691 static int ep_walkable_inside[] =
2696 EL_TUBE_VERTICAL_LEFT,
2697 EL_TUBE_VERTICAL_RIGHT,
2698 EL_TUBE_HORIZONTAL_UP,
2699 EL_TUBE_HORIZONTAL_DOWN,
2708 static int ep_walkable_under[] =
2713 static int ep_passable_over[] =
2723 EL_EM_GATE_1_GRAY_ACTIVE,
2724 EL_EM_GATE_2_GRAY_ACTIVE,
2725 EL_EM_GATE_3_GRAY_ACTIVE,
2726 EL_EM_GATE_4_GRAY_ACTIVE,
2735 EL_EMC_GATE_5_GRAY_ACTIVE,
2736 EL_EMC_GATE_6_GRAY_ACTIVE,
2737 EL_EMC_GATE_7_GRAY_ACTIVE,
2738 EL_EMC_GATE_8_GRAY_ACTIVE,
2740 EL_DC_GATE_WHITE_GRAY,
2741 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2748 static int ep_passable_inside[] =
2754 EL_SP_PORT_HORIZONTAL,
2755 EL_SP_PORT_VERTICAL,
2757 EL_SP_GRAVITY_PORT_LEFT,
2758 EL_SP_GRAVITY_PORT_RIGHT,
2759 EL_SP_GRAVITY_PORT_UP,
2760 EL_SP_GRAVITY_PORT_DOWN,
2761 EL_SP_GRAVITY_ON_PORT_LEFT,
2762 EL_SP_GRAVITY_ON_PORT_RIGHT,
2763 EL_SP_GRAVITY_ON_PORT_UP,
2764 EL_SP_GRAVITY_ON_PORT_DOWN,
2765 EL_SP_GRAVITY_OFF_PORT_LEFT,
2766 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2767 EL_SP_GRAVITY_OFF_PORT_UP,
2768 EL_SP_GRAVITY_OFF_PORT_DOWN,
2773 static int ep_passable_under[] =
2778 static int ep_droppable[] =
2783 static int ep_explodes_1x1_old[] =
2788 static int ep_pushable[] =
2800 EL_SOKOBAN_FIELD_FULL,
2809 static int ep_explodes_cross_old[] =
2814 static int ep_protected[] =
2816 /* same elements as in 'ep_walkable_inside' */
2820 EL_TUBE_VERTICAL_LEFT,
2821 EL_TUBE_VERTICAL_RIGHT,
2822 EL_TUBE_HORIZONTAL_UP,
2823 EL_TUBE_HORIZONTAL_DOWN,
2829 /* same elements as in 'ep_passable_over' */
2838 EL_EM_GATE_1_GRAY_ACTIVE,
2839 EL_EM_GATE_2_GRAY_ACTIVE,
2840 EL_EM_GATE_3_GRAY_ACTIVE,
2841 EL_EM_GATE_4_GRAY_ACTIVE,
2850 EL_EMC_GATE_5_GRAY_ACTIVE,
2851 EL_EMC_GATE_6_GRAY_ACTIVE,
2852 EL_EMC_GATE_7_GRAY_ACTIVE,
2853 EL_EMC_GATE_8_GRAY_ACTIVE,
2855 EL_DC_GATE_WHITE_GRAY,
2856 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2860 /* same elements as in 'ep_passable_inside' */
2865 EL_SP_PORT_HORIZONTAL,
2866 EL_SP_PORT_VERTICAL,
2868 EL_SP_GRAVITY_PORT_LEFT,
2869 EL_SP_GRAVITY_PORT_RIGHT,
2870 EL_SP_GRAVITY_PORT_UP,
2871 EL_SP_GRAVITY_PORT_DOWN,
2872 EL_SP_GRAVITY_ON_PORT_LEFT,
2873 EL_SP_GRAVITY_ON_PORT_RIGHT,
2874 EL_SP_GRAVITY_ON_PORT_UP,
2875 EL_SP_GRAVITY_ON_PORT_DOWN,
2876 EL_SP_GRAVITY_OFF_PORT_LEFT,
2877 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2878 EL_SP_GRAVITY_OFF_PORT_UP,
2879 EL_SP_GRAVITY_OFF_PORT_DOWN,
2884 static int ep_throwable[] =
2889 static int ep_can_explode[] =
2891 /* same elements as in 'ep_explodes_impact' */
2896 /* same elements as in 'ep_explodes_smashed' */
2902 /* elements that can explode by explosion or by dragonfire */
2906 EL_EM_DYNAMITE_ACTIVE,
2907 EL_DYNABOMB_PLAYER_1_ACTIVE,
2908 EL_DYNABOMB_PLAYER_2_ACTIVE,
2909 EL_DYNABOMB_PLAYER_3_ACTIVE,
2910 EL_DYNABOMB_PLAYER_4_ACTIVE,
2911 EL_DYNABOMB_INCREASE_NUMBER,
2912 EL_DYNABOMB_INCREASE_SIZE,
2913 EL_DYNABOMB_INCREASE_POWER,
2914 EL_SP_DISK_RED_ACTIVE,
2922 /* elements that can explode only by explosion */
2928 static int ep_gravity_reachable[] =
2934 EL_INVISIBLE_SAND_ACTIVE,
2939 EL_SP_PORT_HORIZONTAL,
2940 EL_SP_PORT_VERTICAL,
2942 EL_SP_GRAVITY_PORT_LEFT,
2943 EL_SP_GRAVITY_PORT_RIGHT,
2944 EL_SP_GRAVITY_PORT_UP,
2945 EL_SP_GRAVITY_PORT_DOWN,
2946 EL_SP_GRAVITY_ON_PORT_LEFT,
2947 EL_SP_GRAVITY_ON_PORT_RIGHT,
2948 EL_SP_GRAVITY_ON_PORT_UP,
2949 EL_SP_GRAVITY_ON_PORT_DOWN,
2950 EL_SP_GRAVITY_OFF_PORT_LEFT,
2951 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2952 EL_SP_GRAVITY_OFF_PORT_UP,
2953 EL_SP_GRAVITY_OFF_PORT_DOWN,
2959 static int ep_player[] =
2966 EL_SOKOBAN_FIELD_PLAYER,
2972 static int ep_can_pass_magic_wall[] =
2986 static int ep_can_pass_dc_magic_wall[] =
3002 static int ep_switchable[] =
3006 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3007 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3008 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3009 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3010 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3011 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3012 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3013 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3014 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3015 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3016 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3017 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3018 EL_SWITCHGATE_SWITCH_UP,
3019 EL_SWITCHGATE_SWITCH_DOWN,
3020 EL_DC_SWITCHGATE_SWITCH_UP,
3021 EL_DC_SWITCHGATE_SWITCH_DOWN,
3023 EL_LIGHT_SWITCH_ACTIVE,
3025 EL_DC_TIMEGATE_SWITCH,
3026 EL_BALLOON_SWITCH_LEFT,
3027 EL_BALLOON_SWITCH_RIGHT,
3028 EL_BALLOON_SWITCH_UP,
3029 EL_BALLOON_SWITCH_DOWN,
3030 EL_BALLOON_SWITCH_ANY,
3031 EL_BALLOON_SWITCH_NONE,
3034 EL_EMC_MAGIC_BALL_SWITCH,
3035 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3040 static int ep_bd_element[] =
3074 static int ep_sp_element[] =
3076 /* should always be valid */
3079 /* standard classic Supaplex elements */
3086 EL_SP_HARDWARE_GRAY,
3094 EL_SP_GRAVITY_PORT_RIGHT,
3095 EL_SP_GRAVITY_PORT_DOWN,
3096 EL_SP_GRAVITY_PORT_LEFT,
3097 EL_SP_GRAVITY_PORT_UP,
3102 EL_SP_PORT_VERTICAL,
3103 EL_SP_PORT_HORIZONTAL,
3109 EL_SP_HARDWARE_BASE_1,
3110 EL_SP_HARDWARE_GREEN,
3111 EL_SP_HARDWARE_BLUE,
3113 EL_SP_HARDWARE_YELLOW,
3114 EL_SP_HARDWARE_BASE_2,
3115 EL_SP_HARDWARE_BASE_3,
3116 EL_SP_HARDWARE_BASE_4,
3117 EL_SP_HARDWARE_BASE_5,
3118 EL_SP_HARDWARE_BASE_6,
3122 /* additional elements that appeared in newer Supaplex levels */
3125 /* additional gravity port elements (not switching, but setting gravity) */
3126 EL_SP_GRAVITY_ON_PORT_LEFT,
3127 EL_SP_GRAVITY_ON_PORT_RIGHT,
3128 EL_SP_GRAVITY_ON_PORT_UP,
3129 EL_SP_GRAVITY_ON_PORT_DOWN,
3130 EL_SP_GRAVITY_OFF_PORT_LEFT,
3131 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3132 EL_SP_GRAVITY_OFF_PORT_UP,
3133 EL_SP_GRAVITY_OFF_PORT_DOWN,
3135 /* more than one Murphy in a level results in an inactive clone */
3138 /* runtime Supaplex elements */
3139 EL_SP_DISK_RED_ACTIVE,
3140 EL_SP_TERMINAL_ACTIVE,
3141 EL_SP_BUGGY_BASE_ACTIVATING,
3142 EL_SP_BUGGY_BASE_ACTIVE,
3149 static int ep_sb_element[] =
3154 EL_SOKOBAN_FIELD_EMPTY,
3155 EL_SOKOBAN_FIELD_FULL,
3156 EL_SOKOBAN_FIELD_PLAYER,
3161 EL_INVISIBLE_STEELWALL,
3166 static int ep_gem[] =
3178 static int ep_food_dark_yamyam[] =
3206 static int ep_food_penguin[] =
3220 static int ep_food_pig[] =
3232 static int ep_historic_wall[] =
3243 EL_GATE_1_GRAY_ACTIVE,
3244 EL_GATE_2_GRAY_ACTIVE,
3245 EL_GATE_3_GRAY_ACTIVE,
3246 EL_GATE_4_GRAY_ACTIVE,
3255 EL_EM_GATE_1_GRAY_ACTIVE,
3256 EL_EM_GATE_2_GRAY_ACTIVE,
3257 EL_EM_GATE_3_GRAY_ACTIVE,
3258 EL_EM_GATE_4_GRAY_ACTIVE,
3265 EL_EXPANDABLE_WALL_HORIZONTAL,
3266 EL_EXPANDABLE_WALL_VERTICAL,
3267 EL_EXPANDABLE_WALL_ANY,
3268 EL_EXPANDABLE_WALL_GROWING,
3269 EL_BD_EXPANDABLE_WALL,
3276 EL_SP_HARDWARE_GRAY,
3277 EL_SP_HARDWARE_GREEN,
3278 EL_SP_HARDWARE_BLUE,
3280 EL_SP_HARDWARE_YELLOW,
3281 EL_SP_HARDWARE_BASE_1,
3282 EL_SP_HARDWARE_BASE_2,
3283 EL_SP_HARDWARE_BASE_3,
3284 EL_SP_HARDWARE_BASE_4,
3285 EL_SP_HARDWARE_BASE_5,
3286 EL_SP_HARDWARE_BASE_6,
3288 EL_SP_TERMINAL_ACTIVE,
3291 EL_INVISIBLE_STEELWALL,
3292 EL_INVISIBLE_STEELWALL_ACTIVE,
3294 EL_INVISIBLE_WALL_ACTIVE,
3295 EL_STEELWALL_SLIPPERY,
3312 static int ep_historic_solid[] =
3316 EL_EXPANDABLE_WALL_HORIZONTAL,
3317 EL_EXPANDABLE_WALL_VERTICAL,
3318 EL_EXPANDABLE_WALL_ANY,
3319 EL_BD_EXPANDABLE_WALL,
3332 EL_QUICKSAND_FILLING,
3333 EL_QUICKSAND_EMPTYING,
3335 EL_MAGIC_WALL_ACTIVE,
3336 EL_MAGIC_WALL_EMPTYING,
3337 EL_MAGIC_WALL_FILLING,
3341 EL_BD_MAGIC_WALL_ACTIVE,
3342 EL_BD_MAGIC_WALL_EMPTYING,
3343 EL_BD_MAGIC_WALL_FULL,
3344 EL_BD_MAGIC_WALL_FILLING,
3345 EL_BD_MAGIC_WALL_DEAD,
3354 EL_SP_TERMINAL_ACTIVE,
3358 EL_INVISIBLE_WALL_ACTIVE,
3359 EL_SWITCHGATE_SWITCH_UP,
3360 EL_SWITCHGATE_SWITCH_DOWN,
3361 EL_DC_SWITCHGATE_SWITCH_UP,
3362 EL_DC_SWITCHGATE_SWITCH_DOWN,
3364 EL_TIMEGATE_SWITCH_ACTIVE,
3365 EL_DC_TIMEGATE_SWITCH,
3366 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3378 /* the following elements are a direct copy of "indestructible" elements,
3379 except "EL_ACID", which is "indestructible", but not "solid"! */
3384 EL_ACID_POOL_TOPLEFT,
3385 EL_ACID_POOL_TOPRIGHT,
3386 EL_ACID_POOL_BOTTOMLEFT,
3387 EL_ACID_POOL_BOTTOM,
3388 EL_ACID_POOL_BOTTOMRIGHT,
3389 EL_SP_HARDWARE_GRAY,
3390 EL_SP_HARDWARE_GREEN,
3391 EL_SP_HARDWARE_BLUE,
3393 EL_SP_HARDWARE_YELLOW,
3394 EL_SP_HARDWARE_BASE_1,
3395 EL_SP_HARDWARE_BASE_2,
3396 EL_SP_HARDWARE_BASE_3,
3397 EL_SP_HARDWARE_BASE_4,
3398 EL_SP_HARDWARE_BASE_5,
3399 EL_SP_HARDWARE_BASE_6,
3400 EL_INVISIBLE_STEELWALL,
3401 EL_INVISIBLE_STEELWALL_ACTIVE,
3402 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3403 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3404 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3405 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3406 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3407 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3408 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3409 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3410 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3411 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3412 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3413 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3415 EL_LIGHT_SWITCH_ACTIVE,
3416 EL_SIGN_EXCLAMATION,
3417 EL_SIGN_RADIOACTIVITY,
3424 EL_SIGN_ENTRY_FORBIDDEN,
3425 EL_SIGN_EMERGENCY_EXIT,
3433 EL_STEEL_EXIT_CLOSED,
3435 EL_DC_STEELWALL_1_LEFT,
3436 EL_DC_STEELWALL_1_RIGHT,
3437 EL_DC_STEELWALL_1_TOP,
3438 EL_DC_STEELWALL_1_BOTTOM,
3439 EL_DC_STEELWALL_1_HORIZONTAL,
3440 EL_DC_STEELWALL_1_VERTICAL,
3441 EL_DC_STEELWALL_1_TOPLEFT,
3442 EL_DC_STEELWALL_1_TOPRIGHT,
3443 EL_DC_STEELWALL_1_BOTTOMLEFT,
3444 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3445 EL_DC_STEELWALL_1_TOPLEFT_2,
3446 EL_DC_STEELWALL_1_TOPRIGHT_2,
3447 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3448 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3449 EL_DC_STEELWALL_2_LEFT,
3450 EL_DC_STEELWALL_2_RIGHT,
3451 EL_DC_STEELWALL_2_TOP,
3452 EL_DC_STEELWALL_2_BOTTOM,
3453 EL_DC_STEELWALL_2_HORIZONTAL,
3454 EL_DC_STEELWALL_2_VERTICAL,
3455 EL_DC_STEELWALL_2_MIDDLE,
3456 EL_DC_STEELWALL_2_SINGLE,
3457 EL_STEELWALL_SLIPPERY,
3471 EL_GATE_1_GRAY_ACTIVE,
3472 EL_GATE_2_GRAY_ACTIVE,
3473 EL_GATE_3_GRAY_ACTIVE,
3474 EL_GATE_4_GRAY_ACTIVE,
3483 EL_EM_GATE_1_GRAY_ACTIVE,
3484 EL_EM_GATE_2_GRAY_ACTIVE,
3485 EL_EM_GATE_3_GRAY_ACTIVE,
3486 EL_EM_GATE_4_GRAY_ACTIVE,
3488 EL_SWITCHGATE_OPENING,
3489 EL_SWITCHGATE_CLOSED,
3490 EL_SWITCHGATE_CLOSING,
3492 EL_TIMEGATE_OPENING,
3494 EL_TIMEGATE_CLOSING,
3498 EL_TUBE_VERTICAL_LEFT,
3499 EL_TUBE_VERTICAL_RIGHT,
3500 EL_TUBE_HORIZONTAL_UP,
3501 EL_TUBE_HORIZONTAL_DOWN,
3510 static int ep_classic_enemy[] =
3527 static int ep_belt[] =
3529 EL_CONVEYOR_BELT_1_LEFT,
3530 EL_CONVEYOR_BELT_1_MIDDLE,
3531 EL_CONVEYOR_BELT_1_RIGHT,
3532 EL_CONVEYOR_BELT_2_LEFT,
3533 EL_CONVEYOR_BELT_2_MIDDLE,
3534 EL_CONVEYOR_BELT_2_RIGHT,
3535 EL_CONVEYOR_BELT_3_LEFT,
3536 EL_CONVEYOR_BELT_3_MIDDLE,
3537 EL_CONVEYOR_BELT_3_RIGHT,
3538 EL_CONVEYOR_BELT_4_LEFT,
3539 EL_CONVEYOR_BELT_4_MIDDLE,
3540 EL_CONVEYOR_BELT_4_RIGHT,
3545 static int ep_belt_active[] =
3547 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3548 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3549 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3550 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3551 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3552 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3553 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3554 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3555 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3556 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3557 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3558 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3563 static int ep_belt_switch[] =
3565 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3566 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3567 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3568 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3569 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3570 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3571 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3572 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3573 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3574 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3575 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3576 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3581 static int ep_tube[] =
3588 EL_TUBE_HORIZONTAL_UP,
3589 EL_TUBE_HORIZONTAL_DOWN,
3591 EL_TUBE_VERTICAL_LEFT,
3592 EL_TUBE_VERTICAL_RIGHT,
3598 static int ep_acid_pool[] =
3600 EL_ACID_POOL_TOPLEFT,
3601 EL_ACID_POOL_TOPRIGHT,
3602 EL_ACID_POOL_BOTTOMLEFT,
3603 EL_ACID_POOL_BOTTOM,
3604 EL_ACID_POOL_BOTTOMRIGHT,
3609 static int ep_keygate[] =
3619 EL_GATE_1_GRAY_ACTIVE,
3620 EL_GATE_2_GRAY_ACTIVE,
3621 EL_GATE_3_GRAY_ACTIVE,
3622 EL_GATE_4_GRAY_ACTIVE,
3631 EL_EM_GATE_1_GRAY_ACTIVE,
3632 EL_EM_GATE_2_GRAY_ACTIVE,
3633 EL_EM_GATE_3_GRAY_ACTIVE,
3634 EL_EM_GATE_4_GRAY_ACTIVE,
3643 EL_EMC_GATE_5_GRAY_ACTIVE,
3644 EL_EMC_GATE_6_GRAY_ACTIVE,
3645 EL_EMC_GATE_7_GRAY_ACTIVE,
3646 EL_EMC_GATE_8_GRAY_ACTIVE,
3648 EL_DC_GATE_WHITE_GRAY,
3649 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3654 static int ep_amoeboid[] =
3666 static int ep_amoebalive[] =
3677 static int ep_has_editor_content[] =
3699 static int ep_can_turn_each_move[] =
3701 /* !!! do something with this one !!! */
3705 static int ep_can_grow[] =
3719 static int ep_active_bomb[] =
3722 EL_EM_DYNAMITE_ACTIVE,
3723 EL_DYNABOMB_PLAYER_1_ACTIVE,
3724 EL_DYNABOMB_PLAYER_2_ACTIVE,
3725 EL_DYNABOMB_PLAYER_3_ACTIVE,
3726 EL_DYNABOMB_PLAYER_4_ACTIVE,
3727 EL_SP_DISK_RED_ACTIVE,
3732 static int ep_inactive[] =
3742 EL_QUICKSAND_FAST_EMPTY,
3765 EL_GATE_1_GRAY_ACTIVE,
3766 EL_GATE_2_GRAY_ACTIVE,
3767 EL_GATE_3_GRAY_ACTIVE,
3768 EL_GATE_4_GRAY_ACTIVE,
3777 EL_EM_GATE_1_GRAY_ACTIVE,
3778 EL_EM_GATE_2_GRAY_ACTIVE,
3779 EL_EM_GATE_3_GRAY_ACTIVE,
3780 EL_EM_GATE_4_GRAY_ACTIVE,
3789 EL_EMC_GATE_5_GRAY_ACTIVE,
3790 EL_EMC_GATE_6_GRAY_ACTIVE,
3791 EL_EMC_GATE_7_GRAY_ACTIVE,
3792 EL_EMC_GATE_8_GRAY_ACTIVE,
3794 EL_DC_GATE_WHITE_GRAY,
3795 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3796 EL_DC_GATE_FAKE_GRAY,
3799 EL_INVISIBLE_STEELWALL,
3807 EL_WALL_EMERALD_YELLOW,
3808 EL_DYNABOMB_INCREASE_NUMBER,
3809 EL_DYNABOMB_INCREASE_SIZE,
3810 EL_DYNABOMB_INCREASE_POWER,
3814 EL_SOKOBAN_FIELD_EMPTY,
3815 EL_SOKOBAN_FIELD_FULL,
3816 EL_WALL_EMERALD_RED,
3817 EL_WALL_EMERALD_PURPLE,
3818 EL_ACID_POOL_TOPLEFT,
3819 EL_ACID_POOL_TOPRIGHT,
3820 EL_ACID_POOL_BOTTOMLEFT,
3821 EL_ACID_POOL_BOTTOM,
3822 EL_ACID_POOL_BOTTOMRIGHT,
3826 EL_BD_MAGIC_WALL_DEAD,
3828 EL_DC_MAGIC_WALL_DEAD,
3829 EL_AMOEBA_TO_DIAMOND,
3837 EL_SP_GRAVITY_PORT_RIGHT,
3838 EL_SP_GRAVITY_PORT_DOWN,
3839 EL_SP_GRAVITY_PORT_LEFT,
3840 EL_SP_GRAVITY_PORT_UP,
3841 EL_SP_PORT_HORIZONTAL,
3842 EL_SP_PORT_VERTICAL,
3853 EL_SP_HARDWARE_GRAY,
3854 EL_SP_HARDWARE_GREEN,
3855 EL_SP_HARDWARE_BLUE,
3857 EL_SP_HARDWARE_YELLOW,
3858 EL_SP_HARDWARE_BASE_1,
3859 EL_SP_HARDWARE_BASE_2,
3860 EL_SP_HARDWARE_BASE_3,
3861 EL_SP_HARDWARE_BASE_4,
3862 EL_SP_HARDWARE_BASE_5,
3863 EL_SP_HARDWARE_BASE_6,
3864 EL_SP_GRAVITY_ON_PORT_LEFT,
3865 EL_SP_GRAVITY_ON_PORT_RIGHT,
3866 EL_SP_GRAVITY_ON_PORT_UP,
3867 EL_SP_GRAVITY_ON_PORT_DOWN,
3868 EL_SP_GRAVITY_OFF_PORT_LEFT,
3869 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3870 EL_SP_GRAVITY_OFF_PORT_UP,
3871 EL_SP_GRAVITY_OFF_PORT_DOWN,
3872 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3873 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3874 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3875 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3876 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3877 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3878 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3879 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3880 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3881 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3882 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3883 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3884 EL_SIGN_EXCLAMATION,
3885 EL_SIGN_RADIOACTIVITY,
3892 EL_SIGN_ENTRY_FORBIDDEN,
3893 EL_SIGN_EMERGENCY_EXIT,
3901 EL_DC_STEELWALL_1_LEFT,
3902 EL_DC_STEELWALL_1_RIGHT,
3903 EL_DC_STEELWALL_1_TOP,
3904 EL_DC_STEELWALL_1_BOTTOM,
3905 EL_DC_STEELWALL_1_HORIZONTAL,
3906 EL_DC_STEELWALL_1_VERTICAL,
3907 EL_DC_STEELWALL_1_TOPLEFT,
3908 EL_DC_STEELWALL_1_TOPRIGHT,
3909 EL_DC_STEELWALL_1_BOTTOMLEFT,
3910 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3911 EL_DC_STEELWALL_1_TOPLEFT_2,
3912 EL_DC_STEELWALL_1_TOPRIGHT_2,
3913 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3914 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3915 EL_DC_STEELWALL_2_LEFT,
3916 EL_DC_STEELWALL_2_RIGHT,
3917 EL_DC_STEELWALL_2_TOP,
3918 EL_DC_STEELWALL_2_BOTTOM,
3919 EL_DC_STEELWALL_2_HORIZONTAL,
3920 EL_DC_STEELWALL_2_VERTICAL,
3921 EL_DC_STEELWALL_2_MIDDLE,
3922 EL_DC_STEELWALL_2_SINGLE,
3923 EL_STEELWALL_SLIPPERY,
3928 EL_EMC_WALL_SLIPPERY_1,
3929 EL_EMC_WALL_SLIPPERY_2,
3930 EL_EMC_WALL_SLIPPERY_3,
3931 EL_EMC_WALL_SLIPPERY_4,
3952 static int ep_em_slippery_wall[] =
3957 static int ep_gfx_crumbled[] =
3968 static int ep_editor_cascade_active[] =
3970 EL_INTERNAL_CASCADE_BD_ACTIVE,
3971 EL_INTERNAL_CASCADE_EM_ACTIVE,
3972 EL_INTERNAL_CASCADE_EMC_ACTIVE,
3973 EL_INTERNAL_CASCADE_RND_ACTIVE,
3974 EL_INTERNAL_CASCADE_SB_ACTIVE,
3975 EL_INTERNAL_CASCADE_SP_ACTIVE,
3976 EL_INTERNAL_CASCADE_DC_ACTIVE,
3977 EL_INTERNAL_CASCADE_DX_ACTIVE,
3978 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
3979 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
3980 EL_INTERNAL_CASCADE_CE_ACTIVE,
3981 EL_INTERNAL_CASCADE_GE_ACTIVE,
3982 EL_INTERNAL_CASCADE_REF_ACTIVE,
3983 EL_INTERNAL_CASCADE_USER_ACTIVE,
3984 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
3989 static int ep_editor_cascade_inactive[] =
3991 EL_INTERNAL_CASCADE_BD,
3992 EL_INTERNAL_CASCADE_EM,
3993 EL_INTERNAL_CASCADE_EMC,
3994 EL_INTERNAL_CASCADE_RND,
3995 EL_INTERNAL_CASCADE_SB,
3996 EL_INTERNAL_CASCADE_SP,
3997 EL_INTERNAL_CASCADE_DC,
3998 EL_INTERNAL_CASCADE_DX,
3999 EL_INTERNAL_CASCADE_CHARS,
4000 EL_INTERNAL_CASCADE_STEEL_CHARS,
4001 EL_INTERNAL_CASCADE_CE,
4002 EL_INTERNAL_CASCADE_GE,
4003 EL_INTERNAL_CASCADE_REF,
4004 EL_INTERNAL_CASCADE_USER,
4005 EL_INTERNAL_CASCADE_DYNAMIC,
4010 static int ep_obsolete[] =
4014 EL_EM_KEY_1_FILE_OBSOLETE,
4015 EL_EM_KEY_2_FILE_OBSOLETE,
4016 EL_EM_KEY_3_FILE_OBSOLETE,
4017 EL_EM_KEY_4_FILE_OBSOLETE,
4018 EL_ENVELOPE_OBSOLETE,
4027 } element_properties[] =
4029 { ep_diggable, EP_DIGGABLE },
4030 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4031 { ep_dont_run_into, EP_DONT_RUN_INTO },
4032 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4033 { ep_dont_touch, EP_DONT_TOUCH },
4034 { ep_indestructible, EP_INDESTRUCTIBLE },
4035 { ep_slippery, EP_SLIPPERY },
4036 { ep_can_change, EP_CAN_CHANGE },
4037 { ep_can_move, EP_CAN_MOVE },
4038 { ep_can_fall, EP_CAN_FALL },
4039 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4040 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4041 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4042 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4043 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4044 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4045 { ep_walkable_over, EP_WALKABLE_OVER },
4046 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4047 { ep_walkable_under, EP_WALKABLE_UNDER },
4048 { ep_passable_over, EP_PASSABLE_OVER },
4049 { ep_passable_inside, EP_PASSABLE_INSIDE },
4050 { ep_passable_under, EP_PASSABLE_UNDER },
4051 { ep_droppable, EP_DROPPABLE },
4052 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4053 { ep_pushable, EP_PUSHABLE },
4054 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4055 { ep_protected, EP_PROTECTED },
4056 { ep_throwable, EP_THROWABLE },
4057 { ep_can_explode, EP_CAN_EXPLODE },
4058 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4060 { ep_player, EP_PLAYER },
4061 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4062 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4063 { ep_switchable, EP_SWITCHABLE },
4064 { ep_bd_element, EP_BD_ELEMENT },
4065 { ep_sp_element, EP_SP_ELEMENT },
4066 { ep_sb_element, EP_SB_ELEMENT },
4068 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4069 { ep_food_penguin, EP_FOOD_PENGUIN },
4070 { ep_food_pig, EP_FOOD_PIG },
4071 { ep_historic_wall, EP_HISTORIC_WALL },
4072 { ep_historic_solid, EP_HISTORIC_SOLID },
4073 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4074 { ep_belt, EP_BELT },
4075 { ep_belt_active, EP_BELT_ACTIVE },
4076 { ep_belt_switch, EP_BELT_SWITCH },
4077 { ep_tube, EP_TUBE },
4078 { ep_acid_pool, EP_ACID_POOL },
4079 { ep_keygate, EP_KEYGATE },
4080 { ep_amoeboid, EP_AMOEBOID },
4081 { ep_amoebalive, EP_AMOEBALIVE },
4082 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4083 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4084 { ep_can_grow, EP_CAN_GROW },
4085 { ep_active_bomb, EP_ACTIVE_BOMB },
4086 { ep_inactive, EP_INACTIVE },
4088 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4090 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4092 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4093 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4095 { ep_obsolete, EP_OBSOLETE },
4102 /* always start with reliable default values (element has no properties) */
4103 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4104 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4105 SET_PROPERTY(i, j, FALSE);
4107 /* set all base element properties from above array definitions */
4108 for (i = 0; element_properties[i].elements != NULL; i++)
4109 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4110 SET_PROPERTY((element_properties[i].elements)[j],
4111 element_properties[i].property, TRUE);
4113 /* copy properties to some elements that are only stored in level file */
4114 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4115 for (j = 0; copy_properties[j][0] != -1; j++)
4116 if (HAS_PROPERTY(copy_properties[j][0], i))
4117 for (k = 1; k <= 4; k++)
4118 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4120 /* set static element properties that are not listed in array definitions */
4121 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4122 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4125 void InitElementPropertiesEngine(int engine_version)
4127 static int no_wall_properties[] =
4130 EP_COLLECTIBLE_ONLY,
4132 EP_DONT_COLLIDE_WITH,
4135 EP_CAN_SMASH_PLAYER,
4136 EP_CAN_SMASH_ENEMIES,
4137 EP_CAN_SMASH_EVERYTHING,
4142 EP_FOOD_DARK_YAMYAM,
4158 /* important: after initialization in InitElementPropertiesStatic(), the
4159 elements are not again initialized to a default value; therefore all
4160 changes have to make sure that they leave the element with a defined
4161 property (which means that conditional property changes must be set to
4162 a reliable default value before) */
4164 /* resolve group elements */
4165 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4166 ResolveGroupElement(EL_GROUP_START + i);
4168 /* set all special, combined or engine dependent element properties */
4169 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4171 /* ---------- INACTIVE ------------------------------------------------- */
4172 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4173 i <= EL_CHAR_END) ||
4174 (i >= EL_STEEL_CHAR_START &&
4175 i <= EL_STEEL_CHAR_END)));
4177 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4178 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4179 IS_WALKABLE_INSIDE(i) ||
4180 IS_WALKABLE_UNDER(i)));
4182 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4183 IS_PASSABLE_INSIDE(i) ||
4184 IS_PASSABLE_UNDER(i)));
4186 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4187 IS_PASSABLE_OVER(i)));
4189 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4190 IS_PASSABLE_INSIDE(i)));
4192 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4193 IS_PASSABLE_UNDER(i)));
4195 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4198 /* ---------- COLLECTIBLE ---------------------------------------------- */
4199 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4203 /* ---------- SNAPPABLE ------------------------------------------------ */
4204 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4205 IS_COLLECTIBLE(i) ||
4209 /* ---------- WALL ----------------------------------------------------- */
4210 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4212 for (j = 0; no_wall_properties[j] != -1; j++)
4213 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4214 i >= EL_FIRST_RUNTIME_UNREAL)
4215 SET_PROPERTY(i, EP_WALL, FALSE);
4217 if (IS_HISTORIC_WALL(i))
4218 SET_PROPERTY(i, EP_WALL, TRUE);
4220 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4221 if (engine_version < VERSION_IDENT(2,2,0,0))
4222 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4224 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4226 !IS_COLLECTIBLE(i)));
4228 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4229 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4230 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4232 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4233 IS_INDESTRUCTIBLE(i)));
4235 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4237 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4238 else if (engine_version < VERSION_IDENT(2,2,0,0))
4239 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4241 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4245 if (IS_CUSTOM_ELEMENT(i))
4247 /* these are additional properties which are initially false when set */
4249 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4251 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4252 if (DONT_COLLIDE_WITH(i))
4253 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4255 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4256 if (CAN_SMASH_EVERYTHING(i))
4257 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4258 if (CAN_SMASH_ENEMIES(i))
4259 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4262 /* ---------- CAN_SMASH ------------------------------------------------ */
4263 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4264 CAN_SMASH_ENEMIES(i) ||
4265 CAN_SMASH_EVERYTHING(i)));
4267 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4268 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4269 EXPLODES_BY_FIRE(i)));
4271 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4272 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4273 EXPLODES_SMASHED(i)));
4275 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4276 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4277 EXPLODES_IMPACT(i)));
4279 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4280 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4282 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4283 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4284 i == EL_BLACK_ORB));
4286 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4287 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4289 IS_CUSTOM_ELEMENT(i)));
4291 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4292 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4293 i == EL_SP_ELECTRON));
4295 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4296 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4297 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4298 getMoveIntoAcidProperty(&level, i));
4300 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4301 if (MAYBE_DONT_COLLIDE_WITH(i))
4302 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4303 getDontCollideWithProperty(&level, i));
4305 /* ---------- SP_PORT -------------------------------------------------- */
4306 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4307 IS_PASSABLE_INSIDE(i)));
4309 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4310 for (j = 0; j < level.num_android_clone_elements; j++)
4311 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4313 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4315 /* ---------- CAN_CHANGE ----------------------------------------------- */
4316 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4317 for (j = 0; j < element_info[i].num_change_pages; j++)
4318 if (element_info[i].change_page[j].can_change)
4319 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4321 /* ---------- HAS_ACTION ----------------------------------------------- */
4322 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4323 for (j = 0; j < element_info[i].num_change_pages; j++)
4324 if (element_info[i].change_page[j].has_action)
4325 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4327 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4328 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4331 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4333 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4334 element_info[i].crumbled[ACTION_DEFAULT] !=
4335 element_info[i].graphic[ACTION_DEFAULT]);
4337 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
4338 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4339 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
4342 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4343 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4344 IS_EDITOR_CASCADE_INACTIVE(i)));
4347 /* dynamically adjust element properties according to game engine version */
4349 static int ep_em_slippery_wall[] =
4354 EL_EXPANDABLE_WALL_HORIZONTAL,
4355 EL_EXPANDABLE_WALL_VERTICAL,
4356 EL_EXPANDABLE_WALL_ANY,
4357 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4358 EL_EXPANDABLE_STEELWALL_VERTICAL,
4359 EL_EXPANDABLE_STEELWALL_ANY,
4360 EL_EXPANDABLE_STEELWALL_GROWING,
4364 /* special EM style gems behaviour */
4365 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4366 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4367 level.em_slippery_gems);
4369 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4370 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4371 (level.em_slippery_gems &&
4372 engine_version > VERSION_IDENT(2,0,1,0)));
4375 /* this is needed because some graphics depend on element properties */
4376 if (game_status == GAME_MODE_PLAYING)
4377 InitElementGraphicInfo();
4380 void InitElementPropertiesAfterLoading(int engine_version)
4384 /* set some other uninitialized values of custom elements in older levels */
4385 if (engine_version < VERSION_IDENT(3,1,0,0))
4387 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4389 int element = EL_CUSTOM_START + i;
4391 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4393 element_info[element].explosion_delay = 17;
4394 element_info[element].ignition_delay = 8;
4399 static void InitGlobal()
4403 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4405 /* check if element_name_info entry defined for each element in "main.h" */
4406 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4407 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4409 element_info[i].token_name = element_name_info[i].token_name;
4410 element_info[i].class_name = element_name_info[i].class_name;
4411 element_info[i].editor_description= element_name_info[i].editor_description;
4414 printf("%04d: %s\n", i, element_name_info[i].token_name);
4418 /* always start with reliable default values (all elements) */
4419 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4420 ActiveElement[i] = i;
4422 /* now add all entries that have an active state (active elements) */
4423 for (i = 0; element_with_active_state[i].element != -1; i++)
4425 int element = element_with_active_state[i].element;
4426 int element_active = element_with_active_state[i].element_active;
4428 ActiveElement[element] = element_active;
4431 /* always start with reliable default values (all buttons) */
4432 for (i = 0; i < NUM_IMAGE_FILES; i++)
4433 ActiveButton[i] = i;
4435 /* now add all entries that have an active state (active buttons) */
4436 for (i = 0; button_with_active_state[i].button != -1; i++)
4438 int button = button_with_active_state[i].button;
4439 int button_active = button_with_active_state[i].button_active;
4441 ActiveButton[button] = button_active;
4444 /* always start with reliable default values (all fonts) */
4445 for (i = 0; i < NUM_FONTS; i++)
4448 /* now add all entries that have an active state (active fonts) */
4449 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4451 int font = font_with_active_state[i].font_nr;
4452 int font_active = font_with_active_state[i].font_nr_active;
4454 ActiveFont[font] = font_active;
4457 global.autoplay_leveldir = NULL;
4458 global.convert_leveldir = NULL;
4460 global.frames_per_second = 0;
4461 global.fps_slowdown = FALSE;
4462 global.fps_slowdown_factor = 1;
4464 global.border_status = GAME_MODE_MAIN;
4466 global.fading_status = GAME_MODE_MAIN;
4467 global.fading_type = TYPE_ENTER_MENU;
4471 void Execute_Command(char *command)
4475 if (strEqual(command, "print graphicsinfo.conf"))
4477 printf("# You can configure additional/alternative image files here.\n");
4478 printf("# (The entries below are default and therefore commented out.)\n");
4480 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4482 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4485 for (i = 0; image_config[i].token != NULL; i++)
4486 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
4487 image_config[i].value));
4491 else if (strEqual(command, "print soundsinfo.conf"))
4493 printf("# You can configure additional/alternative sound files here.\n");
4494 printf("# (The entries below are default and therefore commented out.)\n");
4496 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4498 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4501 for (i = 0; sound_config[i].token != NULL; i++)
4502 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4503 sound_config[i].value));
4507 else if (strEqual(command, "print musicinfo.conf"))
4509 printf("# You can configure additional/alternative music files here.\n");
4510 printf("# (The entries below are default and therefore commented out.)\n");
4512 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4514 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4517 for (i = 0; music_config[i].token != NULL; i++)
4518 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
4519 music_config[i].value));
4523 else if (strEqual(command, "print editorsetup.conf"))
4525 printf("# You can configure your personal editor element list here.\n");
4526 printf("# (The entries below are default and therefore commented out.)\n");
4529 /* this is needed to be able to check element list for cascade elements */
4530 InitElementPropertiesStatic();
4531 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4533 PrintEditorElementList();
4537 else if (strEqual(command, "print helpanim.conf"))
4539 printf("# You can configure different element help animations here.\n");
4540 printf("# (The entries below are default and therefore commented out.)\n");
4543 for (i = 0; helpanim_config[i].token != NULL; i++)
4545 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4546 helpanim_config[i].value));
4548 if (strEqual(helpanim_config[i].token, "end"))
4554 else if (strEqual(command, "print helptext.conf"))
4556 printf("# You can configure different element help text here.\n");
4557 printf("# (The entries below are default and therefore commented out.)\n");
4560 for (i = 0; helptext_config[i].token != NULL; i++)
4561 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4562 helptext_config[i].value));
4566 else if (strncmp(command, "dump level ", 11) == 0)
4568 char *filename = &command[11];
4570 if (!fileExists(filename))
4571 Error(ERR_EXIT, "cannot open file '%s'", filename);
4573 LoadLevelFromFilename(&level, filename);
4578 else if (strncmp(command, "dump tape ", 10) == 0)
4580 char *filename = &command[10];
4582 if (!fileExists(filename))
4583 Error(ERR_EXIT, "cannot open file '%s'", filename);
4585 LoadTapeFromFilename(filename);
4590 else if (strncmp(command, "autoplay ", 9) == 0)
4592 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
4594 while (*str_ptr != '\0') /* continue parsing string */
4596 /* cut leading whitespace from string, replace it by string terminator */
4597 while (*str_ptr == ' ' || *str_ptr == '\t')
4600 if (*str_ptr == '\0') /* end of string reached */
4603 if (global.autoplay_leveldir == NULL) /* read level set string */
4605 global.autoplay_leveldir = str_ptr;
4606 global.autoplay_all = TRUE; /* default: play all tapes */
4608 for (i = 0; i < MAX_TAPES_PER_SET; i++)
4609 global.autoplay_level[i] = FALSE;
4611 else /* read level number string */
4613 int level_nr = atoi(str_ptr); /* get level_nr value */
4615 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
4616 global.autoplay_level[level_nr] = TRUE;
4618 global.autoplay_all = FALSE;
4621 /* advance string pointer to the next whitespace (or end of string) */
4622 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
4626 else if (strncmp(command, "convert ", 8) == 0)
4628 char *str_copy = getStringCopy(&command[8]);
4629 char *str_ptr = strchr(str_copy, ' ');
4631 global.convert_leveldir = str_copy;
4632 global.convert_level_nr = -1;
4634 if (str_ptr != NULL) /* level number follows */
4636 *str_ptr++ = '\0'; /* terminate leveldir string */
4637 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
4642 #if defined(TARGET_SDL)
4643 else if (strEqual(command, "SDL_ListModes"))
4648 SDL_Init(SDL_INIT_VIDEO);
4650 /* get available fullscreen/hardware modes */
4651 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
4653 /* check if there are any modes available */
4656 printf("No modes available!\n");
4661 /* check if our resolution is restricted */
4662 if (modes == (SDL_Rect **)-1)
4664 printf("All resolutions available.\n");
4668 printf("Available Modes:\n");
4670 for(i = 0; modes[i]; i++)
4671 printf(" %d x %d\n", modes[i]->w, modes[i]->h);
4681 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4685 static void InitSetup()
4687 LoadSetup(); /* global setup info */
4689 /* set some options from setup file */
4691 if (setup.options.verbose)
4692 options.verbose = TRUE;
4695 static void InitGameInfo()
4697 game.restart_level = FALSE;
4700 static void InitPlayerInfo()
4704 /* choose default local player */
4705 local_player = &stored_player[0];
4707 for (i = 0; i < MAX_PLAYERS; i++)
4708 stored_player[i].connected = FALSE;
4710 local_player->connected = TRUE;
4713 static void InitArtworkInfo()
4718 static char *get_string_in_brackets(char *string)
4720 char *string_in_brackets = checked_malloc(strlen(string) + 3);
4722 sprintf(string_in_brackets, "[%s]", string);
4724 return string_in_brackets;
4727 static char *get_level_id_suffix(int id_nr)
4729 char *id_suffix = checked_malloc(1 + 3 + 1);
4731 if (id_nr < 0 || id_nr > 999)
4734 sprintf(id_suffix, ".%03d", id_nr);
4740 static char *get_element_class_token(int element)
4742 char *element_class_name = element_info[element].class_name;
4743 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
4745 sprintf(element_class_token, "[%s]", element_class_name);
4747 return element_class_token;
4750 static char *get_action_class_token(int action)
4752 char *action_class_name = &element_action_info[action].suffix[1];
4753 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
4755 sprintf(action_class_token, "[%s]", action_class_name);
4757 return action_class_token;
4761 static void InitArtworkConfig()
4763 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
4764 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
4765 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
4766 static char *action_id_suffix[NUM_ACTIONS + 1];
4767 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
4768 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
4769 static char *level_id_suffix[MAX_LEVELS + 1];
4770 static char *dummy[1] = { NULL };
4771 static char *ignore_generic_tokens[] =
4777 static char **ignore_image_tokens;
4778 static char **ignore_sound_tokens;
4779 static char **ignore_music_tokens;
4780 int num_ignore_generic_tokens;
4781 int num_ignore_image_tokens;
4782 int num_ignore_sound_tokens;
4783 int num_ignore_music_tokens;
4786 /* dynamically determine list of generic tokens to be ignored */
4787 num_ignore_generic_tokens = 0;
4788 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
4789 num_ignore_generic_tokens++;
4791 /* dynamically determine list of image tokens to be ignored */
4792 num_ignore_image_tokens = num_ignore_generic_tokens;
4793 for (i = 0; image_config_vars[i].token != NULL; i++)
4794 num_ignore_image_tokens++;
4795 ignore_image_tokens =
4796 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
4797 for (i = 0; i < num_ignore_generic_tokens; i++)
4798 ignore_image_tokens[i] = ignore_generic_tokens[i];
4799 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
4800 ignore_image_tokens[num_ignore_generic_tokens + i] =
4801 image_config_vars[i].token;
4802 ignore_image_tokens[num_ignore_image_tokens] = NULL;
4804 /* dynamically determine list of sound tokens to be ignored */
4805 num_ignore_sound_tokens = num_ignore_generic_tokens;
4806 ignore_sound_tokens =
4807 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
4808 for (i = 0; i < num_ignore_generic_tokens; i++)
4809 ignore_sound_tokens[i] = ignore_generic_tokens[i];
4810 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
4812 /* dynamically determine list of music tokens to be ignored */
4813 num_ignore_music_tokens = num_ignore_generic_tokens;
4814 ignore_music_tokens =
4815 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
4816 for (i = 0; i < num_ignore_generic_tokens; i++)
4817 ignore_music_tokens[i] = ignore_generic_tokens[i];
4818 ignore_music_tokens[num_ignore_music_tokens] = NULL;
4820 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4821 image_id_prefix[i] = element_info[i].token_name;
4822 for (i = 0; i < NUM_FONTS; i++)
4823 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
4824 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
4826 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4827 sound_id_prefix[i] = element_info[i].token_name;
4828 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4829 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
4830 get_string_in_brackets(element_info[i].class_name);
4831 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
4833 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
4834 music_id_prefix[i] = music_prefix_info[i].prefix;
4835 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
4837 for (i = 0; i < NUM_ACTIONS; i++)
4838 action_id_suffix[i] = element_action_info[i].suffix;
4839 action_id_suffix[NUM_ACTIONS] = NULL;
4841 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
4842 direction_id_suffix[i] = element_direction_info[i].suffix;
4843 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
4845 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
4846 special_id_suffix[i] = special_suffix_info[i].suffix;
4847 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
4849 for (i = 0; i < MAX_LEVELS; i++)
4850 level_id_suffix[i] = get_level_id_suffix(i);
4851 level_id_suffix[MAX_LEVELS] = NULL;
4853 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
4854 image_id_prefix, action_id_suffix, direction_id_suffix,
4855 special_id_suffix, ignore_image_tokens);
4856 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
4857 sound_id_prefix, action_id_suffix, dummy,
4858 special_id_suffix, ignore_sound_tokens);
4859 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
4860 music_id_prefix, special_id_suffix, level_id_suffix,
4861 dummy, ignore_music_tokens);
4864 static void InitMixer()
4872 char *filename_font_initial = NULL;
4873 Bitmap *bitmap_font_initial = NULL;
4877 /* determine settings for initial font (for displaying startup messages) */
4878 for (i = 0; image_config[i].token != NULL; i++)
4880 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4882 char font_token[128];
4885 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
4886 len_font_token = strlen(font_token);
4888 if (strEqual(image_config[i].token, font_token))
4889 filename_font_initial = image_config[i].value;
4890 else if (strlen(image_config[i].token) > len_font_token &&
4891 strncmp(image_config[i].token, font_token, len_font_token) == 0)
4893 if (strEqual(&image_config[i].token[len_font_token], ".x"))
4894 font_initial[j].src_x = atoi(image_config[i].value);
4895 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
4896 font_initial[j].src_y = atoi(image_config[i].value);
4897 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
4898 font_initial[j].width = atoi(image_config[i].value);
4899 else if (strEqual(&image_config[i].token[len_font_token],".height"))
4900 font_initial[j].height = atoi(image_config[i].value);
4905 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4907 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
4908 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
4911 if (filename_font_initial == NULL) /* should not happen */
4912 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
4914 /* create additional image buffers for double-buffering and cross-fading */
4915 bitmap_db_cross = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
4916 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
4917 bitmap_db_panel = CreateBitmap(DXSIZE, DYSIZE, DEFAULT_DEPTH);
4918 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
4920 /* initialize screen properties */
4921 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
4922 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
4924 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
4925 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
4926 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
4928 bitmap_font_initial = LoadCustomImage(filename_font_initial);
4930 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4931 font_initial[j].bitmap = bitmap_font_initial;
4933 InitFontGraphicInfo();
4935 font_height = getFontHeight(FC_RED);
4938 DrawInitText(getWindowTitleString(), 20, FC_YELLOW);
4940 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
4942 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
4943 DrawInitText(PROGRAM_WEBSITE_STRING, WIN_YSIZE - 20 - font_height, FC_RED);
4945 DrawInitText("Loading graphics", 120, FC_GREEN);
4948 void RedrawBackground()
4950 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
4951 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
4953 redraw_mask = REDRAW_ALL;
4956 void InitGfxBackground()
4960 fieldbuffer = bitmap_db_field;
4961 SetDrawtoField(DRAW_BACKBUFFER);
4964 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
4968 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
4969 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
4972 for (x = 0; x < MAX_BUF_XSIZE; x++)
4973 for (y = 0; y < MAX_BUF_YSIZE; y++)
4976 redraw_mask = REDRAW_ALL;
4979 static void InitLevelInfo()
4981 LoadLevelInfo(); /* global level info */
4982 LoadLevelSetup_LastSeries(); /* last played series info */
4983 LoadLevelSetup_SeriesInfo(); /* last played level info */
4986 void InitLevelArtworkInfo()
4988 LoadLevelArtworkInfo();
4991 static void InitImages()
4993 setLevelArtworkDir(artwork.gfx_first);
4996 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
4997 leveldir_current->identifier,
4998 artwork.gfx_current_identifier,
4999 artwork.gfx_current->identifier,
5000 leveldir_current->graphics_set,
5001 leveldir_current->graphics_path);
5004 ReloadCustomImages();
5006 LoadCustomElementDescriptions();
5007 LoadSpecialMenuDesignSettings();
5009 ReinitializeGraphics();
5012 static void InitSound(char *identifier)
5014 if (identifier == NULL)
5015 identifier = artwork.snd_current->identifier;
5017 /* set artwork path to send it to the sound server process */
5018 setLevelArtworkDir(artwork.snd_first);
5020 InitReloadCustomSounds(identifier);
5021 ReinitializeSounds();
5024 static void InitMusic(char *identifier)
5026 if (identifier == NULL)
5027 identifier = artwork.mus_current->identifier;
5029 /* set artwork path to send it to the sound server process */
5030 setLevelArtworkDir(artwork.mus_first);
5032 InitReloadCustomMusic(identifier);
5033 ReinitializeMusic();
5036 void InitNetworkServer()
5038 #if defined(NETWORK_AVALIABLE)
5042 if (!options.network)
5045 #if defined(NETWORK_AVALIABLE)
5046 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5048 if (!ConnectToServer(options.server_host, options.server_port))
5049 Error(ERR_EXIT, "cannot connect to network game server");
5051 SendToServer_PlayerName(setup.player_name);
5052 SendToServer_ProtocolVersion();
5055 SendToServer_NrWanted(nr_wanted);
5059 static char *getNewArtworkIdentifier(int type)
5061 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5062 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5063 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5064 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5065 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5066 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
5067 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5068 char *leveldir_identifier = leveldir_current->identifier;
5070 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
5071 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5073 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
5075 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5076 char *artwork_current_identifier;
5077 char *artwork_new_identifier = NULL; /* default: nothing has changed */
5079 /* leveldir_current may be invalid (level group, parent link) */
5080 if (!validLevelSeries(leveldir_current))
5083 /* 1st step: determine artwork set to be activated in descending order:
5084 --------------------------------------------------------------------
5085 1. setup artwork (when configured to override everything else)
5086 2. artwork set configured in "levelinfo.conf" of current level set
5087 (artwork in level directory will have priority when loading later)
5088 3. artwork in level directory (stored in artwork sub-directory)
5089 4. setup artwork (currently configured in setup menu) */
5091 if (setup_override_artwork)
5092 artwork_current_identifier = setup_artwork_set;
5093 else if (leveldir_artwork_set != NULL)
5094 artwork_current_identifier = leveldir_artwork_set;
5095 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5096 artwork_current_identifier = leveldir_identifier;
5098 artwork_current_identifier = setup_artwork_set;
5101 /* 2nd step: check if it is really needed to reload artwork set
5102 ------------------------------------------------------------ */
5105 if (type == ARTWORK_TYPE_GRAPHICS)
5106 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
5107 artwork_new_identifier,
5108 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5109 artwork_current_identifier,
5110 leveldir_current->graphics_set,
5111 leveldir_current->identifier);
5114 /* ---------- reload if level set and also artwork set has changed ------- */
5115 if (leveldir_current_identifier[type] != leveldir_identifier &&
5116 (last_has_level_artwork_set[type] || has_level_artwork_set))
5117 artwork_new_identifier = artwork_current_identifier;
5119 leveldir_current_identifier[type] = leveldir_identifier;
5120 last_has_level_artwork_set[type] = has_level_artwork_set;
5123 if (type == ARTWORK_TYPE_GRAPHICS)
5124 printf("::: 1: '%s'\n", artwork_new_identifier);
5127 /* ---------- reload if "override artwork" setting has changed ----------- */
5128 if (last_override_level_artwork[type] != setup_override_artwork)
5129 artwork_new_identifier = artwork_current_identifier;
5131 last_override_level_artwork[type] = setup_override_artwork;
5134 if (type == ARTWORK_TYPE_GRAPHICS)
5135 printf("::: 2: '%s'\n", artwork_new_identifier);
5138 /* ---------- reload if current artwork identifier has changed ----------- */
5139 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5140 artwork_current_identifier))
5141 artwork_new_identifier = artwork_current_identifier;
5143 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5146 if (type == ARTWORK_TYPE_GRAPHICS)
5147 printf("::: 3: '%s'\n", artwork_new_identifier);
5150 /* ---------- do not reload directly after starting ---------------------- */
5151 if (!initialized[type])
5152 artwork_new_identifier = NULL;
5154 initialized[type] = TRUE;
5157 if (type == ARTWORK_TYPE_GRAPHICS)
5158 printf("::: 4: '%s'\n", artwork_new_identifier);
5162 if (type == ARTWORK_TYPE_GRAPHICS)
5163 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
5164 artwork.gfx_current_identifier, artwork_current_identifier,
5165 artwork.gfx_current->identifier, leveldir_current->graphics_set,
5166 artwork_new_identifier);
5169 return artwork_new_identifier;
5172 void ReloadCustomArtwork(int force_reload)
5174 char *gfx_new_identifier;
5175 char *snd_new_identifier;
5176 char *mus_new_identifier;
5177 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5178 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5179 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5180 boolean redraw_screen = FALSE;
5182 force_reload_gfx |= AdjustGraphicsForEMC();
5184 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5185 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5186 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5188 if (gfx_new_identifier != NULL || force_reload_gfx)
5191 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5192 artwork.gfx_current_identifier,
5194 artwork.gfx_current->identifier,
5195 leveldir_current->graphics_set);
5198 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
5202 redraw_screen = TRUE;
5205 if (snd_new_identifier != NULL || force_reload_snd)
5207 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
5209 InitSound(snd_new_identifier);
5211 redraw_screen = TRUE;
5214 if (mus_new_identifier != NULL || force_reload_mus)
5216 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
5218 InitMusic(mus_new_identifier);
5220 redraw_screen = TRUE;
5227 /* force redraw of (open or closed) door graphics */
5228 SetDoorState(DOOR_OPEN_ALL);
5229 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5233 FadeSetEnterScreen();
5234 // FadeSkipNextFadeOut();
5235 // FadeSetDisabled();
5240 fading = fading_none;
5245 void KeyboardAutoRepeatOffUnlessAutoplay()
5247 if (global.autoplay_leveldir == NULL)
5248 KeyboardAutoRepeatOff();
5252 /* ========================================================================= */
5254 /* ========================================================================= */
5258 InitGlobal(); /* initialize some global variables */
5260 if (options.execute_command)
5261 Execute_Command(options.execute_command);
5263 if (options.serveronly)
5265 #if defined(PLATFORM_UNIX)
5266 NetworkServer(options.server_port, options.serveronly);
5268 Error(ERR_WARN, "networking only supported in Unix version");
5271 exit(0); /* never reached, server loops forever */
5278 InitArtworkInfo(); /* needed before loading gfx, sound & music */
5279 InitArtworkConfig(); /* needed before forking sound child process */
5284 InitRND(NEW_RANDOMIZE);
5285 InitSimpleRandom(NEW_RANDOMIZE);
5290 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
5292 InitEventFilter(FilterMouseMotionEvents);
5294 InitElementPropertiesStatic();
5295 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5299 // debug_print_timestamp(0, "INIT");
5301 // debug_print_timestamp(0, "TIME InitLevelInfo: ");
5302 InitLevelArtworkInfo();
5303 // debug_print_timestamp(0, "TIME InitLevelArtworkInfo: ");
5305 InitImages(); /* needs to know current level directory */
5306 InitSound(NULL); /* needs to know current level directory */
5307 InitMusic(NULL); /* needs to know current level directory */
5309 InitGfxBackground();
5315 if (global.autoplay_leveldir)
5320 else if (global.convert_leveldir)
5326 game_status = GAME_MODE_MAIN;
5329 FadeSetEnterScreen();
5330 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
5331 FadeSkipNextFadeOut();
5332 // FadeSetDisabled();
5334 fading = fading_none;
5339 InitNetworkServer();
5342 void CloseAllAndExit(int exit_value)
5347 CloseAudio(); /* called after freeing sounds (needed for SDL) */
5355 #if defined(TARGET_SDL)
5356 if (network_server) /* terminate network server */
5357 SDL_KillThread(server_thread);
5360 CloseVideoDisplay();
5361 ClosePlatformDependentStuff();
5363 if (exit_value != 0)
5364 NotifyUserAboutErrorFile();