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 */
37 #define CONFIG_TOKEN_FONT_INITIAL "font.initial"
40 static struct FontBitmapInfo font_initial[NUM_INITIAL_FONTS];
42 static int copy_properties[][5] =
46 EL_BUG_LEFT, EL_BUG_RIGHT,
47 EL_BUG_UP, EL_BUG_DOWN
51 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
52 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
56 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
57 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
61 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
62 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
66 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
67 EL_PACMAN_UP, EL_PACMAN_DOWN
71 EL_YAMYAM_LEFT, EL_YAMYAM_RIGHT,
72 EL_YAMYAM_UP, EL_YAMYAM_DOWN
76 EL_MOLE_LEFT, EL_MOLE_RIGHT,
77 EL_MOLE_UP, EL_MOLE_DOWN
87 FreeLevelEditorGadgets();
96 static boolean gadgets_initialized = FALSE;
98 if (gadgets_initialized)
101 CreateLevelEditorGadgets();
105 CreateScreenGadgets();
107 InitGadgetsSoundCallback(PlaySoundActivating, PlaySoundSelecting);
109 gadgets_initialized = TRUE;
112 inline void InitElementSmallImagesScaledUp(int graphic)
114 CreateImageWithSmallImages(graphic, graphic_info[graphic].scale_up_factor);
117 void InitElementSmallImages()
119 static int special_graphics[] =
121 IMG_EDITOR_ELEMENT_BORDER,
122 IMG_EDITOR_ELEMENT_BORDER_INPUT,
123 IMG_EDITOR_CASCADE_LIST,
124 IMG_EDITOR_CASCADE_LIST_ACTIVE,
127 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
128 int num_property_mappings = getImageListPropertyMappingSize();
131 /* initialize normal images from static configuration */
132 for (i = 0; element_to_graphic[i].element > -1; i++)
133 InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
135 /* initialize special images from static configuration */
136 for (i = 0; element_to_special_graphic[i].element > -1; i++)
137 InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
139 /* initialize images from dynamic configuration (may be elements or other) */
140 for (i = 0; i < num_property_mappings; i++)
141 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
143 /* initialize special images from above list (non-element images) */
144 for (i = 0; special_graphics[i] > -1; i++)
145 InitElementSmallImagesScaledUp(special_graphics[i]);
148 void InitScaledImages()
152 /* scale normal images from static configuration, if not already scaled */
153 for (i = 0; i < NUM_IMAGE_FILES; i++)
154 ScaleImage(i, graphic_info[i].scale_up_factor);
158 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
159 void SetBitmaps_EM(Bitmap **em_bitmap)
161 em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
162 em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].bitmap;
166 static int getFontBitmapID(int font_nr)
170 if (game_status >= GAME_MODE_TITLE_INITIAL &&
171 game_status <= GAME_MODE_PSEUDO_PREVIEW)
172 special = game_status;
173 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
174 special = GFX_SPECIAL_ARG_MAIN;
176 else if (game_status == GAME_MODE_PLAYING)
177 special = GFX_SPECIAL_ARG_DOOR;
181 return font_info[font_nr].special_bitmap_id[special];
186 void InitFontGraphicInfo()
188 static struct FontBitmapInfo *font_bitmap_info = NULL;
189 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
190 int num_property_mappings = getImageListPropertyMappingSize();
191 int num_font_bitmaps = NUM_FONTS;
194 if (graphic_info == NULL) /* still at startup phase */
196 InitFontInfo(font_initial, NUM_INITIAL_FONTS, getFontBitmapID);
201 /* ---------- initialize font graphic definitions ---------- */
203 /* always start with reliable default values (normal font graphics) */
204 for (i = 0; i < NUM_FONTS; i++)
205 font_info[i].graphic = IMG_FONT_INITIAL_1;
207 /* initialize normal font/graphic mapping from static configuration */
208 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
210 int font_nr = font_to_graphic[i].font_nr;
211 int special = font_to_graphic[i].special;
212 int graphic = font_to_graphic[i].graphic;
217 font_info[font_nr].graphic = graphic;
220 /* always start with reliable default values (special font graphics) */
221 for (i = 0; i < NUM_FONTS; i++)
223 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
225 font_info[i].special_graphic[j] = font_info[i].graphic;
226 font_info[i].special_bitmap_id[j] = i;
230 /* initialize special font/graphic mapping from static configuration */
231 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
233 int font_nr = font_to_graphic[i].font_nr;
234 int special = font_to_graphic[i].special;
235 int graphic = font_to_graphic[i].graphic;
236 int base_graphic = font2baseimg(font_nr);
238 if (IS_SPECIAL_GFX_ARG(special))
240 boolean base_redefined =
241 getImageListEntryFromImageID(base_graphic)->redefined;
242 boolean special_redefined =
243 getImageListEntryFromImageID(graphic)->redefined;
244 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
246 /* if the base font ("font.title_1", for example) has been redefined,
247 but not the special font ("font.title_1.LEVELS", for example), do not
248 use an existing (in this case considered obsolete) special font
249 anymore, but use the automatically determined default font */
250 /* special case: cloned special fonts must be explicitly redefined,
251 but are not automatically redefined by redefining base font */
252 if (base_redefined && !special_redefined && !special_cloned)
255 font_info[font_nr].special_graphic[special] = graphic;
256 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
261 /* initialize special font/graphic mapping from dynamic configuration */
262 for (i = 0; i < num_property_mappings; i++)
264 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
265 int special = property_mapping[i].ext3_index;
266 int graphic = property_mapping[i].artwork_index;
271 if (IS_SPECIAL_GFX_ARG(special))
273 font_info[font_nr].special_graphic[special] = graphic;
274 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
279 /* correct special font/graphic mapping for cloned fonts for downwards
280 compatibility of PREVIEW fonts -- this is only needed for implicit
281 redefinition of special font by redefined base font, and only if other
282 fonts are cloned from this special font (like in the "Zelda" level set) */
283 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
285 int font_nr = font_to_graphic[i].font_nr;
286 int special = font_to_graphic[i].special;
287 int graphic = font_to_graphic[i].graphic;
289 if (IS_SPECIAL_GFX_ARG(special))
291 boolean special_redefined =
292 getImageListEntryFromImageID(graphic)->redefined;
293 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
295 if (special_cloned && !special_redefined)
299 for (j = 0; font_to_graphic[j].font_nr > -1; j++)
301 int font_nr2 = font_to_graphic[j].font_nr;
302 int special2 = font_to_graphic[j].special;
303 int graphic2 = font_to_graphic[j].graphic;
305 if (IS_SPECIAL_GFX_ARG(special2) &&
306 graphic2 == graphic_info[graphic].clone_from)
308 font_info[font_nr].special_graphic[special] =
309 font_info[font_nr2].special_graphic[special2];
310 font_info[font_nr].special_bitmap_id[special] =
311 font_info[font_nr2].special_bitmap_id[special2];
318 /* reset non-redefined ".active" font graphics if normal font is redefined */
319 /* (this different treatment is needed because normal and active fonts are
320 independently defined ("active" is not a property of font definitions!) */
321 for (i = 0; i < NUM_FONTS; i++)
323 int font_nr_base = i;
324 int font_nr_active = FONT_ACTIVE(font_nr_base);
326 /* check only those fonts with exist as normal and ".active" variant */
327 if (font_nr_base != font_nr_active)
329 int base_graphic = font_info[font_nr_base].graphic;
330 int active_graphic = font_info[font_nr_active].graphic;
331 boolean base_redefined =
332 getImageListEntryFromImageID(base_graphic)->redefined;
333 boolean active_redefined =
334 getImageListEntryFromImageID(active_graphic)->redefined;
336 /* if the base font ("font.menu_1", for example) has been redefined,
337 but not the active font ("font.menu_1.active", for example), do not
338 use an existing (in this case considered obsolete) active font
339 anymore, but use the automatically determined default font */
340 if (base_redefined && !active_redefined)
341 font_info[font_nr_active].graphic = base_graphic;
343 /* now also check each "special" font (which may be the same as above) */
344 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
346 int base_graphic = font_info[font_nr_base].special_graphic[j];
347 int active_graphic = font_info[font_nr_active].special_graphic[j];
348 boolean base_redefined =
349 getImageListEntryFromImageID(base_graphic)->redefined;
350 boolean active_redefined =
351 getImageListEntryFromImageID(active_graphic)->redefined;
353 /* same as above, but check special graphic definitions, for example:
354 redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN" */
355 if (base_redefined && !active_redefined)
357 font_info[font_nr_active].special_graphic[j] =
358 font_info[font_nr_base].special_graphic[j];
359 font_info[font_nr_active].special_bitmap_id[j] =
360 font_info[font_nr_base].special_bitmap_id[j];
366 /* ---------- initialize font bitmap array ---------- */
368 if (font_bitmap_info != NULL)
369 FreeFontInfo(font_bitmap_info);
372 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
374 /* ---------- initialize font bitmap definitions ---------- */
376 for (i = 0; i < NUM_FONTS; i++)
378 if (i < NUM_INITIAL_FONTS)
380 font_bitmap_info[i] = font_initial[i];
384 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
386 int font_bitmap_id = font_info[i].special_bitmap_id[j];
387 int graphic = font_info[i].special_graphic[j];
389 /* set 'graphic_info' for font entries, if uninitialized (guessed) */
390 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
392 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
393 graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
396 /* copy font relevant information from graphics information */
397 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
398 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
399 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
400 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
401 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
403 font_bitmap_info[font_bitmap_id].draw_xoffset =
404 graphic_info[graphic].draw_xoffset;
405 font_bitmap_info[font_bitmap_id].draw_yoffset =
406 graphic_info[graphic].draw_yoffset;
408 font_bitmap_info[font_bitmap_id].num_chars =
409 graphic_info[graphic].anim_frames;
410 font_bitmap_info[font_bitmap_id].num_chars_per_line =
411 graphic_info[graphic].anim_frames_per_line;
415 InitFontInfo(font_bitmap_info, num_font_bitmaps, getFontBitmapID);
418 void InitElementGraphicInfo()
420 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
421 int num_property_mappings = getImageListPropertyMappingSize();
424 if (graphic_info == NULL) /* still at startup phase */
427 /* set values to -1 to identify later as "uninitialized" values */
428 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
430 for (act = 0; act < NUM_ACTIONS; act++)
432 element_info[i].graphic[act] = -1;
433 element_info[i].crumbled[act] = -1;
435 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
437 element_info[i].direction_graphic[act][dir] = -1;
438 element_info[i].direction_crumbled[act][dir] = -1;
443 /* initialize normal element/graphic mapping from static configuration */
444 for (i = 0; element_to_graphic[i].element > -1; i++)
446 int element = element_to_graphic[i].element;
447 int action = element_to_graphic[i].action;
448 int direction = element_to_graphic[i].direction;
449 boolean crumbled = element_to_graphic[i].crumbled;
450 int graphic = element_to_graphic[i].graphic;
451 int base_graphic = el2baseimg(element);
453 if (graphic_info[graphic].bitmap == NULL)
456 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
459 boolean base_redefined =
460 getImageListEntryFromImageID(base_graphic)->redefined;
461 boolean act_dir_redefined =
462 getImageListEntryFromImageID(graphic)->redefined;
464 /* if the base graphic ("emerald", for example) has been redefined,
465 but not the action graphic ("emerald.falling", for example), do not
466 use an existing (in this case considered obsolete) action graphic
467 anymore, but use the automatically determined default graphic */
468 if (base_redefined && !act_dir_redefined)
473 action = ACTION_DEFAULT;
478 element_info[element].direction_crumbled[action][direction] = graphic;
480 element_info[element].crumbled[action] = graphic;
485 element_info[element].direction_graphic[action][direction] = graphic;
487 element_info[element].graphic[action] = graphic;
491 /* initialize normal element/graphic mapping from dynamic configuration */
492 for (i = 0; i < num_property_mappings; i++)
494 int element = property_mapping[i].base_index;
495 int action = property_mapping[i].ext1_index;
496 int direction = property_mapping[i].ext2_index;
497 int special = property_mapping[i].ext3_index;
498 int graphic = property_mapping[i].artwork_index;
499 boolean crumbled = FALSE;
501 if (special == GFX_SPECIAL_ARG_CRUMBLED)
507 if (graphic_info[graphic].bitmap == NULL)
510 if (element >= MAX_NUM_ELEMENTS || special != -1)
514 action = ACTION_DEFAULT;
519 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
520 element_info[element].direction_crumbled[action][dir] = -1;
523 element_info[element].direction_crumbled[action][direction] = graphic;
525 element_info[element].crumbled[action] = graphic;
530 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
531 element_info[element].direction_graphic[action][dir] = -1;
534 element_info[element].direction_graphic[action][direction] = graphic;
536 element_info[element].graphic[action] = graphic;
540 /* now copy all graphics that are defined to be cloned from other graphics */
541 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
543 int graphic = element_info[i].graphic[ACTION_DEFAULT];
544 int crumbled_like, diggable_like;
549 crumbled_like = graphic_info[graphic].crumbled_like;
550 diggable_like = graphic_info[graphic].diggable_like;
552 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
554 for (act = 0; act < NUM_ACTIONS; act++)
555 element_info[i].crumbled[act] =
556 element_info[crumbled_like].crumbled[act];
557 for (act = 0; act < NUM_ACTIONS; act++)
558 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
559 element_info[i].direction_crumbled[act][dir] =
560 element_info[crumbled_like].direction_crumbled[act][dir];
563 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
565 element_info[i].graphic[ACTION_DIGGING] =
566 element_info[diggable_like].graphic[ACTION_DIGGING];
567 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
568 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
569 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
574 /* set hardcoded definitions for some runtime elements without graphic */
575 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
579 /* set hardcoded definitions for some internal elements without graphic */
580 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
582 if (IS_EDITOR_CASCADE_INACTIVE(i))
583 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
584 else if (IS_EDITOR_CASCADE_ACTIVE(i))
585 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
589 /* now set all undefined/invalid graphics to -1 to set to default after it */
590 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
592 for (act = 0; act < NUM_ACTIONS; act++)
596 graphic = element_info[i].graphic[act];
597 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
598 element_info[i].graphic[act] = -1;
600 graphic = element_info[i].crumbled[act];
601 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
602 element_info[i].crumbled[act] = -1;
604 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
606 graphic = element_info[i].direction_graphic[act][dir];
607 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
608 element_info[i].direction_graphic[act][dir] = -1;
610 graphic = element_info[i].direction_crumbled[act][dir];
611 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
612 element_info[i].direction_crumbled[act][dir] = -1;
617 /* adjust graphics with 2nd tile for movement according to direction
618 (do this before correcting '-1' values to minimize calculations) */
619 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
621 for (act = 0; act < NUM_ACTIONS; act++)
623 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
625 int graphic = element_info[i].direction_graphic[act][dir];
626 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
628 if (act == ACTION_FALLING) /* special case */
629 graphic = element_info[i].graphic[act];
632 graphic_info[graphic].double_movement &&
633 graphic_info[graphic].swap_double_tiles != 0)
635 struct GraphicInfo *g = &graphic_info[graphic];
636 int src_x_front = g->src_x;
637 int src_y_front = g->src_y;
638 int src_x_back = g->src_x + g->offset2_x;
639 int src_y_back = g->src_y + g->offset2_y;
640 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
642 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
643 src_y_front < src_y_back);
644 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
645 boolean swap_movement_tiles_autodetected =
646 (!frames_are_ordered_diagonally &&
647 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
648 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
649 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
650 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
653 /* swap frontside and backside graphic tile coordinates, if needed */
654 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
656 /* get current (wrong) backside tile coordinates */
657 getGraphicSourceExt(graphic, 0, &dummy, &src_x_back, &src_y_back,
660 /* set frontside tile coordinates to backside tile coordinates */
661 g->src_x = src_x_back;
662 g->src_y = src_y_back;
664 /* invert tile offset to point to new backside tile coordinates */
668 /* do not swap front and backside tiles again after correction */
669 g->swap_double_tiles = 0;
676 /* now set all '-1' values to element specific default values */
677 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
679 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
680 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
681 int default_direction_graphic[NUM_DIRECTIONS_FULL];
682 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
684 if (default_graphic == -1)
685 default_graphic = IMG_UNKNOWN;
687 if (default_crumbled == -1)
688 default_crumbled = default_graphic;
690 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
691 if (default_crumbled == -1)
692 default_crumbled = IMG_EMPTY;
695 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
697 default_direction_graphic[dir] =
698 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
699 default_direction_crumbled[dir] =
700 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
702 if (default_direction_graphic[dir] == -1)
703 default_direction_graphic[dir] = default_graphic;
705 if (default_direction_crumbled[dir] == -1)
706 default_direction_crumbled[dir] = default_direction_graphic[dir];
708 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
709 if (default_direction_crumbled[dir] == -1)
710 default_direction_crumbled[dir] = default_crumbled;
714 for (act = 0; act < NUM_ACTIONS; act++)
716 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
717 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
718 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
719 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
720 act == ACTION_TURNING_FROM_RIGHT ||
721 act == ACTION_TURNING_FROM_UP ||
722 act == ACTION_TURNING_FROM_DOWN);
724 /* generic default action graphic (defined by "[default]" directive) */
725 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
726 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
727 int default_remove_graphic = IMG_EMPTY;
729 if (act_remove && default_action_graphic != -1)
730 default_remove_graphic = default_action_graphic;
732 /* look for special default action graphic (classic game specific) */
733 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
734 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
735 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
736 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
737 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
738 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
740 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
741 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
742 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
743 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
744 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
745 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
748 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
749 /* !!! make this better !!! */
750 if (i == EL_EMPTY_SPACE)
752 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
753 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
757 if (default_action_graphic == -1)
758 default_action_graphic = default_graphic;
760 if (default_action_crumbled == -1)
761 default_action_crumbled = default_action_graphic;
763 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
764 if (default_action_crumbled == -1)
765 default_action_crumbled = default_crumbled;
768 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
770 /* use action graphic as the default direction graphic, if undefined */
771 int default_action_direction_graphic = element_info[i].graphic[act];
772 int default_action_direction_crumbled = element_info[i].crumbled[act];
774 /* no graphic for current action -- use default direction graphic */
775 if (default_action_direction_graphic == -1)
776 default_action_direction_graphic =
777 (act_remove ? default_remove_graphic :
779 element_info[i].direction_graphic[ACTION_TURNING][dir] :
780 default_action_graphic != default_graphic ?
781 default_action_graphic :
782 default_direction_graphic[dir]);
784 if (element_info[i].direction_graphic[act][dir] == -1)
785 element_info[i].direction_graphic[act][dir] =
786 default_action_direction_graphic;
789 if (default_action_direction_crumbled == -1)
790 default_action_direction_crumbled =
791 element_info[i].direction_graphic[act][dir];
793 if (default_action_direction_crumbled == -1)
794 default_action_direction_crumbled =
795 (act_remove ? default_remove_graphic :
797 element_info[i].direction_crumbled[ACTION_TURNING][dir] :
798 default_action_crumbled != default_crumbled ?
799 default_action_crumbled :
800 default_direction_crumbled[dir]);
803 if (element_info[i].direction_crumbled[act][dir] == -1)
804 element_info[i].direction_crumbled[act][dir] =
805 default_action_direction_crumbled;
808 /* no graphic for this specific action -- use default action graphic */
809 if (element_info[i].graphic[act] == -1)
810 element_info[i].graphic[act] =
811 (act_remove ? default_remove_graphic :
812 act_turning ? element_info[i].graphic[ACTION_TURNING] :
813 default_action_graphic);
815 if (element_info[i].crumbled[act] == -1)
816 element_info[i].crumbled[act] = element_info[i].graphic[act];
818 if (element_info[i].crumbled[act] == -1)
819 element_info[i].crumbled[act] =
820 (act_remove ? default_remove_graphic :
821 act_turning ? element_info[i].crumbled[ACTION_TURNING] :
822 default_action_crumbled);
828 /* !!! THIS ALSO CLEARS SPECIAL FLAGS (AND IS NOT NEEDED ANYWAY) !!! */
829 /* set animation mode to "none" for each graphic with only 1 frame */
830 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
832 for (act = 0; act < NUM_ACTIONS; act++)
834 int graphic = element_info[i].graphic[act];
835 int crumbled = element_info[i].crumbled[act];
837 if (graphic_info[graphic].anim_frames == 1)
838 graphic_info[graphic].anim_mode = ANIM_NONE;
839 if (graphic_info[crumbled].anim_frames == 1)
840 graphic_info[crumbled].anim_mode = ANIM_NONE;
842 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
844 graphic = element_info[i].direction_graphic[act][dir];
845 crumbled = element_info[i].direction_crumbled[act][dir];
847 if (graphic_info[graphic].anim_frames == 1)
848 graphic_info[graphic].anim_mode = ANIM_NONE;
849 if (graphic_info[crumbled].anim_frames == 1)
850 graphic_info[crumbled].anim_mode = ANIM_NONE;
860 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
861 if (element_info[i].graphic[ACTION_DEFAULT] == IMG_UNKNOWN &&
863 Error(ERR_INFO, "warning: no graphic for element '%s' (%d)",
864 element_info[i].token_name, i);
870 void InitElementSpecialGraphicInfo()
872 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
873 int num_property_mappings = getImageListPropertyMappingSize();
876 /* always start with reliable default values */
877 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
878 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
879 element_info[i].special_graphic[j] =
880 element_info[i].graphic[ACTION_DEFAULT];
882 /* initialize special element/graphic mapping from static configuration */
883 for (i = 0; element_to_special_graphic[i].element > -1; i++)
885 int element = element_to_special_graphic[i].element;
886 int special = element_to_special_graphic[i].special;
887 int graphic = element_to_special_graphic[i].graphic;
888 int base_graphic = el2baseimg(element);
889 boolean base_redefined =
890 getImageListEntryFromImageID(base_graphic)->redefined;
891 boolean special_redefined =
892 getImageListEntryFromImageID(graphic)->redefined;
894 /* if the base graphic ("emerald", for example) has been redefined,
895 but not the special graphic ("emerald.EDITOR", for example), do not
896 use an existing (in this case considered obsolete) special graphic
897 anymore, but use the automatically created (down-scaled) graphic */
898 if (base_redefined && !special_redefined)
901 element_info[element].special_graphic[special] = graphic;
904 /* initialize special element/graphic mapping from dynamic configuration */
905 for (i = 0; i < num_property_mappings; i++)
907 int element = property_mapping[i].base_index;
908 int special = property_mapping[i].ext3_index;
909 int graphic = property_mapping[i].artwork_index;
911 if (element >= MAX_NUM_ELEMENTS)
914 if (IS_SPECIAL_GFX_ARG(special))
915 element_info[element].special_graphic[special] = graphic;
918 /* now set all undefined/invalid graphics to default */
919 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
920 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
921 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
922 element_info[i].special_graphic[j] =
923 element_info[i].graphic[ACTION_DEFAULT];
926 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
931 if (type != TYPE_TOKEN)
932 return get_parameter_value(value_raw, suffix, type);
934 if (strEqual(value_raw, ARG_UNDEFINED))
935 return ARG_UNDEFINED_VALUE;
937 /* !!! OPTIMIZE THIS BY USING HASH !!! */
938 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
939 if (strEqual(element_info[i].token_name, value_raw))
942 /* !!! OPTIMIZE THIS BY USING HASH !!! */
943 for (i = 0; image_config[i].token != NULL; i++)
945 int len_config_value = strlen(image_config[i].value);
947 if (!strEqual(&image_config[i].value[len_config_value - 4], ".pcx") &&
948 !strEqual(&image_config[i].value[len_config_value - 4], ".wav") &&
949 !strEqual(image_config[i].value, UNDEFINED_FILENAME))
952 if (strEqual(image_config[i].token, value_raw))
961 static int get_scaled_graphic_width(int graphic)
963 int original_width = getOriginalImageWidthFromImageID(graphic);
964 int scale_up_factor = graphic_info[graphic].scale_up_factor;
966 return original_width * scale_up_factor;
969 static int get_scaled_graphic_height(int graphic)
971 int original_height = getOriginalImageHeightFromImageID(graphic);
972 int scale_up_factor = graphic_info[graphic].scale_up_factor;
974 return original_height * scale_up_factor;
977 static void set_graphic_parameters(int graphic)
979 struct FileInfo *image = getImageListEntryFromImageID(graphic);
980 char **parameter_raw = image->parameter;
981 Bitmap *src_bitmap = getBitmapFromImageID(graphic);
982 int parameter[NUM_GFX_ARGS];
983 int anim_frames_per_row = 1, anim_frames_per_col = 1;
984 int anim_frames_per_line = 1;
987 /* if fallback to default artwork is done, also use the default parameters */
988 if (image->fallback_to_default)
989 parameter_raw = image->default_parameter;
991 /* get integer values from string parameters */
992 for (i = 0; i < NUM_GFX_ARGS; i++)
993 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
994 image_config_suffix[i].token,
995 image_config_suffix[i].type);
997 graphic_info[graphic].bitmap = src_bitmap;
999 /* always start with reliable default values */
1000 graphic_info[graphic].src_image_width = 0;
1001 graphic_info[graphic].src_image_height = 0;
1002 graphic_info[graphic].src_x = 0;
1003 graphic_info[graphic].src_y = 0;
1004 graphic_info[graphic].width = TILEX; /* default for element graphics */
1005 graphic_info[graphic].height = TILEY; /* default for element graphics */
1006 graphic_info[graphic].offset_x = 0; /* one or both of these values ... */
1007 graphic_info[graphic].offset_y = 0; /* ... will be corrected later */
1008 graphic_info[graphic].offset2_x = 0; /* one or both of these values ... */
1009 graphic_info[graphic].offset2_y = 0; /* ... will be corrected later */
1010 graphic_info[graphic].swap_double_tiles = -1; /* auto-detect tile swapping */
1011 graphic_info[graphic].crumbled_like = -1; /* do not use clone element */
1012 graphic_info[graphic].diggable_like = -1; /* do not use clone element */
1013 graphic_info[graphic].border_size = TILEX / 8; /* "CRUMBLED" border size */
1014 graphic_info[graphic].scale_up_factor = 1; /* default: no scaling up */
1015 graphic_info[graphic].clone_from = -1; /* do not use clone graphic */
1016 graphic_info[graphic].anim_delay_fixed = 0;
1017 graphic_info[graphic].anim_delay_random = 0;
1018 graphic_info[graphic].post_delay_fixed = 0;
1019 graphic_info[graphic].post_delay_random = 0;
1020 graphic_info[graphic].fade_delay = -1;
1021 graphic_info[graphic].post_delay = -1;
1022 graphic_info[graphic].auto_delay = -1;
1023 graphic_info[graphic].align = ALIGN_CENTER; /* default for title screens */
1024 graphic_info[graphic].valign = VALIGN_MIDDLE; /* default for title screens */
1025 graphic_info[graphic].sort_priority = 0; /* default for title screens */
1028 /* optional zoom factor for scaling up the image to a larger size */
1029 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1030 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1031 if (graphic_info[graphic].scale_up_factor < 1)
1032 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
1036 if (graphic_info[graphic].use_image_size)
1038 /* set new default bitmap size (with scaling, but without small images) */
1039 graphic_info[graphic].width = get_scaled_graphic_width(graphic);
1040 graphic_info[graphic].height = get_scaled_graphic_height(graphic);
1044 /* optional x and y tile position of animation frame sequence */
1045 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1046 graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
1047 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1048 graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
1050 /* optional x and y pixel position of animation frame sequence */
1051 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1052 graphic_info[graphic].src_x = parameter[GFX_ARG_X];
1053 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1054 graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
1056 /* optional width and height of each animation frame */
1057 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1058 graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
1059 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1060 graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
1063 /* optional zoom factor for scaling up the image to a larger size */
1064 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1065 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1066 if (graphic_info[graphic].scale_up_factor < 1)
1067 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
1072 /* get final bitmap size (with scaling, but without small images) */
1073 int src_image_width = get_scaled_graphic_width(graphic);
1074 int src_image_height = get_scaled_graphic_height(graphic);
1076 anim_frames_per_row = src_image_width / graphic_info[graphic].width;
1077 anim_frames_per_col = src_image_height / graphic_info[graphic].height;
1079 graphic_info[graphic].src_image_width = src_image_width;
1080 graphic_info[graphic].src_image_height = src_image_height;
1083 /* correct x or y offset dependent of vertical or horizontal frame order */
1084 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1086 graphic_info[graphic].offset_y =
1087 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1088 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
1089 anim_frames_per_line = anim_frames_per_col;
1091 else /* frames are ordered horizontally */
1093 graphic_info[graphic].offset_x =
1094 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1095 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
1096 anim_frames_per_line = anim_frames_per_row;
1099 /* optionally, the x and y offset of frames can be specified directly */
1100 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1101 graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
1102 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1103 graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
1105 /* optionally, moving animations may have separate start and end graphics */
1106 graphic_info[graphic].double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1108 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1109 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1111 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1112 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1113 graphic_info[graphic].offset2_y =
1114 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1115 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].height);
1116 else /* frames are ordered horizontally */
1117 graphic_info[graphic].offset2_x =
1118 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1119 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].width);
1121 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1122 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1123 graphic_info[graphic].offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1124 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1125 graphic_info[graphic].offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1127 /* optionally, the second movement tile can be specified as start tile */
1128 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1129 graphic_info[graphic].swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1131 /* automatically determine correct number of frames, if not defined */
1132 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1133 graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
1134 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1135 graphic_info[graphic].anim_frames = anim_frames_per_row;
1136 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1137 graphic_info[graphic].anim_frames = anim_frames_per_col;
1139 graphic_info[graphic].anim_frames = 1;
1141 if (graphic_info[graphic].anim_frames == 0) /* frames must be at least 1 */
1142 graphic_info[graphic].anim_frames = 1;
1144 graphic_info[graphic].anim_frames_per_line =
1145 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1146 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1148 graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
1149 if (graphic_info[graphic].anim_delay == 0) /* delay must be at least 1 */
1150 graphic_info[graphic].anim_delay = 1;
1152 graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
1154 if (graphic_info[graphic].anim_frames == 1)
1155 graphic_info[graphic].anim_mode = ANIM_NONE;
1158 /* automatically determine correct start frame, if not defined */
1159 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1160 graphic_info[graphic].anim_start_frame = 0;
1161 else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
1162 graphic_info[graphic].anim_start_frame =
1163 graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1165 graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
1167 /* animation synchronized with global frame counter, not move position */
1168 graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1170 /* optional element for cloning crumble graphics */
1171 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1172 graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1174 /* optional element for cloning digging graphics */
1175 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1176 graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1178 /* optional border size for "crumbling" diggable graphics */
1179 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1180 graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
1182 /* this is only used for player "boring" and "sleeping" actions */
1183 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1184 graphic_info[graphic].anim_delay_fixed =
1185 parameter[GFX_ARG_ANIM_DELAY_FIXED];
1186 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1187 graphic_info[graphic].anim_delay_random =
1188 parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1189 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1190 graphic_info[graphic].post_delay_fixed =
1191 parameter[GFX_ARG_POST_DELAY_FIXED];
1192 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1193 graphic_info[graphic].post_delay_random =
1194 parameter[GFX_ARG_POST_DELAY_RANDOM];
1196 /* this is only used for toon animations */
1197 graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
1198 graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY];
1200 /* this is only used for drawing font characters */
1201 graphic_info[graphic].draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1202 graphic_info[graphic].draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1204 /* this is only used for drawing envelope graphics */
1205 graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1207 /* optional graphic for cloning all graphics settings */
1208 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1209 graphic_info[graphic].clone_from = parameter[GFX_ARG_CLONE_FROM];
1211 /* optional settings for drawing title screens */
1212 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1213 graphic_info[graphic].fade_delay = parameter[GFX_ARG_FADE_DELAY];
1214 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1215 graphic_info[graphic].post_delay = parameter[GFX_ARG_POST_DELAY];
1216 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1217 graphic_info[graphic].auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1218 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1219 graphic_info[graphic].align = parameter[GFX_ARG_ALIGN];
1220 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1221 graphic_info[graphic].valign = parameter[GFX_ARG_VALIGN];
1222 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1223 graphic_info[graphic].sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1226 static void set_cloned_graphic_parameters(int graphic)
1228 int fallback_graphic = IMG_CHAR_EXCLAM;
1229 int max_num_images = getImageListSize();
1230 int clone_graphic = graphic_info[graphic].clone_from;
1231 int num_references_followed = 1;
1233 while (graphic_info[clone_graphic].clone_from != -1 &&
1234 num_references_followed < max_num_images)
1236 clone_graphic = graphic_info[clone_graphic].clone_from;
1238 num_references_followed++;
1241 if (num_references_followed >= max_num_images)
1243 Error(ERR_INFO_LINE, "-");
1244 Error(ERR_INFO, "warning: error found in config file:");
1245 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1246 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1247 Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1248 Error(ERR_INFO, "custom graphic rejected for this element/action");
1250 if (graphic == fallback_graphic)
1251 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1253 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1254 Error(ERR_INFO_LINE, "-");
1256 graphic_info[graphic] = graphic_info[fallback_graphic];
1260 graphic_info[graphic] = graphic_info[clone_graphic];
1261 graphic_info[graphic].clone_from = clone_graphic;
1265 static void InitGraphicInfo()
1267 int fallback_graphic = IMG_CHAR_EXCLAM;
1268 int num_images = getImageListSize();
1271 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1272 static boolean clipmasks_initialized = FALSE;
1274 XGCValues clip_gc_values;
1275 unsigned long clip_gc_valuemask;
1276 GC copy_clipmask_gc = None;
1279 /* use image size as default values for width and height for these images */
1280 static int full_size_graphics[] =
1285 IMG_BACKGROUND_ENVELOPE_1,
1286 IMG_BACKGROUND_ENVELOPE_2,
1287 IMG_BACKGROUND_ENVELOPE_3,
1288 IMG_BACKGROUND_ENVELOPE_4,
1291 IMG_BACKGROUND_TITLE_INITIAL,
1292 IMG_BACKGROUND_TITLE,
1293 IMG_BACKGROUND_MESSAGE_INITIAL,
1294 IMG_BACKGROUND_MESSAGE,
1295 IMG_BACKGROUND_MAIN,
1296 IMG_BACKGROUND_LEVELS,
1297 IMG_BACKGROUND_SCORES,
1298 IMG_BACKGROUND_EDITOR,
1299 IMG_BACKGROUND_INFO,
1300 IMG_BACKGROUND_INFO_ELEMENTS,
1301 IMG_BACKGROUND_INFO_MUSIC,
1302 IMG_BACKGROUND_INFO_CREDITS,
1303 IMG_BACKGROUND_INFO_PROGRAM,
1304 IMG_BACKGROUND_INFO_LEVELSET,
1305 IMG_BACKGROUND_SETUP,
1306 IMG_BACKGROUND_DOOR,
1308 IMG_TITLESCREEN_INITIAL_1,
1309 IMG_TITLESCREEN_INITIAL_2,
1310 IMG_TITLESCREEN_INITIAL_3,
1311 IMG_TITLESCREEN_INITIAL_4,
1312 IMG_TITLESCREEN_INITIAL_5,
1322 checked_free(graphic_info);
1324 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1327 /* initialize "use_image_size" flag with default value */
1328 for (i = 0; i < num_images; i++)
1329 graphic_info[i].use_image_size = FALSE;
1331 /* initialize "use_image_size" flag from static configuration above */
1332 for (i = 0; full_size_graphics[i] != -1; i++)
1333 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1336 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1337 if (clipmasks_initialized)
1339 for (i = 0; i < num_images; i++)
1341 if (graphic_info[i].clip_mask)
1342 XFreePixmap(display, graphic_info[i].clip_mask);
1343 if (graphic_info[i].clip_gc)
1344 XFreeGC(display, graphic_info[i].clip_gc);
1346 graphic_info[i].clip_mask = None;
1347 graphic_info[i].clip_gc = None;
1352 /* first set all graphic paramaters ... */
1353 for (i = 0; i < num_images; i++)
1354 set_graphic_parameters(i);
1356 /* ... then copy these parameters for cloned graphics */
1357 for (i = 0; i < num_images; i++)
1358 if (graphic_info[i].clone_from != -1)
1359 set_cloned_graphic_parameters(i);
1361 for (i = 0; i < num_images; i++)
1366 int first_frame, last_frame;
1367 int src_bitmap_width, src_bitmap_height;
1369 /* now check if no animation frames are outside of the loaded image */
1371 if (graphic_info[i].bitmap == NULL)
1372 continue; /* skip check for optional images that are undefined */
1374 /* get image size (this can differ from the standard element tile size!) */
1375 width = graphic_info[i].width;
1376 height = graphic_info[i].height;
1378 /* get final bitmap size (with scaling, but without small images) */
1379 src_bitmap_width = graphic_info[i].src_image_width;
1380 src_bitmap_height = graphic_info[i].src_image_height;
1382 /* check if first animation frame is inside specified bitmap */
1385 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1388 /* this avoids calculating wrong start position for out-of-bounds frame */
1389 src_x = graphic_info[i].src_x;
1390 src_y = graphic_info[i].src_y;
1393 if (src_x < 0 || src_y < 0 ||
1394 src_x + width > src_bitmap_width ||
1395 src_y + height > src_bitmap_height)
1397 Error(ERR_INFO_LINE, "-");
1398 Error(ERR_INFO, "warning: error found in config file:");
1399 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1400 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1401 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1403 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1404 src_x, src_y, src_bitmap_width, src_bitmap_height);
1405 Error(ERR_INFO, "custom graphic rejected for this element/action");
1407 if (i == fallback_graphic)
1408 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1410 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1411 Error(ERR_INFO_LINE, "-");
1413 graphic_info[i] = graphic_info[fallback_graphic];
1416 /* check if last animation frame is inside specified bitmap */
1418 last_frame = graphic_info[i].anim_frames - 1;
1419 getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1421 if (src_x < 0 || src_y < 0 ||
1422 src_x + width > src_bitmap_width ||
1423 src_y + height > src_bitmap_height)
1425 Error(ERR_INFO_LINE, "-");
1426 Error(ERR_INFO, "warning: error found in config file:");
1427 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1428 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1429 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1431 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1432 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1433 Error(ERR_INFO, "custom graphic rejected for this element/action");
1435 if (i == fallback_graphic)
1436 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1438 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1439 Error(ERR_INFO_LINE, "-");
1441 graphic_info[i] = graphic_info[fallback_graphic];
1444 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1445 /* currently we only need a tile clip mask from the first frame */
1446 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1448 if (copy_clipmask_gc == None)
1450 clip_gc_values.graphics_exposures = False;
1451 clip_gc_valuemask = GCGraphicsExposures;
1452 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
1453 clip_gc_valuemask, &clip_gc_values);
1456 graphic_info[i].clip_mask =
1457 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
1459 src_pixmap = src_bitmap->clip_mask;
1460 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
1461 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
1463 clip_gc_values.graphics_exposures = False;
1464 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
1465 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
1467 graphic_info[i].clip_gc =
1468 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
1472 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1473 if (copy_clipmask_gc)
1474 XFreeGC(display, copy_clipmask_gc);
1476 clipmasks_initialized = TRUE;
1480 static void InitElementSoundInfo()
1482 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1483 int num_property_mappings = getSoundListPropertyMappingSize();
1486 /* set values to -1 to identify later as "uninitialized" values */
1487 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1488 for (act = 0; act < NUM_ACTIONS; act++)
1489 element_info[i].sound[act] = -1;
1491 /* initialize element/sound mapping from static configuration */
1492 for (i = 0; element_to_sound[i].element > -1; i++)
1494 int element = element_to_sound[i].element;
1495 int action = element_to_sound[i].action;
1496 int sound = element_to_sound[i].sound;
1497 boolean is_class = element_to_sound[i].is_class;
1500 action = ACTION_DEFAULT;
1503 element_info[element].sound[action] = sound;
1505 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1506 if (strEqual(element_info[j].class_name,
1507 element_info[element].class_name))
1508 element_info[j].sound[action] = sound;
1511 /* initialize element class/sound mapping from dynamic configuration */
1512 for (i = 0; i < num_property_mappings; i++)
1514 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1515 int action = property_mapping[i].ext1_index;
1516 int sound = property_mapping[i].artwork_index;
1518 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1522 action = ACTION_DEFAULT;
1524 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1525 if (strEqual(element_info[j].class_name,
1526 element_info[element_class].class_name))
1527 element_info[j].sound[action] = sound;
1530 /* initialize element/sound mapping from dynamic configuration */
1531 for (i = 0; i < num_property_mappings; i++)
1533 int element = property_mapping[i].base_index;
1534 int action = property_mapping[i].ext1_index;
1535 int sound = property_mapping[i].artwork_index;
1537 if (element >= MAX_NUM_ELEMENTS)
1541 action = ACTION_DEFAULT;
1543 element_info[element].sound[action] = sound;
1546 /* now set all '-1' values to element specific default values */
1547 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1549 for (act = 0; act < NUM_ACTIONS; act++)
1551 /* generic default action sound (defined by "[default]" directive) */
1552 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1554 /* look for special default action sound (classic game specific) */
1555 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1556 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1557 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1558 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1559 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1560 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1562 /* !!! there's no such thing as a "default action sound" !!! */
1564 /* look for element specific default sound (independent from action) */
1565 if (element_info[i].sound[ACTION_DEFAULT] != -1)
1566 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
1570 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1571 /* !!! make this better !!! */
1572 if (i == EL_EMPTY_SPACE)
1573 default_action_sound = element_info[EL_DEFAULT].sound[act];
1576 /* no sound for this specific action -- use default action sound */
1577 if (element_info[i].sound[act] == -1)
1578 element_info[i].sound[act] = default_action_sound;
1582 /* copy sound settings to some elements that are only stored in level file
1583 in native R'n'D levels, but are used by game engine in native EM levels */
1584 for (i = 0; copy_properties[i][0] != -1; i++)
1585 for (j = 1; j <= 4; j++)
1586 for (act = 0; act < NUM_ACTIONS; act++)
1587 element_info[copy_properties[i][j]].sound[act] =
1588 element_info[copy_properties[i][0]].sound[act];
1591 static void InitGameModeSoundInfo()
1595 /* set values to -1 to identify later as "uninitialized" values */
1596 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1599 /* initialize gamemode/sound mapping from static configuration */
1600 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1602 int gamemode = gamemode_to_sound[i].gamemode;
1603 int sound = gamemode_to_sound[i].sound;
1606 gamemode = GAME_MODE_DEFAULT;
1608 menu.sound[gamemode] = sound;
1611 /* now set all '-1' values to levelset specific default values */
1612 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1613 if (menu.sound[i] == -1)
1614 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1617 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1618 if (menu.sound[i] != -1)
1619 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
1623 static void set_sound_parameters(int sound, char **parameter_raw)
1625 int parameter[NUM_SND_ARGS];
1628 /* get integer values from string parameters */
1629 for (i = 0; i < NUM_SND_ARGS; i++)
1631 get_parameter_value(parameter_raw[i],
1632 sound_config_suffix[i].token,
1633 sound_config_suffix[i].type);
1635 /* explicit loop mode setting in configuration overrides default value */
1636 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1637 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1639 /* sound volume to change the original volume when loading the sound file */
1640 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1642 /* sound priority to give certain sounds a higher or lower priority */
1643 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
1646 static void InitSoundInfo()
1648 int *sound_effect_properties;
1649 int num_sounds = getSoundListSize();
1652 checked_free(sound_info);
1654 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1655 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1657 /* initialize sound effect for all elements to "no sound" */
1658 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1659 for (j = 0; j < NUM_ACTIONS; j++)
1660 element_info[i].sound[j] = SND_UNDEFINED;
1662 for (i = 0; i < num_sounds; i++)
1664 struct FileInfo *sound = getSoundListEntry(i);
1665 int len_effect_text = strlen(sound->token);
1667 sound_effect_properties[i] = ACTION_OTHER;
1668 sound_info[i].loop = FALSE; /* default: play sound only once */
1671 printf("::: sound %d: '%s'\n", i, sound->token);
1674 /* determine all loop sounds and identify certain sound classes */
1676 for (j = 0; element_action_info[j].suffix; j++)
1678 int len_action_text = strlen(element_action_info[j].suffix);
1680 if (len_action_text < len_effect_text &&
1681 strEqual(&sound->token[len_effect_text - len_action_text],
1682 element_action_info[j].suffix))
1684 sound_effect_properties[i] = element_action_info[j].value;
1685 sound_info[i].loop = element_action_info[j].is_loop_sound;
1691 /* associate elements and some selected sound actions */
1693 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1695 if (element_info[j].class_name)
1697 int len_class_text = strlen(element_info[j].class_name);
1699 if (len_class_text + 1 < len_effect_text &&
1700 strncmp(sound->token,
1701 element_info[j].class_name, len_class_text) == 0 &&
1702 sound->token[len_class_text] == '.')
1704 int sound_action_value = sound_effect_properties[i];
1706 element_info[j].sound[sound_action_value] = i;
1711 set_sound_parameters(i, sound->parameter);
1714 free(sound_effect_properties);
1717 static void InitGameModeMusicInfo()
1719 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1720 int num_property_mappings = getMusicListPropertyMappingSize();
1721 int default_levelset_music = -1;
1724 /* set values to -1 to identify later as "uninitialized" values */
1725 for (i = 0; i < MAX_LEVELS; i++)
1726 levelset.music[i] = -1;
1727 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1730 /* initialize gamemode/music mapping from static configuration */
1731 for (i = 0; gamemode_to_music[i].music > -1; i++)
1733 int gamemode = gamemode_to_music[i].gamemode;
1734 int music = gamemode_to_music[i].music;
1737 printf("::: gamemode == %d, music == %d\n", gamemode, music);
1741 gamemode = GAME_MODE_DEFAULT;
1743 menu.music[gamemode] = music;
1746 /* initialize gamemode/music mapping from dynamic configuration */
1747 for (i = 0; i < num_property_mappings; i++)
1749 int prefix = property_mapping[i].base_index;
1750 int gamemode = property_mapping[i].ext1_index;
1751 int level = property_mapping[i].ext2_index;
1752 int music = property_mapping[i].artwork_index;
1755 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
1756 prefix, gamemode, level, music);
1759 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1763 gamemode = GAME_MODE_DEFAULT;
1765 /* level specific music only allowed for in-game music */
1766 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1767 gamemode = GAME_MODE_PLAYING;
1772 default_levelset_music = music;
1775 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1776 levelset.music[level] = music;
1777 if (gamemode != GAME_MODE_PLAYING)
1778 menu.music[gamemode] = music;
1781 /* now set all '-1' values to menu specific default values */
1782 /* (undefined values of "levelset.music[]" might stay at "-1" to
1783 allow dynamic selection of music files from music directory!) */
1784 for (i = 0; i < MAX_LEVELS; i++)
1785 if (levelset.music[i] == -1)
1786 levelset.music[i] = default_levelset_music;
1787 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1788 if (menu.music[i] == -1)
1789 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1792 for (i = 0; i < MAX_LEVELS; i++)
1793 if (levelset.music[i] != -1)
1794 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
1795 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1796 if (menu.music[i] != -1)
1797 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
1801 static void set_music_parameters(int music, char **parameter_raw)
1803 int parameter[NUM_MUS_ARGS];
1806 /* get integer values from string parameters */
1807 for (i = 0; i < NUM_MUS_ARGS; i++)
1809 get_parameter_value(parameter_raw[i],
1810 music_config_suffix[i].token,
1811 music_config_suffix[i].type);
1813 /* explicit loop mode setting in configuration overrides default value */
1814 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1815 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1818 static void InitMusicInfo()
1820 int num_music = getMusicListSize();
1823 checked_free(music_info);
1825 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1827 for (i = 0; i < num_music; i++)
1829 struct FileInfo *music = getMusicListEntry(i);
1830 int len_music_text = strlen(music->token);
1832 music_info[i].loop = TRUE; /* default: play music in loop mode */
1834 /* determine all loop music */
1836 for (j = 0; music_prefix_info[j].prefix; j++)
1838 int len_prefix_text = strlen(music_prefix_info[j].prefix);
1840 if (len_prefix_text < len_music_text &&
1841 strncmp(music->token,
1842 music_prefix_info[j].prefix, len_prefix_text) == 0)
1844 music_info[i].loop = music_prefix_info[j].is_loop_music;
1850 set_music_parameters(i, music->parameter);
1854 static void ReinitializeGraphics()
1856 InitGraphicInfo(); /* graphic properties mapping */
1857 InitElementGraphicInfo(); /* element game graphic mapping */
1858 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
1860 InitElementSmallImages(); /* scale elements to all needed sizes */
1861 InitScaledImages(); /* scale all other images, if needed */
1862 InitFontGraphicInfo(); /* initialize text drawing functions */
1864 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
1866 SetMainBackgroundImage(IMG_BACKGROUND);
1867 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1873 static void ReinitializeSounds()
1875 InitSoundInfo(); /* sound properties mapping */
1876 InitElementSoundInfo(); /* element game sound mapping */
1877 InitGameModeSoundInfo(); /* game mode sound mapping */
1879 InitPlayLevelSound(); /* internal game sound settings */
1882 static void ReinitializeMusic()
1884 InitMusicInfo(); /* music properties mapping */
1885 InitGameModeMusicInfo(); /* game mode music mapping */
1888 static int get_special_property_bit(int element, int property_bit_nr)
1890 struct PropertyBitInfo
1896 static struct PropertyBitInfo pb_can_move_into_acid[] =
1898 /* the player may be able fall into acid when gravity is activated */
1903 { EL_SP_MURPHY, 0 },
1904 { EL_SOKOBAN_FIELD_PLAYER, 0 },
1906 /* all elements that can move may be able to also move into acid */
1909 { EL_BUG_RIGHT, 1 },
1912 { EL_SPACESHIP, 2 },
1913 { EL_SPACESHIP_LEFT, 2 },
1914 { EL_SPACESHIP_RIGHT, 2 },
1915 { EL_SPACESHIP_UP, 2 },
1916 { EL_SPACESHIP_DOWN, 2 },
1917 { EL_BD_BUTTERFLY, 3 },
1918 { EL_BD_BUTTERFLY_LEFT, 3 },
1919 { EL_BD_BUTTERFLY_RIGHT, 3 },
1920 { EL_BD_BUTTERFLY_UP, 3 },
1921 { EL_BD_BUTTERFLY_DOWN, 3 },
1922 { EL_BD_FIREFLY, 4 },
1923 { EL_BD_FIREFLY_LEFT, 4 },
1924 { EL_BD_FIREFLY_RIGHT, 4 },
1925 { EL_BD_FIREFLY_UP, 4 },
1926 { EL_BD_FIREFLY_DOWN, 4 },
1928 { EL_YAMYAM_LEFT, 5 },
1929 { EL_YAMYAM_RIGHT, 5 },
1930 { EL_YAMYAM_UP, 5 },
1931 { EL_YAMYAM_DOWN, 5 },
1932 { EL_DARK_YAMYAM, 6 },
1935 { EL_PACMAN_LEFT, 8 },
1936 { EL_PACMAN_RIGHT, 8 },
1937 { EL_PACMAN_UP, 8 },
1938 { EL_PACMAN_DOWN, 8 },
1940 { EL_MOLE_LEFT, 9 },
1941 { EL_MOLE_RIGHT, 9 },
1943 { EL_MOLE_DOWN, 9 },
1947 { EL_SATELLITE, 13 },
1948 { EL_SP_SNIKSNAK, 14 },
1949 { EL_SP_ELECTRON, 15 },
1952 { EL_EMC_ANDROID, 18 },
1957 static struct PropertyBitInfo pb_dont_collide_with[] =
1959 { EL_SP_SNIKSNAK, 0 },
1960 { EL_SP_ELECTRON, 1 },
1968 struct PropertyBitInfo *pb_info;
1971 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
1972 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
1977 struct PropertyBitInfo *pb_info = NULL;
1980 for (i = 0; pb_definition[i].bit_nr != -1; i++)
1981 if (pb_definition[i].bit_nr == property_bit_nr)
1982 pb_info = pb_definition[i].pb_info;
1984 if (pb_info == NULL)
1987 for (i = 0; pb_info[i].element != -1; i++)
1988 if (pb_info[i].element == element)
1989 return pb_info[i].bit_nr;
1994 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
1995 boolean property_value)
1997 int bit_nr = get_special_property_bit(element, property_bit_nr);
2002 *bitfield |= (1 << bit_nr);
2004 *bitfield &= ~(1 << bit_nr);
2008 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2010 int bit_nr = get_special_property_bit(element, property_bit_nr);
2013 return ((*bitfield & (1 << bit_nr)) != 0);
2018 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2020 static int group_nr;
2021 static struct ElementGroupInfo *group;
2022 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2025 if (actual_group == NULL) /* not yet initialized */
2028 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
2030 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2031 group_element - EL_GROUP_START + 1);
2033 /* replace element which caused too deep recursion by question mark */
2034 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2039 if (recursion_depth == 0) /* initialization */
2041 group = actual_group;
2042 group_nr = GROUP_NR(group_element);
2044 group->num_elements_resolved = 0;
2045 group->choice_pos = 0;
2047 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2048 element_info[i].in_group[group_nr] = FALSE;
2051 for (i = 0; i < actual_group->num_elements; i++)
2053 int element = actual_group->element[i];
2055 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2058 if (IS_GROUP_ELEMENT(element))
2059 ResolveGroupElementExt(element, recursion_depth + 1);
2062 group->element_resolved[group->num_elements_resolved++] = element;
2063 element_info[element].in_group[group_nr] = TRUE;
2068 void ResolveGroupElement(int group_element)
2070 ResolveGroupElementExt(group_element, 0);
2073 void InitElementPropertiesStatic()
2075 static int ep_diggable[] =
2080 EL_SP_BUGGY_BASE_ACTIVATING,
2083 EL_INVISIBLE_SAND_ACTIVE,
2086 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2087 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2092 EL_SP_BUGGY_BASE_ACTIVE,
2099 static int ep_collectible_only[] =
2121 EL_DYNABOMB_INCREASE_NUMBER,
2122 EL_DYNABOMB_INCREASE_SIZE,
2123 EL_DYNABOMB_INCREASE_POWER,
2141 /* !!! handle separately !!! */
2142 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2148 static int ep_dont_run_into[] =
2150 /* same elements as in 'ep_dont_touch' */
2156 /* same elements as in 'ep_dont_collide_with' */
2168 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2173 EL_SP_BUGGY_BASE_ACTIVE,
2180 static int ep_dont_collide_with[] =
2182 /* same elements as in 'ep_dont_touch' */
2199 static int ep_dont_touch[] =
2209 static int ep_indestructible[] =
2213 EL_ACID_POOL_TOPLEFT,
2214 EL_ACID_POOL_TOPRIGHT,
2215 EL_ACID_POOL_BOTTOMLEFT,
2216 EL_ACID_POOL_BOTTOM,
2217 EL_ACID_POOL_BOTTOMRIGHT,
2218 EL_SP_HARDWARE_GRAY,
2219 EL_SP_HARDWARE_GREEN,
2220 EL_SP_HARDWARE_BLUE,
2222 EL_SP_HARDWARE_YELLOW,
2223 EL_SP_HARDWARE_BASE_1,
2224 EL_SP_HARDWARE_BASE_2,
2225 EL_SP_HARDWARE_BASE_3,
2226 EL_SP_HARDWARE_BASE_4,
2227 EL_SP_HARDWARE_BASE_5,
2228 EL_SP_HARDWARE_BASE_6,
2229 EL_INVISIBLE_STEELWALL,
2230 EL_INVISIBLE_STEELWALL_ACTIVE,
2231 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2232 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2233 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2234 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2235 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2236 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2237 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2238 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2239 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2240 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2241 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2242 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2244 EL_LIGHT_SWITCH_ACTIVE,
2245 EL_SIGN_EXCLAMATION,
2246 EL_SIGN_RADIOACTIVITY,
2253 EL_SIGN_ENTRY_FORBIDDEN,
2254 EL_SIGN_EMERGENCY_EXIT,
2262 EL_STEEL_EXIT_CLOSED,
2264 EL_EM_STEEL_EXIT_CLOSED,
2265 EL_EM_STEEL_EXIT_OPEN,
2266 EL_DC_STEELWALL_1_LEFT,
2267 EL_DC_STEELWALL_1_RIGHT,
2268 EL_DC_STEELWALL_1_TOP,
2269 EL_DC_STEELWALL_1_BOTTOM,
2270 EL_DC_STEELWALL_1_HORIZONTAL,
2271 EL_DC_STEELWALL_1_VERTICAL,
2272 EL_DC_STEELWALL_1_TOPLEFT,
2273 EL_DC_STEELWALL_1_TOPRIGHT,
2274 EL_DC_STEELWALL_1_BOTTOMLEFT,
2275 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2276 EL_DC_STEELWALL_1_TOPLEFT_2,
2277 EL_DC_STEELWALL_1_TOPRIGHT_2,
2278 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2279 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2280 EL_DC_STEELWALL_2_LEFT,
2281 EL_DC_STEELWALL_2_RIGHT,
2282 EL_DC_STEELWALL_2_TOP,
2283 EL_DC_STEELWALL_2_BOTTOM,
2284 EL_DC_STEELWALL_2_HORIZONTAL,
2285 EL_DC_STEELWALL_2_VERTICAL,
2286 EL_DC_STEELWALL_2_MIDDLE,
2287 EL_DC_STEELWALL_2_SINGLE,
2288 EL_STEELWALL_SLIPPERY,
2302 EL_GATE_1_GRAY_ACTIVE,
2303 EL_GATE_2_GRAY_ACTIVE,
2304 EL_GATE_3_GRAY_ACTIVE,
2305 EL_GATE_4_GRAY_ACTIVE,
2314 EL_EM_GATE_1_GRAY_ACTIVE,
2315 EL_EM_GATE_2_GRAY_ACTIVE,
2316 EL_EM_GATE_3_GRAY_ACTIVE,
2317 EL_EM_GATE_4_GRAY_ACTIVE,
2326 EL_EMC_GATE_5_GRAY_ACTIVE,
2327 EL_EMC_GATE_6_GRAY_ACTIVE,
2328 EL_EMC_GATE_7_GRAY_ACTIVE,
2329 EL_EMC_GATE_8_GRAY_ACTIVE,
2331 EL_DC_GATE_WHITE_GRAY,
2332 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2333 EL_DC_GATE_FAKE_GRAY,
2335 EL_SWITCHGATE_OPENING,
2336 EL_SWITCHGATE_CLOSED,
2337 EL_SWITCHGATE_CLOSING,
2339 EL_DC_SWITCHGATE_SWITCH_UP,
2340 EL_DC_SWITCHGATE_SWITCH_DOWN,
2343 EL_TIMEGATE_OPENING,
2345 EL_TIMEGATE_CLOSING,
2347 EL_DC_TIMEGATE_SWITCH,
2348 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2353 EL_TUBE_VERTICAL_LEFT,
2354 EL_TUBE_VERTICAL_RIGHT,
2355 EL_TUBE_HORIZONTAL_UP,
2356 EL_TUBE_HORIZONTAL_DOWN,
2361 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2362 EL_EXPANDABLE_STEELWALL_VERTICAL,
2363 EL_EXPANDABLE_STEELWALL_ANY,
2368 static int ep_slippery[] =
2382 EL_ROBOT_WHEEL_ACTIVE,
2388 EL_ACID_POOL_TOPLEFT,
2389 EL_ACID_POOL_TOPRIGHT,
2399 EL_STEELWALL_SLIPPERY,
2402 EL_EMC_WALL_SLIPPERY_1,
2403 EL_EMC_WALL_SLIPPERY_2,
2404 EL_EMC_WALL_SLIPPERY_3,
2405 EL_EMC_WALL_SLIPPERY_4,
2407 EL_EMC_MAGIC_BALL_ACTIVE,
2412 static int ep_can_change[] =
2417 static int ep_can_move[] =
2419 /* same elements as in 'pb_can_move_into_acid' */
2442 static int ep_can_fall[] =
2456 EL_QUICKSAND_FAST_FULL,
2458 EL_BD_MAGIC_WALL_FULL,
2459 EL_DC_MAGIC_WALL_FULL,
2473 static int ep_can_smash_player[] =
2499 static int ep_can_smash_enemies[] =
2508 static int ep_can_smash_everything[] =
2517 static int ep_explodes_by_fire[] =
2519 /* same elements as in 'ep_explodes_impact' */
2524 /* same elements as in 'ep_explodes_smashed' */
2534 EL_EM_DYNAMITE_ACTIVE,
2535 EL_DYNABOMB_PLAYER_1_ACTIVE,
2536 EL_DYNABOMB_PLAYER_2_ACTIVE,
2537 EL_DYNABOMB_PLAYER_3_ACTIVE,
2538 EL_DYNABOMB_PLAYER_4_ACTIVE,
2539 EL_DYNABOMB_INCREASE_NUMBER,
2540 EL_DYNABOMB_INCREASE_SIZE,
2541 EL_DYNABOMB_INCREASE_POWER,
2542 EL_SP_DISK_RED_ACTIVE,
2556 static int ep_explodes_smashed[] =
2558 /* same elements as in 'ep_explodes_impact' */
2572 static int ep_explodes_impact[] =
2581 static int ep_walkable_over[] =
2585 EL_SOKOBAN_FIELD_EMPTY,
2591 EL_EM_STEEL_EXIT_OPEN,
2600 EL_GATE_1_GRAY_ACTIVE,
2601 EL_GATE_2_GRAY_ACTIVE,
2602 EL_GATE_3_GRAY_ACTIVE,
2603 EL_GATE_4_GRAY_ACTIVE,
2611 static int ep_walkable_inside[] =
2616 EL_TUBE_VERTICAL_LEFT,
2617 EL_TUBE_VERTICAL_RIGHT,
2618 EL_TUBE_HORIZONTAL_UP,
2619 EL_TUBE_HORIZONTAL_DOWN,
2628 static int ep_walkable_under[] =
2633 static int ep_passable_over[] =
2643 EL_EM_GATE_1_GRAY_ACTIVE,
2644 EL_EM_GATE_2_GRAY_ACTIVE,
2645 EL_EM_GATE_3_GRAY_ACTIVE,
2646 EL_EM_GATE_4_GRAY_ACTIVE,
2655 EL_EMC_GATE_5_GRAY_ACTIVE,
2656 EL_EMC_GATE_6_GRAY_ACTIVE,
2657 EL_EMC_GATE_7_GRAY_ACTIVE,
2658 EL_EMC_GATE_8_GRAY_ACTIVE,
2660 EL_DC_GATE_WHITE_GRAY,
2661 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2668 static int ep_passable_inside[] =
2674 EL_SP_PORT_HORIZONTAL,
2675 EL_SP_PORT_VERTICAL,
2677 EL_SP_GRAVITY_PORT_LEFT,
2678 EL_SP_GRAVITY_PORT_RIGHT,
2679 EL_SP_GRAVITY_PORT_UP,
2680 EL_SP_GRAVITY_PORT_DOWN,
2681 EL_SP_GRAVITY_ON_PORT_LEFT,
2682 EL_SP_GRAVITY_ON_PORT_RIGHT,
2683 EL_SP_GRAVITY_ON_PORT_UP,
2684 EL_SP_GRAVITY_ON_PORT_DOWN,
2685 EL_SP_GRAVITY_OFF_PORT_LEFT,
2686 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2687 EL_SP_GRAVITY_OFF_PORT_UP,
2688 EL_SP_GRAVITY_OFF_PORT_DOWN,
2693 static int ep_passable_under[] =
2698 static int ep_droppable[] =
2703 static int ep_explodes_1x1_old[] =
2708 static int ep_pushable[] =
2720 EL_SOKOBAN_FIELD_FULL,
2729 static int ep_explodes_cross_old[] =
2734 static int ep_protected[] =
2736 /* same elements as in 'ep_walkable_inside' */
2740 EL_TUBE_VERTICAL_LEFT,
2741 EL_TUBE_VERTICAL_RIGHT,
2742 EL_TUBE_HORIZONTAL_UP,
2743 EL_TUBE_HORIZONTAL_DOWN,
2749 /* same elements as in 'ep_passable_over' */
2758 EL_EM_GATE_1_GRAY_ACTIVE,
2759 EL_EM_GATE_2_GRAY_ACTIVE,
2760 EL_EM_GATE_3_GRAY_ACTIVE,
2761 EL_EM_GATE_4_GRAY_ACTIVE,
2770 EL_EMC_GATE_5_GRAY_ACTIVE,
2771 EL_EMC_GATE_6_GRAY_ACTIVE,
2772 EL_EMC_GATE_7_GRAY_ACTIVE,
2773 EL_EMC_GATE_8_GRAY_ACTIVE,
2775 EL_DC_GATE_WHITE_GRAY,
2776 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2780 /* same elements as in 'ep_passable_inside' */
2785 EL_SP_PORT_HORIZONTAL,
2786 EL_SP_PORT_VERTICAL,
2788 EL_SP_GRAVITY_PORT_LEFT,
2789 EL_SP_GRAVITY_PORT_RIGHT,
2790 EL_SP_GRAVITY_PORT_UP,
2791 EL_SP_GRAVITY_PORT_DOWN,
2792 EL_SP_GRAVITY_ON_PORT_LEFT,
2793 EL_SP_GRAVITY_ON_PORT_RIGHT,
2794 EL_SP_GRAVITY_ON_PORT_UP,
2795 EL_SP_GRAVITY_ON_PORT_DOWN,
2796 EL_SP_GRAVITY_OFF_PORT_LEFT,
2797 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2798 EL_SP_GRAVITY_OFF_PORT_UP,
2799 EL_SP_GRAVITY_OFF_PORT_DOWN,
2804 static int ep_throwable[] =
2809 static int ep_can_explode[] =
2811 /* same elements as in 'ep_explodes_impact' */
2816 /* same elements as in 'ep_explodes_smashed' */
2822 /* elements that can explode by explosion or by dragonfire */
2826 EL_EM_DYNAMITE_ACTIVE,
2827 EL_DYNABOMB_PLAYER_1_ACTIVE,
2828 EL_DYNABOMB_PLAYER_2_ACTIVE,
2829 EL_DYNABOMB_PLAYER_3_ACTIVE,
2830 EL_DYNABOMB_PLAYER_4_ACTIVE,
2831 EL_DYNABOMB_INCREASE_NUMBER,
2832 EL_DYNABOMB_INCREASE_SIZE,
2833 EL_DYNABOMB_INCREASE_POWER,
2834 EL_SP_DISK_RED_ACTIVE,
2842 /* elements that can explode only by explosion */
2848 static int ep_gravity_reachable[] =
2854 EL_INVISIBLE_SAND_ACTIVE,
2859 EL_SP_PORT_HORIZONTAL,
2860 EL_SP_PORT_VERTICAL,
2862 EL_SP_GRAVITY_PORT_LEFT,
2863 EL_SP_GRAVITY_PORT_RIGHT,
2864 EL_SP_GRAVITY_PORT_UP,
2865 EL_SP_GRAVITY_PORT_DOWN,
2866 EL_SP_GRAVITY_ON_PORT_LEFT,
2867 EL_SP_GRAVITY_ON_PORT_RIGHT,
2868 EL_SP_GRAVITY_ON_PORT_UP,
2869 EL_SP_GRAVITY_ON_PORT_DOWN,
2870 EL_SP_GRAVITY_OFF_PORT_LEFT,
2871 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2872 EL_SP_GRAVITY_OFF_PORT_UP,
2873 EL_SP_GRAVITY_OFF_PORT_DOWN,
2879 static int ep_player[] =
2886 EL_SOKOBAN_FIELD_PLAYER,
2892 static int ep_can_pass_magic_wall[] =
2906 static int ep_can_pass_dc_magic_wall[] =
2922 static int ep_switchable[] =
2926 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2927 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2928 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2929 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2930 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2931 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2932 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2933 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2934 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2935 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2936 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2937 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2938 EL_SWITCHGATE_SWITCH_UP,
2939 EL_SWITCHGATE_SWITCH_DOWN,
2940 EL_DC_SWITCHGATE_SWITCH_UP,
2941 EL_DC_SWITCHGATE_SWITCH_DOWN,
2943 EL_LIGHT_SWITCH_ACTIVE,
2945 EL_DC_TIMEGATE_SWITCH,
2946 EL_BALLOON_SWITCH_LEFT,
2947 EL_BALLOON_SWITCH_RIGHT,
2948 EL_BALLOON_SWITCH_UP,
2949 EL_BALLOON_SWITCH_DOWN,
2950 EL_BALLOON_SWITCH_ANY,
2951 EL_BALLOON_SWITCH_NONE,
2954 EL_EMC_MAGIC_BALL_SWITCH,
2955 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
2960 static int ep_bd_element[] =
2994 static int ep_sp_element[] =
2996 /* should always be valid */
2999 /* standard classic Supaplex elements */
3006 EL_SP_HARDWARE_GRAY,
3014 EL_SP_GRAVITY_PORT_RIGHT,
3015 EL_SP_GRAVITY_PORT_DOWN,
3016 EL_SP_GRAVITY_PORT_LEFT,
3017 EL_SP_GRAVITY_PORT_UP,
3022 EL_SP_PORT_VERTICAL,
3023 EL_SP_PORT_HORIZONTAL,
3029 EL_SP_HARDWARE_BASE_1,
3030 EL_SP_HARDWARE_GREEN,
3031 EL_SP_HARDWARE_BLUE,
3033 EL_SP_HARDWARE_YELLOW,
3034 EL_SP_HARDWARE_BASE_2,
3035 EL_SP_HARDWARE_BASE_3,
3036 EL_SP_HARDWARE_BASE_4,
3037 EL_SP_HARDWARE_BASE_5,
3038 EL_SP_HARDWARE_BASE_6,
3042 /* additional elements that appeared in newer Supaplex levels */
3045 /* additional gravity port elements (not switching, but setting gravity) */
3046 EL_SP_GRAVITY_ON_PORT_LEFT,
3047 EL_SP_GRAVITY_ON_PORT_RIGHT,
3048 EL_SP_GRAVITY_ON_PORT_UP,
3049 EL_SP_GRAVITY_ON_PORT_DOWN,
3050 EL_SP_GRAVITY_OFF_PORT_LEFT,
3051 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3052 EL_SP_GRAVITY_OFF_PORT_UP,
3053 EL_SP_GRAVITY_OFF_PORT_DOWN,
3055 /* more than one Murphy in a level results in an inactive clone */
3058 /* runtime Supaplex elements */
3059 EL_SP_DISK_RED_ACTIVE,
3060 EL_SP_TERMINAL_ACTIVE,
3061 EL_SP_BUGGY_BASE_ACTIVATING,
3062 EL_SP_BUGGY_BASE_ACTIVE,
3069 static int ep_sb_element[] =
3074 EL_SOKOBAN_FIELD_EMPTY,
3075 EL_SOKOBAN_FIELD_FULL,
3076 EL_SOKOBAN_FIELD_PLAYER,
3081 EL_INVISIBLE_STEELWALL,
3086 static int ep_gem[] =
3098 static int ep_food_dark_yamyam[] =
3126 static int ep_food_penguin[] =
3140 static int ep_food_pig[] =
3152 static int ep_historic_wall[] =
3163 EL_GATE_1_GRAY_ACTIVE,
3164 EL_GATE_2_GRAY_ACTIVE,
3165 EL_GATE_3_GRAY_ACTIVE,
3166 EL_GATE_4_GRAY_ACTIVE,
3175 EL_EM_GATE_1_GRAY_ACTIVE,
3176 EL_EM_GATE_2_GRAY_ACTIVE,
3177 EL_EM_GATE_3_GRAY_ACTIVE,
3178 EL_EM_GATE_4_GRAY_ACTIVE,
3185 EL_EXPANDABLE_WALL_HORIZONTAL,
3186 EL_EXPANDABLE_WALL_VERTICAL,
3187 EL_EXPANDABLE_WALL_ANY,
3188 EL_EXPANDABLE_WALL_GROWING,
3189 EL_BD_EXPANDABLE_WALL,
3196 EL_SP_HARDWARE_GRAY,
3197 EL_SP_HARDWARE_GREEN,
3198 EL_SP_HARDWARE_BLUE,
3200 EL_SP_HARDWARE_YELLOW,
3201 EL_SP_HARDWARE_BASE_1,
3202 EL_SP_HARDWARE_BASE_2,
3203 EL_SP_HARDWARE_BASE_3,
3204 EL_SP_HARDWARE_BASE_4,
3205 EL_SP_HARDWARE_BASE_5,
3206 EL_SP_HARDWARE_BASE_6,
3208 EL_SP_TERMINAL_ACTIVE,
3211 EL_INVISIBLE_STEELWALL,
3212 EL_INVISIBLE_STEELWALL_ACTIVE,
3214 EL_INVISIBLE_WALL_ACTIVE,
3215 EL_STEELWALL_SLIPPERY,
3232 static int ep_historic_solid[] =
3236 EL_EXPANDABLE_WALL_HORIZONTAL,
3237 EL_EXPANDABLE_WALL_VERTICAL,
3238 EL_EXPANDABLE_WALL_ANY,
3239 EL_BD_EXPANDABLE_WALL,
3252 EL_QUICKSAND_FILLING,
3253 EL_QUICKSAND_EMPTYING,
3255 EL_MAGIC_WALL_ACTIVE,
3256 EL_MAGIC_WALL_EMPTYING,
3257 EL_MAGIC_WALL_FILLING,
3261 EL_BD_MAGIC_WALL_ACTIVE,
3262 EL_BD_MAGIC_WALL_EMPTYING,
3263 EL_BD_MAGIC_WALL_FULL,
3264 EL_BD_MAGIC_WALL_FILLING,
3265 EL_BD_MAGIC_WALL_DEAD,
3274 EL_SP_TERMINAL_ACTIVE,
3278 EL_INVISIBLE_WALL_ACTIVE,
3279 EL_SWITCHGATE_SWITCH_UP,
3280 EL_SWITCHGATE_SWITCH_DOWN,
3281 EL_DC_SWITCHGATE_SWITCH_UP,
3282 EL_DC_SWITCHGATE_SWITCH_DOWN,
3284 EL_TIMEGATE_SWITCH_ACTIVE,
3285 EL_DC_TIMEGATE_SWITCH,
3286 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3298 /* the following elements are a direct copy of "indestructible" elements,
3299 except "EL_ACID", which is "indestructible", but not "solid"! */
3304 EL_ACID_POOL_TOPLEFT,
3305 EL_ACID_POOL_TOPRIGHT,
3306 EL_ACID_POOL_BOTTOMLEFT,
3307 EL_ACID_POOL_BOTTOM,
3308 EL_ACID_POOL_BOTTOMRIGHT,
3309 EL_SP_HARDWARE_GRAY,
3310 EL_SP_HARDWARE_GREEN,
3311 EL_SP_HARDWARE_BLUE,
3313 EL_SP_HARDWARE_YELLOW,
3314 EL_SP_HARDWARE_BASE_1,
3315 EL_SP_HARDWARE_BASE_2,
3316 EL_SP_HARDWARE_BASE_3,
3317 EL_SP_HARDWARE_BASE_4,
3318 EL_SP_HARDWARE_BASE_5,
3319 EL_SP_HARDWARE_BASE_6,
3320 EL_INVISIBLE_STEELWALL,
3321 EL_INVISIBLE_STEELWALL_ACTIVE,
3322 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3323 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3324 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3325 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3326 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3327 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3328 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3329 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3330 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3331 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3332 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3333 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3335 EL_LIGHT_SWITCH_ACTIVE,
3336 EL_SIGN_EXCLAMATION,
3337 EL_SIGN_RADIOACTIVITY,
3344 EL_SIGN_ENTRY_FORBIDDEN,
3345 EL_SIGN_EMERGENCY_EXIT,
3353 EL_STEEL_EXIT_CLOSED,
3355 EL_DC_STEELWALL_1_LEFT,
3356 EL_DC_STEELWALL_1_RIGHT,
3357 EL_DC_STEELWALL_1_TOP,
3358 EL_DC_STEELWALL_1_BOTTOM,
3359 EL_DC_STEELWALL_1_HORIZONTAL,
3360 EL_DC_STEELWALL_1_VERTICAL,
3361 EL_DC_STEELWALL_1_TOPLEFT,
3362 EL_DC_STEELWALL_1_TOPRIGHT,
3363 EL_DC_STEELWALL_1_BOTTOMLEFT,
3364 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3365 EL_DC_STEELWALL_1_TOPLEFT_2,
3366 EL_DC_STEELWALL_1_TOPRIGHT_2,
3367 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3368 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3369 EL_DC_STEELWALL_2_LEFT,
3370 EL_DC_STEELWALL_2_RIGHT,
3371 EL_DC_STEELWALL_2_TOP,
3372 EL_DC_STEELWALL_2_BOTTOM,
3373 EL_DC_STEELWALL_2_HORIZONTAL,
3374 EL_DC_STEELWALL_2_VERTICAL,
3375 EL_DC_STEELWALL_2_MIDDLE,
3376 EL_DC_STEELWALL_2_SINGLE,
3377 EL_STEELWALL_SLIPPERY,
3391 EL_GATE_1_GRAY_ACTIVE,
3392 EL_GATE_2_GRAY_ACTIVE,
3393 EL_GATE_3_GRAY_ACTIVE,
3394 EL_GATE_4_GRAY_ACTIVE,
3403 EL_EM_GATE_1_GRAY_ACTIVE,
3404 EL_EM_GATE_2_GRAY_ACTIVE,
3405 EL_EM_GATE_3_GRAY_ACTIVE,
3406 EL_EM_GATE_4_GRAY_ACTIVE,
3408 EL_SWITCHGATE_OPENING,
3409 EL_SWITCHGATE_CLOSED,
3410 EL_SWITCHGATE_CLOSING,
3412 EL_TIMEGATE_OPENING,
3414 EL_TIMEGATE_CLOSING,
3418 EL_TUBE_VERTICAL_LEFT,
3419 EL_TUBE_VERTICAL_RIGHT,
3420 EL_TUBE_HORIZONTAL_UP,
3421 EL_TUBE_HORIZONTAL_DOWN,
3430 static int ep_classic_enemy[] =
3447 static int ep_belt[] =
3449 EL_CONVEYOR_BELT_1_LEFT,
3450 EL_CONVEYOR_BELT_1_MIDDLE,
3451 EL_CONVEYOR_BELT_1_RIGHT,
3452 EL_CONVEYOR_BELT_2_LEFT,
3453 EL_CONVEYOR_BELT_2_MIDDLE,
3454 EL_CONVEYOR_BELT_2_RIGHT,
3455 EL_CONVEYOR_BELT_3_LEFT,
3456 EL_CONVEYOR_BELT_3_MIDDLE,
3457 EL_CONVEYOR_BELT_3_RIGHT,
3458 EL_CONVEYOR_BELT_4_LEFT,
3459 EL_CONVEYOR_BELT_4_MIDDLE,
3460 EL_CONVEYOR_BELT_4_RIGHT,
3465 static int ep_belt_active[] =
3467 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3468 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3469 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3470 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3471 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3472 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3473 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3474 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3475 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3476 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3477 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3478 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3483 static int ep_belt_switch[] =
3485 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3486 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3487 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3488 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3489 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3490 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3491 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3492 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3493 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3494 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3495 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3496 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3501 static int ep_tube[] =
3508 EL_TUBE_HORIZONTAL_UP,
3509 EL_TUBE_HORIZONTAL_DOWN,
3511 EL_TUBE_VERTICAL_LEFT,
3512 EL_TUBE_VERTICAL_RIGHT,
3518 static int ep_acid_pool[] =
3520 EL_ACID_POOL_TOPLEFT,
3521 EL_ACID_POOL_TOPRIGHT,
3522 EL_ACID_POOL_BOTTOMLEFT,
3523 EL_ACID_POOL_BOTTOM,
3524 EL_ACID_POOL_BOTTOMRIGHT,
3529 static int ep_keygate[] =
3539 EL_GATE_1_GRAY_ACTIVE,
3540 EL_GATE_2_GRAY_ACTIVE,
3541 EL_GATE_3_GRAY_ACTIVE,
3542 EL_GATE_4_GRAY_ACTIVE,
3551 EL_EM_GATE_1_GRAY_ACTIVE,
3552 EL_EM_GATE_2_GRAY_ACTIVE,
3553 EL_EM_GATE_3_GRAY_ACTIVE,
3554 EL_EM_GATE_4_GRAY_ACTIVE,
3563 EL_EMC_GATE_5_GRAY_ACTIVE,
3564 EL_EMC_GATE_6_GRAY_ACTIVE,
3565 EL_EMC_GATE_7_GRAY_ACTIVE,
3566 EL_EMC_GATE_8_GRAY_ACTIVE,
3568 EL_DC_GATE_WHITE_GRAY,
3569 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3574 static int ep_amoeboid[] =
3586 static int ep_amoebalive[] =
3597 static int ep_has_editor_content[] =
3619 static int ep_can_turn_each_move[] =
3621 /* !!! do something with this one !!! */
3625 static int ep_can_grow[] =
3639 static int ep_active_bomb[] =
3642 EL_EM_DYNAMITE_ACTIVE,
3643 EL_DYNABOMB_PLAYER_1_ACTIVE,
3644 EL_DYNABOMB_PLAYER_2_ACTIVE,
3645 EL_DYNABOMB_PLAYER_3_ACTIVE,
3646 EL_DYNABOMB_PLAYER_4_ACTIVE,
3647 EL_SP_DISK_RED_ACTIVE,
3652 static int ep_inactive[] =
3662 EL_QUICKSAND_FAST_EMPTY,
3685 EL_GATE_1_GRAY_ACTIVE,
3686 EL_GATE_2_GRAY_ACTIVE,
3687 EL_GATE_3_GRAY_ACTIVE,
3688 EL_GATE_4_GRAY_ACTIVE,
3697 EL_EM_GATE_1_GRAY_ACTIVE,
3698 EL_EM_GATE_2_GRAY_ACTIVE,
3699 EL_EM_GATE_3_GRAY_ACTIVE,
3700 EL_EM_GATE_4_GRAY_ACTIVE,
3709 EL_EMC_GATE_5_GRAY_ACTIVE,
3710 EL_EMC_GATE_6_GRAY_ACTIVE,
3711 EL_EMC_GATE_7_GRAY_ACTIVE,
3712 EL_EMC_GATE_8_GRAY_ACTIVE,
3714 EL_DC_GATE_WHITE_GRAY,
3715 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3716 EL_DC_GATE_FAKE_GRAY,
3719 EL_INVISIBLE_STEELWALL,
3727 EL_WALL_EMERALD_YELLOW,
3728 EL_DYNABOMB_INCREASE_NUMBER,
3729 EL_DYNABOMB_INCREASE_SIZE,
3730 EL_DYNABOMB_INCREASE_POWER,
3734 EL_SOKOBAN_FIELD_EMPTY,
3735 EL_SOKOBAN_FIELD_FULL,
3736 EL_WALL_EMERALD_RED,
3737 EL_WALL_EMERALD_PURPLE,
3738 EL_ACID_POOL_TOPLEFT,
3739 EL_ACID_POOL_TOPRIGHT,
3740 EL_ACID_POOL_BOTTOMLEFT,
3741 EL_ACID_POOL_BOTTOM,
3742 EL_ACID_POOL_BOTTOMRIGHT,
3746 EL_BD_MAGIC_WALL_DEAD,
3748 EL_DC_MAGIC_WALL_DEAD,
3749 EL_AMOEBA_TO_DIAMOND,
3757 EL_SP_GRAVITY_PORT_RIGHT,
3758 EL_SP_GRAVITY_PORT_DOWN,
3759 EL_SP_GRAVITY_PORT_LEFT,
3760 EL_SP_GRAVITY_PORT_UP,
3761 EL_SP_PORT_HORIZONTAL,
3762 EL_SP_PORT_VERTICAL,
3773 EL_SP_HARDWARE_GRAY,
3774 EL_SP_HARDWARE_GREEN,
3775 EL_SP_HARDWARE_BLUE,
3777 EL_SP_HARDWARE_YELLOW,
3778 EL_SP_HARDWARE_BASE_1,
3779 EL_SP_HARDWARE_BASE_2,
3780 EL_SP_HARDWARE_BASE_3,
3781 EL_SP_HARDWARE_BASE_4,
3782 EL_SP_HARDWARE_BASE_5,
3783 EL_SP_HARDWARE_BASE_6,
3784 EL_SP_GRAVITY_ON_PORT_LEFT,
3785 EL_SP_GRAVITY_ON_PORT_RIGHT,
3786 EL_SP_GRAVITY_ON_PORT_UP,
3787 EL_SP_GRAVITY_ON_PORT_DOWN,
3788 EL_SP_GRAVITY_OFF_PORT_LEFT,
3789 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3790 EL_SP_GRAVITY_OFF_PORT_UP,
3791 EL_SP_GRAVITY_OFF_PORT_DOWN,
3792 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3793 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3794 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3795 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3796 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3797 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3798 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3799 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3800 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3801 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3802 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3803 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3804 EL_SIGN_EXCLAMATION,
3805 EL_SIGN_RADIOACTIVITY,
3812 EL_SIGN_ENTRY_FORBIDDEN,
3813 EL_SIGN_EMERGENCY_EXIT,
3821 EL_DC_STEELWALL_1_LEFT,
3822 EL_DC_STEELWALL_1_RIGHT,
3823 EL_DC_STEELWALL_1_TOP,
3824 EL_DC_STEELWALL_1_BOTTOM,
3825 EL_DC_STEELWALL_1_HORIZONTAL,
3826 EL_DC_STEELWALL_1_VERTICAL,
3827 EL_DC_STEELWALL_1_TOPLEFT,
3828 EL_DC_STEELWALL_1_TOPRIGHT,
3829 EL_DC_STEELWALL_1_BOTTOMLEFT,
3830 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3831 EL_DC_STEELWALL_1_TOPLEFT_2,
3832 EL_DC_STEELWALL_1_TOPRIGHT_2,
3833 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3834 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3835 EL_DC_STEELWALL_2_LEFT,
3836 EL_DC_STEELWALL_2_RIGHT,
3837 EL_DC_STEELWALL_2_TOP,
3838 EL_DC_STEELWALL_2_BOTTOM,
3839 EL_DC_STEELWALL_2_HORIZONTAL,
3840 EL_DC_STEELWALL_2_VERTICAL,
3841 EL_DC_STEELWALL_2_MIDDLE,
3842 EL_DC_STEELWALL_2_SINGLE,
3843 EL_STEELWALL_SLIPPERY,
3848 EL_EMC_WALL_SLIPPERY_1,
3849 EL_EMC_WALL_SLIPPERY_2,
3850 EL_EMC_WALL_SLIPPERY_3,
3851 EL_EMC_WALL_SLIPPERY_4,
3872 static int ep_em_slippery_wall[] =
3877 static int ep_gfx_crumbled[] =
3888 static int ep_editor_cascade_active[] =
3890 EL_INTERNAL_CASCADE_BD_ACTIVE,
3891 EL_INTERNAL_CASCADE_EM_ACTIVE,
3892 EL_INTERNAL_CASCADE_EMC_ACTIVE,
3893 EL_INTERNAL_CASCADE_RND_ACTIVE,
3894 EL_INTERNAL_CASCADE_SB_ACTIVE,
3895 EL_INTERNAL_CASCADE_SP_ACTIVE,
3896 EL_INTERNAL_CASCADE_DC_ACTIVE,
3897 EL_INTERNAL_CASCADE_DX_ACTIVE,
3898 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
3899 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
3900 EL_INTERNAL_CASCADE_CE_ACTIVE,
3901 EL_INTERNAL_CASCADE_GE_ACTIVE,
3902 EL_INTERNAL_CASCADE_REF_ACTIVE,
3903 EL_INTERNAL_CASCADE_USER_ACTIVE,
3904 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
3909 static int ep_editor_cascade_inactive[] =
3911 EL_INTERNAL_CASCADE_BD,
3912 EL_INTERNAL_CASCADE_EM,
3913 EL_INTERNAL_CASCADE_EMC,
3914 EL_INTERNAL_CASCADE_RND,
3915 EL_INTERNAL_CASCADE_SB,
3916 EL_INTERNAL_CASCADE_SP,
3917 EL_INTERNAL_CASCADE_DC,
3918 EL_INTERNAL_CASCADE_DX,
3919 EL_INTERNAL_CASCADE_CHARS,
3920 EL_INTERNAL_CASCADE_STEEL_CHARS,
3921 EL_INTERNAL_CASCADE_CE,
3922 EL_INTERNAL_CASCADE_GE,
3923 EL_INTERNAL_CASCADE_REF,
3924 EL_INTERNAL_CASCADE_USER,
3925 EL_INTERNAL_CASCADE_DYNAMIC,
3930 static int ep_obsolete[] =
3934 EL_EM_KEY_1_FILE_OBSOLETE,
3935 EL_EM_KEY_2_FILE_OBSOLETE,
3936 EL_EM_KEY_3_FILE_OBSOLETE,
3937 EL_EM_KEY_4_FILE_OBSOLETE,
3938 EL_ENVELOPE_OBSOLETE,
3947 } element_properties[] =
3949 { ep_diggable, EP_DIGGABLE },
3950 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
3951 { ep_dont_run_into, EP_DONT_RUN_INTO },
3952 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
3953 { ep_dont_touch, EP_DONT_TOUCH },
3954 { ep_indestructible, EP_INDESTRUCTIBLE },
3955 { ep_slippery, EP_SLIPPERY },
3956 { ep_can_change, EP_CAN_CHANGE },
3957 { ep_can_move, EP_CAN_MOVE },
3958 { ep_can_fall, EP_CAN_FALL },
3959 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
3960 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
3961 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
3962 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
3963 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
3964 { ep_explodes_impact, EP_EXPLODES_IMPACT },
3965 { ep_walkable_over, EP_WALKABLE_OVER },
3966 { ep_walkable_inside, EP_WALKABLE_INSIDE },
3967 { ep_walkable_under, EP_WALKABLE_UNDER },
3968 { ep_passable_over, EP_PASSABLE_OVER },
3969 { ep_passable_inside, EP_PASSABLE_INSIDE },
3970 { ep_passable_under, EP_PASSABLE_UNDER },
3971 { ep_droppable, EP_DROPPABLE },
3972 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
3973 { ep_pushable, EP_PUSHABLE },
3974 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
3975 { ep_protected, EP_PROTECTED },
3976 { ep_throwable, EP_THROWABLE },
3977 { ep_can_explode, EP_CAN_EXPLODE },
3978 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
3980 { ep_player, EP_PLAYER },
3981 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
3982 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
3983 { ep_switchable, EP_SWITCHABLE },
3984 { ep_bd_element, EP_BD_ELEMENT },
3985 { ep_sp_element, EP_SP_ELEMENT },
3986 { ep_sb_element, EP_SB_ELEMENT },
3988 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
3989 { ep_food_penguin, EP_FOOD_PENGUIN },
3990 { ep_food_pig, EP_FOOD_PIG },
3991 { ep_historic_wall, EP_HISTORIC_WALL },
3992 { ep_historic_solid, EP_HISTORIC_SOLID },
3993 { ep_classic_enemy, EP_CLASSIC_ENEMY },
3994 { ep_belt, EP_BELT },
3995 { ep_belt_active, EP_BELT_ACTIVE },
3996 { ep_belt_switch, EP_BELT_SWITCH },
3997 { ep_tube, EP_TUBE },
3998 { ep_acid_pool, EP_ACID_POOL },
3999 { ep_keygate, EP_KEYGATE },
4000 { ep_amoeboid, EP_AMOEBOID },
4001 { ep_amoebalive, EP_AMOEBALIVE },
4002 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4003 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4004 { ep_can_grow, EP_CAN_GROW },
4005 { ep_active_bomb, EP_ACTIVE_BOMB },
4006 { ep_inactive, EP_INACTIVE },
4008 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4010 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4012 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4013 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4015 { ep_obsolete, EP_OBSOLETE },
4022 /* always start with reliable default values (element has no properties) */
4023 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4024 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4025 SET_PROPERTY(i, j, FALSE);
4027 /* set all base element properties from above array definitions */
4028 for (i = 0; element_properties[i].elements != NULL; i++)
4029 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4030 SET_PROPERTY((element_properties[i].elements)[j],
4031 element_properties[i].property, TRUE);
4033 /* copy properties to some elements that are only stored in level file */
4034 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4035 for (j = 0; copy_properties[j][0] != -1; j++)
4036 if (HAS_PROPERTY(copy_properties[j][0], i))
4037 for (k = 1; k <= 4; k++)
4038 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4040 /* set static element properties that are not listed in array definitions */
4041 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4042 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4045 void InitElementPropertiesEngine(int engine_version)
4047 static int no_wall_properties[] =
4050 EP_COLLECTIBLE_ONLY,
4052 EP_DONT_COLLIDE_WITH,
4055 EP_CAN_SMASH_PLAYER,
4056 EP_CAN_SMASH_ENEMIES,
4057 EP_CAN_SMASH_EVERYTHING,
4062 EP_FOOD_DARK_YAMYAM,
4078 /* important: after initialization in InitElementPropertiesStatic(), the
4079 elements are not again initialized to a default value; therefore all
4080 changes have to make sure that they leave the element with a defined
4081 property (which means that conditional property changes must be set to
4082 a reliable default value before) */
4084 /* resolve group elements */
4085 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4086 ResolveGroupElement(EL_GROUP_START + i);
4088 /* set all special, combined or engine dependent element properties */
4089 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4091 /* ---------- INACTIVE ------------------------------------------------- */
4092 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4093 i <= EL_CHAR_END) ||
4094 (i >= EL_STEEL_CHAR_START &&
4095 i <= EL_STEEL_CHAR_END)));
4097 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4098 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4099 IS_WALKABLE_INSIDE(i) ||
4100 IS_WALKABLE_UNDER(i)));
4102 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4103 IS_PASSABLE_INSIDE(i) ||
4104 IS_PASSABLE_UNDER(i)));
4106 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4107 IS_PASSABLE_OVER(i)));
4109 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4110 IS_PASSABLE_INSIDE(i)));
4112 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4113 IS_PASSABLE_UNDER(i)));
4115 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4118 /* ---------- COLLECTIBLE ---------------------------------------------- */
4119 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4123 /* ---------- SNAPPABLE ------------------------------------------------ */
4124 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4125 IS_COLLECTIBLE(i) ||
4129 /* ---------- WALL ----------------------------------------------------- */
4130 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4132 for (j = 0; no_wall_properties[j] != -1; j++)
4133 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4134 i >= EL_FIRST_RUNTIME_UNREAL)
4135 SET_PROPERTY(i, EP_WALL, FALSE);
4137 if (IS_HISTORIC_WALL(i))
4138 SET_PROPERTY(i, EP_WALL, TRUE);
4140 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4141 if (engine_version < VERSION_IDENT(2,2,0,0))
4142 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4144 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4146 !IS_COLLECTIBLE(i)));
4148 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4149 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4150 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4152 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4153 IS_INDESTRUCTIBLE(i)));
4155 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4157 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4158 else if (engine_version < VERSION_IDENT(2,2,0,0))
4159 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4161 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4165 if (IS_CUSTOM_ELEMENT(i))
4167 /* these are additional properties which are initially false when set */
4169 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4171 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4172 if (DONT_COLLIDE_WITH(i))
4173 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4175 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4176 if (CAN_SMASH_EVERYTHING(i))
4177 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4178 if (CAN_SMASH_ENEMIES(i))
4179 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4182 /* ---------- CAN_SMASH ------------------------------------------------ */
4183 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4184 CAN_SMASH_ENEMIES(i) ||
4185 CAN_SMASH_EVERYTHING(i)));
4187 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4188 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4189 EXPLODES_BY_FIRE(i)));
4191 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4192 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4193 EXPLODES_SMASHED(i)));
4195 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4196 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4197 EXPLODES_IMPACT(i)));
4199 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4200 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4202 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4203 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4204 i == EL_BLACK_ORB));
4206 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4207 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4209 IS_CUSTOM_ELEMENT(i)));
4211 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4212 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4213 i == EL_SP_ELECTRON));
4215 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4216 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4217 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4218 getMoveIntoAcidProperty(&level, i));
4220 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4221 if (MAYBE_DONT_COLLIDE_WITH(i))
4222 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4223 getDontCollideWithProperty(&level, i));
4225 /* ---------- SP_PORT -------------------------------------------------- */
4226 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4227 IS_PASSABLE_INSIDE(i)));
4229 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4230 for (j = 0; j < level.num_android_clone_elements; j++)
4231 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4233 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4235 /* ---------- CAN_CHANGE ----------------------------------------------- */
4236 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4237 for (j = 0; j < element_info[i].num_change_pages; j++)
4238 if (element_info[i].change_page[j].can_change)
4239 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4241 /* ---------- HAS_ACTION ----------------------------------------------- */
4242 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4243 for (j = 0; j < element_info[i].num_change_pages; j++)
4244 if (element_info[i].change_page[j].has_action)
4245 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4247 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4248 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4251 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4253 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4254 element_info[i].crumbled[ACTION_DEFAULT] !=
4255 element_info[i].graphic[ACTION_DEFAULT]);
4257 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
4258 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4259 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
4262 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4263 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4264 IS_EDITOR_CASCADE_INACTIVE(i)));
4267 /* dynamically adjust element properties according to game engine version */
4269 static int ep_em_slippery_wall[] =
4274 EL_EXPANDABLE_WALL_HORIZONTAL,
4275 EL_EXPANDABLE_WALL_VERTICAL,
4276 EL_EXPANDABLE_WALL_ANY,
4277 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4278 EL_EXPANDABLE_STEELWALL_VERTICAL,
4279 EL_EXPANDABLE_STEELWALL_ANY,
4280 EL_EXPANDABLE_STEELWALL_GROWING,
4284 /* special EM style gems behaviour */
4285 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4286 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4287 level.em_slippery_gems);
4289 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4290 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4291 (level.em_slippery_gems &&
4292 engine_version > VERSION_IDENT(2,0,1,0)));
4295 /* this is needed because some graphics depend on element properties */
4296 if (game_status == GAME_MODE_PLAYING)
4297 InitElementGraphicInfo();
4300 void InitElementPropertiesAfterLoading(int engine_version)
4304 /* set some other uninitialized values of custom elements in older levels */
4305 if (engine_version < VERSION_IDENT(3,1,0,0))
4307 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4309 int element = EL_CUSTOM_START + i;
4311 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4313 element_info[element].explosion_delay = 17;
4314 element_info[element].ignition_delay = 8;
4319 static void InitGlobal()
4323 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4325 /* check if element_name_info entry defined for each element in "main.h" */
4326 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4327 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4329 element_info[i].token_name = element_name_info[i].token_name;
4330 element_info[i].class_name = element_name_info[i].class_name;
4331 element_info[i].editor_description=element_name_info[i].editor_description;
4334 printf("%04d: %s\n", i, element_name_info[i].token_name);
4338 global.autoplay_leveldir = NULL;
4339 global.convert_leveldir = NULL;
4341 global.frames_per_second = 0;
4342 global.fps_slowdown = FALSE;
4343 global.fps_slowdown_factor = 1;
4346 void Execute_Command(char *command)
4350 if (strEqual(command, "print graphicsinfo.conf"))
4352 printf("# You can configure additional/alternative image files here.\n");
4353 printf("# (The entries below are default and therefore commented out.)\n");
4355 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4357 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4360 for (i = 0; image_config[i].token != NULL; i++)
4361 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
4362 image_config[i].value));
4366 else if (strEqual(command, "print soundsinfo.conf"))
4368 printf("# You can configure additional/alternative sound files here.\n");
4369 printf("# (The entries below are default and therefore commented out.)\n");
4371 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4373 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4376 for (i = 0; sound_config[i].token != NULL; i++)
4377 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4378 sound_config[i].value));
4382 else if (strEqual(command, "print musicinfo.conf"))
4384 printf("# You can configure additional/alternative music files here.\n");
4385 printf("# (The entries below are default and therefore commented out.)\n");
4387 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4389 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4392 for (i = 0; music_config[i].token != NULL; i++)
4393 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
4394 music_config[i].value));
4398 else if (strEqual(command, "print editorsetup.conf"))
4400 printf("# You can configure your personal editor element list here.\n");
4401 printf("# (The entries below are default and therefore commented out.)\n");
4404 /* this is needed to be able to check element list for cascade elements */
4405 InitElementPropertiesStatic();
4406 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4408 PrintEditorElementList();
4412 else if (strEqual(command, "print helpanim.conf"))
4414 printf("# You can configure different element help animations here.\n");
4415 printf("# (The entries below are default and therefore commented out.)\n");
4418 for (i = 0; helpanim_config[i].token != NULL; i++)
4420 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4421 helpanim_config[i].value));
4423 if (strEqual(helpanim_config[i].token, "end"))
4429 else if (strEqual(command, "print helptext.conf"))
4431 printf("# You can configure different element help text here.\n");
4432 printf("# (The entries below are default and therefore commented out.)\n");
4435 for (i = 0; helptext_config[i].token != NULL; i++)
4436 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4437 helptext_config[i].value));
4441 else if (strncmp(command, "dump level ", 11) == 0)
4443 char *filename = &command[11];
4445 if (!fileExists(filename))
4446 Error(ERR_EXIT, "cannot open file '%s'", filename);
4448 LoadLevelFromFilename(&level, filename);
4453 else if (strncmp(command, "dump tape ", 10) == 0)
4455 char *filename = &command[10];
4457 if (!fileExists(filename))
4458 Error(ERR_EXIT, "cannot open file '%s'", filename);
4460 LoadTapeFromFilename(filename);
4465 else if (strncmp(command, "autoplay ", 9) == 0)
4467 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
4469 while (*str_ptr != '\0') /* continue parsing string */
4471 /* cut leading whitespace from string, replace it by string terminator */
4472 while (*str_ptr == ' ' || *str_ptr == '\t')
4475 if (*str_ptr == '\0') /* end of string reached */
4478 if (global.autoplay_leveldir == NULL) /* read level set string */
4480 global.autoplay_leveldir = str_ptr;
4481 global.autoplay_all = TRUE; /* default: play all tapes */
4483 for (i = 0; i < MAX_TAPES_PER_SET; i++)
4484 global.autoplay_level[i] = FALSE;
4486 else /* read level number string */
4488 int level_nr = atoi(str_ptr); /* get level_nr value */
4490 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
4491 global.autoplay_level[level_nr] = TRUE;
4493 global.autoplay_all = FALSE;
4496 /* advance string pointer to the next whitespace (or end of string) */
4497 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
4501 else if (strncmp(command, "convert ", 8) == 0)
4503 char *str_copy = getStringCopy(&command[8]);
4504 char *str_ptr = strchr(str_copy, ' ');
4506 global.convert_leveldir = str_copy;
4507 global.convert_level_nr = -1;
4509 if (str_ptr != NULL) /* level number follows */
4511 *str_ptr++ = '\0'; /* terminate leveldir string */
4512 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
4517 #if defined(TARGET_SDL)
4518 else if (strEqual(command, "SDL_ListModes"))
4523 SDL_Init(SDL_INIT_VIDEO);
4525 /* get available fullscreen/hardware modes */
4526 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
4528 /* check if there are any modes available */
4531 printf("No modes available!\n");
4536 /* check if our resolution is restricted */
4537 if (modes == (SDL_Rect **)-1)
4539 printf("All resolutions available.\n");
4543 printf("Available Modes:\n");
4545 for(i = 0; modes[i]; i++)
4546 printf(" %d x %d\n", modes[i]->w, modes[i]->h);
4556 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4560 static void InitSetup()
4562 LoadSetup(); /* global setup info */
4564 /* set some options from setup file */
4566 if (setup.options.verbose)
4567 options.verbose = TRUE;
4570 static void InitGameInfo()
4572 game.restart_level = FALSE;
4575 static void InitPlayerInfo()
4579 /* choose default local player */
4580 local_player = &stored_player[0];
4582 for (i = 0; i < MAX_PLAYERS; i++)
4583 stored_player[i].connected = FALSE;
4585 local_player->connected = TRUE;
4588 static void InitArtworkInfo()
4593 static char *get_string_in_brackets(char *string)
4595 char *string_in_brackets = checked_malloc(strlen(string) + 3);
4597 sprintf(string_in_brackets, "[%s]", string);
4599 return string_in_brackets;
4602 static char *get_level_id_suffix(int id_nr)
4604 char *id_suffix = checked_malloc(1 + 3 + 1);
4606 if (id_nr < 0 || id_nr > 999)
4609 sprintf(id_suffix, ".%03d", id_nr);
4615 static char *get_element_class_token(int element)
4617 char *element_class_name = element_info[element].class_name;
4618 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
4620 sprintf(element_class_token, "[%s]", element_class_name);
4622 return element_class_token;
4625 static char *get_action_class_token(int action)
4627 char *action_class_name = &element_action_info[action].suffix[1];
4628 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
4630 sprintf(action_class_token, "[%s]", action_class_name);
4632 return action_class_token;
4636 static void InitArtworkConfig()
4638 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
4639 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
4640 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
4641 static char *action_id_suffix[NUM_ACTIONS + 1];
4642 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
4643 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
4644 static char *level_id_suffix[MAX_LEVELS + 1];
4645 static char *dummy[1] = { NULL };
4646 static char *ignore_generic_tokens[] =
4652 static char **ignore_image_tokens;
4653 static char **ignore_sound_tokens;
4654 static char **ignore_music_tokens;
4655 int num_ignore_generic_tokens;
4656 int num_ignore_image_tokens;
4657 int num_ignore_sound_tokens;
4658 int num_ignore_music_tokens;
4661 /* dynamically determine list of generic tokens to be ignored */
4662 num_ignore_generic_tokens = 0;
4663 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
4664 num_ignore_generic_tokens++;
4666 /* dynamically determine list of image tokens to be ignored */
4667 num_ignore_image_tokens = num_ignore_generic_tokens;
4668 for (i = 0; image_config_vars[i].token != NULL; i++)
4669 num_ignore_image_tokens++;
4670 ignore_image_tokens =
4671 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
4672 for (i = 0; i < num_ignore_generic_tokens; i++)
4673 ignore_image_tokens[i] = ignore_generic_tokens[i];
4674 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
4675 ignore_image_tokens[num_ignore_generic_tokens + i] =
4676 image_config_vars[i].token;
4677 ignore_image_tokens[num_ignore_image_tokens] = NULL;
4679 /* dynamically determine list of sound tokens to be ignored */
4680 num_ignore_sound_tokens = num_ignore_generic_tokens;
4681 ignore_sound_tokens =
4682 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
4683 for (i = 0; i < num_ignore_generic_tokens; i++)
4684 ignore_sound_tokens[i] = ignore_generic_tokens[i];
4685 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
4687 /* dynamically determine list of music tokens to be ignored */
4688 num_ignore_music_tokens = num_ignore_generic_tokens;
4689 ignore_music_tokens =
4690 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
4691 for (i = 0; i < num_ignore_generic_tokens; i++)
4692 ignore_music_tokens[i] = ignore_generic_tokens[i];
4693 ignore_music_tokens[num_ignore_music_tokens] = NULL;
4695 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4696 image_id_prefix[i] = element_info[i].token_name;
4697 for (i = 0; i < NUM_FONTS; i++)
4698 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
4699 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
4701 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4702 sound_id_prefix[i] = element_info[i].token_name;
4703 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4704 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
4705 get_string_in_brackets(element_info[i].class_name);
4706 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
4708 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
4709 music_id_prefix[i] = music_prefix_info[i].prefix;
4710 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
4712 for (i = 0; i < NUM_ACTIONS; i++)
4713 action_id_suffix[i] = element_action_info[i].suffix;
4714 action_id_suffix[NUM_ACTIONS] = NULL;
4716 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
4717 direction_id_suffix[i] = element_direction_info[i].suffix;
4718 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
4720 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
4721 special_id_suffix[i] = special_suffix_info[i].suffix;
4722 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
4724 for (i = 0; i < MAX_LEVELS; i++)
4725 level_id_suffix[i] = get_level_id_suffix(i);
4726 level_id_suffix[MAX_LEVELS] = NULL;
4728 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
4729 image_id_prefix, action_id_suffix, direction_id_suffix,
4730 special_id_suffix, ignore_image_tokens);
4731 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
4732 sound_id_prefix, action_id_suffix, dummy,
4733 special_id_suffix, ignore_sound_tokens);
4734 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
4735 music_id_prefix, special_id_suffix, level_id_suffix,
4736 dummy, ignore_music_tokens);
4739 static void InitMixer()
4747 char *filename_font_initial = NULL;
4748 Bitmap *bitmap_font_initial = NULL;
4752 /* determine settings for initial font (for displaying startup messages) */
4753 for (i = 0; image_config[i].token != NULL; i++)
4755 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4757 char font_token[128];
4760 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
4761 len_font_token = strlen(font_token);
4763 if (strEqual(image_config[i].token, font_token))
4764 filename_font_initial = image_config[i].value;
4765 else if (strlen(image_config[i].token) > len_font_token &&
4766 strncmp(image_config[i].token, font_token, len_font_token) == 0)
4768 if (strEqual(&image_config[i].token[len_font_token], ".x"))
4769 font_initial[j].src_x = atoi(image_config[i].value);
4770 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
4771 font_initial[j].src_y = atoi(image_config[i].value);
4772 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
4773 font_initial[j].width = atoi(image_config[i].value);
4774 else if (strEqual(&image_config[i].token[len_font_token],".height"))
4775 font_initial[j].height = atoi(image_config[i].value);
4780 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4782 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
4783 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
4786 if (filename_font_initial == NULL) /* should not happen */
4787 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
4789 /* create additional image buffers for double-buffering and cross-fading */
4790 bitmap_db_cross = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
4791 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
4792 bitmap_db_panel = CreateBitmap(DXSIZE, DYSIZE, DEFAULT_DEPTH);
4793 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
4795 /* initialize screen properties */
4796 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
4797 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
4799 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
4800 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
4801 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
4803 bitmap_font_initial = LoadCustomImage(filename_font_initial);
4805 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4806 font_initial[j].bitmap = bitmap_font_initial;
4808 InitFontGraphicInfo();
4810 font_height = getFontHeight(FC_RED);
4813 DrawInitText(getWindowTitleString(), 20, FC_YELLOW);
4815 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
4817 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
4818 DrawInitText(PROGRAM_WEBSITE_STRING, WIN_YSIZE - 20 - font_height, FC_RED);
4820 DrawInitText("Loading graphics", 120, FC_GREEN);
4823 void RedrawBackground()
4825 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
4826 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
4828 redraw_mask = REDRAW_ALL;
4831 void InitGfxBackground()
4835 fieldbuffer = bitmap_db_field;
4836 SetDrawtoField(DRAW_BACKBUFFER);
4840 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
4841 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
4843 for (x = 0; x < MAX_BUF_XSIZE; x++)
4844 for (y = 0; y < MAX_BUF_YSIZE; y++)
4847 redraw_mask = REDRAW_ALL;
4850 static void InitLevelInfo()
4852 LoadLevelInfo(); /* global level info */
4853 LoadLevelSetup_LastSeries(); /* last played series info */
4854 LoadLevelSetup_SeriesInfo(); /* last played level info */
4857 void InitLevelArtworkInfo()
4859 LoadLevelArtworkInfo();
4862 static void InitImages()
4864 setLevelArtworkDir(artwork.gfx_first);
4867 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
4868 leveldir_current->identifier,
4869 artwork.gfx_current_identifier,
4870 artwork.gfx_current->identifier,
4871 leveldir_current->graphics_set,
4872 leveldir_current->graphics_path);
4875 ReloadCustomImages();
4877 LoadCustomElementDescriptions();
4878 LoadSpecialMenuDesignSettings();
4880 ReinitializeGraphics();
4883 static void InitSound(char *identifier)
4885 if (identifier == NULL)
4886 identifier = artwork.snd_current->identifier;
4888 /* set artwork path to send it to the sound server process */
4889 setLevelArtworkDir(artwork.snd_first);
4891 InitReloadCustomSounds(identifier);
4892 ReinitializeSounds();
4895 static void InitMusic(char *identifier)
4897 if (identifier == NULL)
4898 identifier = artwork.mus_current->identifier;
4900 /* set artwork path to send it to the sound server process */
4901 setLevelArtworkDir(artwork.mus_first);
4903 InitReloadCustomMusic(identifier);
4904 ReinitializeMusic();
4907 void InitNetworkServer()
4909 #if defined(NETWORK_AVALIABLE)
4913 if (!options.network)
4916 #if defined(NETWORK_AVALIABLE)
4917 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
4919 if (!ConnectToServer(options.server_host, options.server_port))
4920 Error(ERR_EXIT, "cannot connect to network game server");
4922 SendToServer_PlayerName(setup.player_name);
4923 SendToServer_ProtocolVersion();
4926 SendToServer_NrWanted(nr_wanted);
4930 static char *getNewArtworkIdentifier(int type)
4932 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
4933 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
4934 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
4935 static boolean initialized[3] = { FALSE, FALSE, FALSE };
4936 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
4937 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
4938 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
4939 char *leveldir_identifier = leveldir_current->identifier;
4941 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
4942 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
4944 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
4946 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
4947 char *artwork_current_identifier;
4948 char *artwork_new_identifier = NULL; /* default: nothing has changed */
4950 /* leveldir_current may be invalid (level group, parent link) */
4951 if (!validLevelSeries(leveldir_current))
4954 /* 1st step: determine artwork set to be activated in descending order:
4955 --------------------------------------------------------------------
4956 1. setup artwork (when configured to override everything else)
4957 2. artwork set configured in "levelinfo.conf" of current level set
4958 (artwork in level directory will have priority when loading later)
4959 3. artwork in level directory (stored in artwork sub-directory)
4960 4. setup artwork (currently configured in setup menu) */
4962 if (setup_override_artwork)
4963 artwork_current_identifier = setup_artwork_set;
4964 else if (leveldir_artwork_set != NULL)
4965 artwork_current_identifier = leveldir_artwork_set;
4966 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
4967 artwork_current_identifier = leveldir_identifier;
4969 artwork_current_identifier = setup_artwork_set;
4972 /* 2nd step: check if it is really needed to reload artwork set
4973 ------------------------------------------------------------ */
4976 if (type == ARTWORK_TYPE_GRAPHICS)
4977 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
4978 artwork_new_identifier,
4979 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4980 artwork_current_identifier,
4981 leveldir_current->graphics_set,
4982 leveldir_current->identifier);
4985 /* ---------- reload if level set and also artwork set has changed ------- */
4986 if (leveldir_current_identifier[type] != leveldir_identifier &&
4987 (last_has_level_artwork_set[type] || has_level_artwork_set))
4988 artwork_new_identifier = artwork_current_identifier;
4990 leveldir_current_identifier[type] = leveldir_identifier;
4991 last_has_level_artwork_set[type] = has_level_artwork_set;
4994 if (type == ARTWORK_TYPE_GRAPHICS)
4995 printf("::: 1: '%s'\n", artwork_new_identifier);
4998 /* ---------- reload if "override artwork" setting has changed ----------- */
4999 if (last_override_level_artwork[type] != setup_override_artwork)
5000 artwork_new_identifier = artwork_current_identifier;
5002 last_override_level_artwork[type] = setup_override_artwork;
5005 if (type == ARTWORK_TYPE_GRAPHICS)
5006 printf("::: 2: '%s'\n", artwork_new_identifier);
5009 /* ---------- reload if current artwork identifier has changed ----------- */
5010 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5011 artwork_current_identifier))
5012 artwork_new_identifier = artwork_current_identifier;
5014 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5017 if (type == ARTWORK_TYPE_GRAPHICS)
5018 printf("::: 3: '%s'\n", artwork_new_identifier);
5021 /* ---------- do not reload directly after starting ---------------------- */
5022 if (!initialized[type])
5023 artwork_new_identifier = NULL;
5025 initialized[type] = TRUE;
5028 if (type == ARTWORK_TYPE_GRAPHICS)
5029 printf("::: 4: '%s'\n", artwork_new_identifier);
5033 if (type == ARTWORK_TYPE_GRAPHICS)
5034 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
5035 artwork.gfx_current_identifier, artwork_current_identifier,
5036 artwork.gfx_current->identifier, leveldir_current->graphics_set,
5037 artwork_new_identifier);
5040 return artwork_new_identifier;
5043 void ReloadCustomArtwork(int force_reload)
5045 char *gfx_new_identifier;
5046 char *snd_new_identifier;
5047 char *mus_new_identifier;
5048 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5049 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5050 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5051 boolean redraw_screen = FALSE;
5053 force_reload_gfx |= AdjustGraphicsForEMC();
5055 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5056 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5057 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5059 if (gfx_new_identifier != NULL || force_reload_gfx)
5062 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5063 artwork.gfx_current_identifier,
5065 artwork.gfx_current->identifier,
5066 leveldir_current->graphics_set);
5069 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
5073 redraw_screen = TRUE;
5076 if (snd_new_identifier != NULL || force_reload_snd)
5078 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
5080 InitSound(snd_new_identifier);
5082 redraw_screen = TRUE;
5085 if (mus_new_identifier != NULL || force_reload_mus)
5087 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
5089 InitMusic(mus_new_identifier);
5091 redraw_screen = TRUE;
5098 /* force redraw of (open or closed) door graphics */
5099 SetDoorState(DOOR_OPEN_ALL);
5100 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5104 void KeyboardAutoRepeatOffUnlessAutoplay()
5106 if (global.autoplay_leveldir == NULL)
5107 KeyboardAutoRepeatOff();
5111 /* ========================================================================= */
5113 /* ========================================================================= */
5117 InitGlobal(); /* initialize some global variables */
5119 if (options.execute_command)
5120 Execute_Command(options.execute_command);
5122 if (options.serveronly)
5124 #if defined(PLATFORM_UNIX)
5125 NetworkServer(options.server_port, options.serveronly);
5127 Error(ERR_WARN, "networking only supported in Unix version");
5130 exit(0); /* never reached, server loops forever */
5137 InitArtworkInfo(); /* needed before loading gfx, sound & music */
5138 InitArtworkConfig(); /* needed before forking sound child process */
5143 InitRND(NEW_RANDOMIZE);
5144 InitSimpleRandom(NEW_RANDOMIZE);
5149 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
5151 InitEventFilter(FilterMouseMotionEvents);
5153 InitElementPropertiesStatic();
5154 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5158 // debug_print_timestamp(0, "INIT");
5160 // debug_print_timestamp(0, "TIME InitLevelInfo: ");
5161 InitLevelArtworkInfo();
5162 // debug_print_timestamp(0, "TIME InitLevelArtworkInfo: ");
5164 InitImages(); /* needs to know current level directory */
5165 InitSound(NULL); /* needs to know current level directory */
5166 InitMusic(NULL); /* needs to know current level directory */
5168 InitGfxBackground();
5174 if (global.autoplay_leveldir)
5179 else if (global.convert_leveldir)
5185 game_status = GAME_MODE_MAIN;
5189 InitNetworkServer();
5192 void CloseAllAndExit(int exit_value)
5197 CloseAudio(); /* called after freeing sounds (needed for SDL) */
5205 #if defined(TARGET_SDL)
5206 if (network_server) /* terminate network server */
5207 SDL_KillThread(server_thread);
5210 CloseVideoDisplay();
5211 ClosePlatformDependentStuff();
5213 if (exit_value != 0)
5214 NotifyUserAboutErrorFile();