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_MAIN,
1294 IMG_BACKGROUND_LEVELS,
1295 IMG_BACKGROUND_SCORES,
1296 IMG_BACKGROUND_EDITOR,
1297 IMG_BACKGROUND_INFO,
1298 IMG_BACKGROUND_INFO_ELEMENTS,
1299 IMG_BACKGROUND_INFO_MUSIC,
1300 IMG_BACKGROUND_INFO_CREDITS,
1301 IMG_BACKGROUND_INFO_PROGRAM,
1302 IMG_BACKGROUND_INFO_LEVELSET,
1303 IMG_BACKGROUND_SETUP,
1304 IMG_BACKGROUND_DOOR,
1306 IMG_TITLESCREEN_INITIAL_1,
1307 IMG_TITLESCREEN_INITIAL_2,
1308 IMG_TITLESCREEN_INITIAL_3,
1309 IMG_TITLESCREEN_INITIAL_4,
1310 IMG_TITLESCREEN_INITIAL_5,
1320 checked_free(graphic_info);
1322 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1325 /* initialize "use_image_size" flag with default value */
1326 for (i = 0; i < num_images; i++)
1327 graphic_info[i].use_image_size = FALSE;
1329 /* initialize "use_image_size" flag from static configuration above */
1330 for (i = 0; full_size_graphics[i] != -1; i++)
1331 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1334 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1335 if (clipmasks_initialized)
1337 for (i = 0; i < num_images; i++)
1339 if (graphic_info[i].clip_mask)
1340 XFreePixmap(display, graphic_info[i].clip_mask);
1341 if (graphic_info[i].clip_gc)
1342 XFreeGC(display, graphic_info[i].clip_gc);
1344 graphic_info[i].clip_mask = None;
1345 graphic_info[i].clip_gc = None;
1350 /* first set all graphic paramaters ... */
1351 for (i = 0; i < num_images; i++)
1352 set_graphic_parameters(i);
1354 /* ... then copy these parameters for cloned graphics */
1355 for (i = 0; i < num_images; i++)
1356 if (graphic_info[i].clone_from != -1)
1357 set_cloned_graphic_parameters(i);
1359 for (i = 0; i < num_images; i++)
1364 int first_frame, last_frame;
1365 int src_bitmap_width, src_bitmap_height;
1367 /* now check if no animation frames are outside of the loaded image */
1369 if (graphic_info[i].bitmap == NULL)
1370 continue; /* skip check for optional images that are undefined */
1372 /* get image size (this can differ from the standard element tile size!) */
1373 width = graphic_info[i].width;
1374 height = graphic_info[i].height;
1376 /* get final bitmap size (with scaling, but without small images) */
1377 src_bitmap_width = graphic_info[i].src_image_width;
1378 src_bitmap_height = graphic_info[i].src_image_height;
1380 /* check if first animation frame is inside specified bitmap */
1383 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1386 /* this avoids calculating wrong start position for out-of-bounds frame */
1387 src_x = graphic_info[i].src_x;
1388 src_y = graphic_info[i].src_y;
1391 if (src_x < 0 || src_y < 0 ||
1392 src_x + width > src_bitmap_width ||
1393 src_y + height > src_bitmap_height)
1395 Error(ERR_INFO_LINE, "-");
1396 Error(ERR_INFO, "warning: error found in config file:");
1397 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1398 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1399 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1401 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1402 src_x, src_y, src_bitmap_width, src_bitmap_height);
1403 Error(ERR_INFO, "custom graphic rejected for this element/action");
1405 if (i == fallback_graphic)
1406 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1408 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1409 Error(ERR_INFO_LINE, "-");
1411 graphic_info[i] = graphic_info[fallback_graphic];
1414 /* check if last animation frame is inside specified bitmap */
1416 last_frame = graphic_info[i].anim_frames - 1;
1417 getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1419 if (src_x < 0 || src_y < 0 ||
1420 src_x + width > src_bitmap_width ||
1421 src_y + height > src_bitmap_height)
1423 Error(ERR_INFO_LINE, "-");
1424 Error(ERR_INFO, "warning: error found in config file:");
1425 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1426 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1427 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1429 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1430 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1431 Error(ERR_INFO, "custom graphic rejected for this element/action");
1433 if (i == fallback_graphic)
1434 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1436 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1437 Error(ERR_INFO_LINE, "-");
1439 graphic_info[i] = graphic_info[fallback_graphic];
1442 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1443 /* currently we only need a tile clip mask from the first frame */
1444 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1446 if (copy_clipmask_gc == None)
1448 clip_gc_values.graphics_exposures = False;
1449 clip_gc_valuemask = GCGraphicsExposures;
1450 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
1451 clip_gc_valuemask, &clip_gc_values);
1454 graphic_info[i].clip_mask =
1455 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
1457 src_pixmap = src_bitmap->clip_mask;
1458 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
1459 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
1461 clip_gc_values.graphics_exposures = False;
1462 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
1463 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
1465 graphic_info[i].clip_gc =
1466 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
1470 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1471 if (copy_clipmask_gc)
1472 XFreeGC(display, copy_clipmask_gc);
1474 clipmasks_initialized = TRUE;
1478 static void InitElementSoundInfo()
1480 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1481 int num_property_mappings = getSoundListPropertyMappingSize();
1484 /* set values to -1 to identify later as "uninitialized" values */
1485 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1486 for (act = 0; act < NUM_ACTIONS; act++)
1487 element_info[i].sound[act] = -1;
1489 /* initialize element/sound mapping from static configuration */
1490 for (i = 0; element_to_sound[i].element > -1; i++)
1492 int element = element_to_sound[i].element;
1493 int action = element_to_sound[i].action;
1494 int sound = element_to_sound[i].sound;
1495 boolean is_class = element_to_sound[i].is_class;
1498 action = ACTION_DEFAULT;
1501 element_info[element].sound[action] = sound;
1503 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1504 if (strEqual(element_info[j].class_name,
1505 element_info[element].class_name))
1506 element_info[j].sound[action] = sound;
1509 /* initialize element class/sound mapping from dynamic configuration */
1510 for (i = 0; i < num_property_mappings; i++)
1512 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1513 int action = property_mapping[i].ext1_index;
1514 int sound = property_mapping[i].artwork_index;
1516 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1520 action = ACTION_DEFAULT;
1522 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1523 if (strEqual(element_info[j].class_name,
1524 element_info[element_class].class_name))
1525 element_info[j].sound[action] = sound;
1528 /* initialize element/sound mapping from dynamic configuration */
1529 for (i = 0; i < num_property_mappings; i++)
1531 int element = property_mapping[i].base_index;
1532 int action = property_mapping[i].ext1_index;
1533 int sound = property_mapping[i].artwork_index;
1535 if (element >= MAX_NUM_ELEMENTS)
1539 action = ACTION_DEFAULT;
1541 element_info[element].sound[action] = sound;
1544 /* now set all '-1' values to element specific default values */
1545 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1547 for (act = 0; act < NUM_ACTIONS; act++)
1549 /* generic default action sound (defined by "[default]" directive) */
1550 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1552 /* look for special default action sound (classic game specific) */
1553 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1554 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1555 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1556 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1557 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1558 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1560 /* !!! there's no such thing as a "default action sound" !!! */
1562 /* look for element specific default sound (independent from action) */
1563 if (element_info[i].sound[ACTION_DEFAULT] != -1)
1564 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
1568 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1569 /* !!! make this better !!! */
1570 if (i == EL_EMPTY_SPACE)
1571 default_action_sound = element_info[EL_DEFAULT].sound[act];
1574 /* no sound for this specific action -- use default action sound */
1575 if (element_info[i].sound[act] == -1)
1576 element_info[i].sound[act] = default_action_sound;
1580 /* copy sound settings to some elements that are only stored in level file
1581 in native R'n'D levels, but are used by game engine in native EM levels */
1582 for (i = 0; copy_properties[i][0] != -1; i++)
1583 for (j = 1; j <= 4; j++)
1584 for (act = 0; act < NUM_ACTIONS; act++)
1585 element_info[copy_properties[i][j]].sound[act] =
1586 element_info[copy_properties[i][0]].sound[act];
1589 static void InitGameModeSoundInfo()
1593 /* set values to -1 to identify later as "uninitialized" values */
1594 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1597 /* initialize gamemode/sound mapping from static configuration */
1598 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1600 int gamemode = gamemode_to_sound[i].gamemode;
1601 int sound = gamemode_to_sound[i].sound;
1604 gamemode = GAME_MODE_DEFAULT;
1606 menu.sound[gamemode] = sound;
1609 /* now set all '-1' values to levelset specific default values */
1610 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1611 if (menu.sound[i] == -1)
1612 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1615 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1616 if (menu.sound[i] != -1)
1617 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
1621 static void set_sound_parameters(int sound, char **parameter_raw)
1623 int parameter[NUM_SND_ARGS];
1626 /* get integer values from string parameters */
1627 for (i = 0; i < NUM_SND_ARGS; i++)
1629 get_parameter_value(parameter_raw[i],
1630 sound_config_suffix[i].token,
1631 sound_config_suffix[i].type);
1633 /* explicit loop mode setting in configuration overrides default value */
1634 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1635 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1637 /* sound volume to change the original volume when loading the sound file */
1638 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1640 /* sound priority to give certain sounds a higher or lower priority */
1641 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
1644 static void InitSoundInfo()
1646 int *sound_effect_properties;
1647 int num_sounds = getSoundListSize();
1650 checked_free(sound_info);
1652 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1653 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1655 /* initialize sound effect for all elements to "no sound" */
1656 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1657 for (j = 0; j < NUM_ACTIONS; j++)
1658 element_info[i].sound[j] = SND_UNDEFINED;
1660 for (i = 0; i < num_sounds; i++)
1662 struct FileInfo *sound = getSoundListEntry(i);
1663 int len_effect_text = strlen(sound->token);
1665 sound_effect_properties[i] = ACTION_OTHER;
1666 sound_info[i].loop = FALSE; /* default: play sound only once */
1669 printf("::: sound %d: '%s'\n", i, sound->token);
1672 /* determine all loop sounds and identify certain sound classes */
1674 for (j = 0; element_action_info[j].suffix; j++)
1676 int len_action_text = strlen(element_action_info[j].suffix);
1678 if (len_action_text < len_effect_text &&
1679 strEqual(&sound->token[len_effect_text - len_action_text],
1680 element_action_info[j].suffix))
1682 sound_effect_properties[i] = element_action_info[j].value;
1683 sound_info[i].loop = element_action_info[j].is_loop_sound;
1689 /* associate elements and some selected sound actions */
1691 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1693 if (element_info[j].class_name)
1695 int len_class_text = strlen(element_info[j].class_name);
1697 if (len_class_text + 1 < len_effect_text &&
1698 strncmp(sound->token,
1699 element_info[j].class_name, len_class_text) == 0 &&
1700 sound->token[len_class_text] == '.')
1702 int sound_action_value = sound_effect_properties[i];
1704 element_info[j].sound[sound_action_value] = i;
1709 set_sound_parameters(i, sound->parameter);
1712 free(sound_effect_properties);
1715 static void InitGameModeMusicInfo()
1717 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1718 int num_property_mappings = getMusicListPropertyMappingSize();
1719 int default_levelset_music = -1;
1722 /* set values to -1 to identify later as "uninitialized" values */
1723 for (i = 0; i < MAX_LEVELS; i++)
1724 levelset.music[i] = -1;
1725 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1728 /* initialize gamemode/music mapping from static configuration */
1729 for (i = 0; gamemode_to_music[i].music > -1; i++)
1731 int gamemode = gamemode_to_music[i].gamemode;
1732 int music = gamemode_to_music[i].music;
1735 printf("::: gamemode == %d, music == %d\n", gamemode, music);
1739 gamemode = GAME_MODE_DEFAULT;
1741 menu.music[gamemode] = music;
1744 /* initialize gamemode/music mapping from dynamic configuration */
1745 for (i = 0; i < num_property_mappings; i++)
1747 int prefix = property_mapping[i].base_index;
1748 int gamemode = property_mapping[i].ext1_index;
1749 int level = property_mapping[i].ext2_index;
1750 int music = property_mapping[i].artwork_index;
1753 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
1754 prefix, gamemode, level, music);
1757 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1761 gamemode = GAME_MODE_DEFAULT;
1763 /* level specific music only allowed for in-game music */
1764 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1765 gamemode = GAME_MODE_PLAYING;
1770 default_levelset_music = music;
1773 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1774 levelset.music[level] = music;
1775 if (gamemode != GAME_MODE_PLAYING)
1776 menu.music[gamemode] = music;
1779 /* now set all '-1' values to menu specific default values */
1780 /* (undefined values of "levelset.music[]" might stay at "-1" to
1781 allow dynamic selection of music files from music directory!) */
1782 for (i = 0; i < MAX_LEVELS; i++)
1783 if (levelset.music[i] == -1)
1784 levelset.music[i] = default_levelset_music;
1785 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1786 if (menu.music[i] == -1)
1787 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1790 for (i = 0; i < MAX_LEVELS; i++)
1791 if (levelset.music[i] != -1)
1792 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
1793 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1794 if (menu.music[i] != -1)
1795 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
1799 static void set_music_parameters(int music, char **parameter_raw)
1801 int parameter[NUM_MUS_ARGS];
1804 /* get integer values from string parameters */
1805 for (i = 0; i < NUM_MUS_ARGS; i++)
1807 get_parameter_value(parameter_raw[i],
1808 music_config_suffix[i].token,
1809 music_config_suffix[i].type);
1811 /* explicit loop mode setting in configuration overrides default value */
1812 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1813 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1816 static void InitMusicInfo()
1818 int num_music = getMusicListSize();
1821 checked_free(music_info);
1823 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1825 for (i = 0; i < num_music; i++)
1827 struct FileInfo *music = getMusicListEntry(i);
1828 int len_music_text = strlen(music->token);
1830 music_info[i].loop = TRUE; /* default: play music in loop mode */
1832 /* determine all loop music */
1834 for (j = 0; music_prefix_info[j].prefix; j++)
1836 int len_prefix_text = strlen(music_prefix_info[j].prefix);
1838 if (len_prefix_text < len_music_text &&
1839 strncmp(music->token,
1840 music_prefix_info[j].prefix, len_prefix_text) == 0)
1842 music_info[i].loop = music_prefix_info[j].is_loop_music;
1848 set_music_parameters(i, music->parameter);
1852 static void ReinitializeGraphics()
1854 InitGraphicInfo(); /* graphic properties mapping */
1855 InitElementGraphicInfo(); /* element game graphic mapping */
1856 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
1858 InitElementSmallImages(); /* scale elements to all needed sizes */
1859 InitScaledImages(); /* scale all other images, if needed */
1860 InitFontGraphicInfo(); /* initialize text drawing functions */
1862 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
1864 SetMainBackgroundImage(IMG_BACKGROUND);
1865 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1871 static void ReinitializeSounds()
1873 InitSoundInfo(); /* sound properties mapping */
1874 InitElementSoundInfo(); /* element game sound mapping */
1875 InitGameModeSoundInfo(); /* game mode sound mapping */
1877 InitPlayLevelSound(); /* internal game sound settings */
1880 static void ReinitializeMusic()
1882 InitMusicInfo(); /* music properties mapping */
1883 InitGameModeMusicInfo(); /* game mode music mapping */
1886 static int get_special_property_bit(int element, int property_bit_nr)
1888 struct PropertyBitInfo
1894 static struct PropertyBitInfo pb_can_move_into_acid[] =
1896 /* the player may be able fall into acid when gravity is activated */
1901 { EL_SP_MURPHY, 0 },
1902 { EL_SOKOBAN_FIELD_PLAYER, 0 },
1904 /* all elements that can move may be able to also move into acid */
1907 { EL_BUG_RIGHT, 1 },
1910 { EL_SPACESHIP, 2 },
1911 { EL_SPACESHIP_LEFT, 2 },
1912 { EL_SPACESHIP_RIGHT, 2 },
1913 { EL_SPACESHIP_UP, 2 },
1914 { EL_SPACESHIP_DOWN, 2 },
1915 { EL_BD_BUTTERFLY, 3 },
1916 { EL_BD_BUTTERFLY_LEFT, 3 },
1917 { EL_BD_BUTTERFLY_RIGHT, 3 },
1918 { EL_BD_BUTTERFLY_UP, 3 },
1919 { EL_BD_BUTTERFLY_DOWN, 3 },
1920 { EL_BD_FIREFLY, 4 },
1921 { EL_BD_FIREFLY_LEFT, 4 },
1922 { EL_BD_FIREFLY_RIGHT, 4 },
1923 { EL_BD_FIREFLY_UP, 4 },
1924 { EL_BD_FIREFLY_DOWN, 4 },
1926 { EL_YAMYAM_LEFT, 5 },
1927 { EL_YAMYAM_RIGHT, 5 },
1928 { EL_YAMYAM_UP, 5 },
1929 { EL_YAMYAM_DOWN, 5 },
1930 { EL_DARK_YAMYAM, 6 },
1933 { EL_PACMAN_LEFT, 8 },
1934 { EL_PACMAN_RIGHT, 8 },
1935 { EL_PACMAN_UP, 8 },
1936 { EL_PACMAN_DOWN, 8 },
1938 { EL_MOLE_LEFT, 9 },
1939 { EL_MOLE_RIGHT, 9 },
1941 { EL_MOLE_DOWN, 9 },
1945 { EL_SATELLITE, 13 },
1946 { EL_SP_SNIKSNAK, 14 },
1947 { EL_SP_ELECTRON, 15 },
1950 { EL_EMC_ANDROID, 18 },
1955 static struct PropertyBitInfo pb_dont_collide_with[] =
1957 { EL_SP_SNIKSNAK, 0 },
1958 { EL_SP_ELECTRON, 1 },
1966 struct PropertyBitInfo *pb_info;
1969 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
1970 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
1975 struct PropertyBitInfo *pb_info = NULL;
1978 for (i = 0; pb_definition[i].bit_nr != -1; i++)
1979 if (pb_definition[i].bit_nr == property_bit_nr)
1980 pb_info = pb_definition[i].pb_info;
1982 if (pb_info == NULL)
1985 for (i = 0; pb_info[i].element != -1; i++)
1986 if (pb_info[i].element == element)
1987 return pb_info[i].bit_nr;
1992 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
1993 boolean property_value)
1995 int bit_nr = get_special_property_bit(element, property_bit_nr);
2000 *bitfield |= (1 << bit_nr);
2002 *bitfield &= ~(1 << bit_nr);
2006 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2008 int bit_nr = get_special_property_bit(element, property_bit_nr);
2011 return ((*bitfield & (1 << bit_nr)) != 0);
2016 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2018 static int group_nr;
2019 static struct ElementGroupInfo *group;
2020 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2023 if (actual_group == NULL) /* not yet initialized */
2026 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
2028 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2029 group_element - EL_GROUP_START + 1);
2031 /* replace element which caused too deep recursion by question mark */
2032 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2037 if (recursion_depth == 0) /* initialization */
2039 group = actual_group;
2040 group_nr = GROUP_NR(group_element);
2042 group->num_elements_resolved = 0;
2043 group->choice_pos = 0;
2045 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2046 element_info[i].in_group[group_nr] = FALSE;
2049 for (i = 0; i < actual_group->num_elements; i++)
2051 int element = actual_group->element[i];
2053 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2056 if (IS_GROUP_ELEMENT(element))
2057 ResolveGroupElementExt(element, recursion_depth + 1);
2060 group->element_resolved[group->num_elements_resolved++] = element;
2061 element_info[element].in_group[group_nr] = TRUE;
2066 void ResolveGroupElement(int group_element)
2068 ResolveGroupElementExt(group_element, 0);
2071 void InitElementPropertiesStatic()
2073 static int ep_diggable[] =
2078 EL_SP_BUGGY_BASE_ACTIVATING,
2081 EL_INVISIBLE_SAND_ACTIVE,
2084 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2085 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2090 EL_SP_BUGGY_BASE_ACTIVE,
2097 static int ep_collectible_only[] =
2119 EL_DYNABOMB_INCREASE_NUMBER,
2120 EL_DYNABOMB_INCREASE_SIZE,
2121 EL_DYNABOMB_INCREASE_POWER,
2139 /* !!! handle separately !!! */
2140 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2146 static int ep_dont_run_into[] =
2148 /* same elements as in 'ep_dont_touch' */
2154 /* same elements as in 'ep_dont_collide_with' */
2166 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2171 EL_SP_BUGGY_BASE_ACTIVE,
2178 static int ep_dont_collide_with[] =
2180 /* same elements as in 'ep_dont_touch' */
2197 static int ep_dont_touch[] =
2207 static int ep_indestructible[] =
2211 EL_ACID_POOL_TOPLEFT,
2212 EL_ACID_POOL_TOPRIGHT,
2213 EL_ACID_POOL_BOTTOMLEFT,
2214 EL_ACID_POOL_BOTTOM,
2215 EL_ACID_POOL_BOTTOMRIGHT,
2216 EL_SP_HARDWARE_GRAY,
2217 EL_SP_HARDWARE_GREEN,
2218 EL_SP_HARDWARE_BLUE,
2220 EL_SP_HARDWARE_YELLOW,
2221 EL_SP_HARDWARE_BASE_1,
2222 EL_SP_HARDWARE_BASE_2,
2223 EL_SP_HARDWARE_BASE_3,
2224 EL_SP_HARDWARE_BASE_4,
2225 EL_SP_HARDWARE_BASE_5,
2226 EL_SP_HARDWARE_BASE_6,
2227 EL_INVISIBLE_STEELWALL,
2228 EL_INVISIBLE_STEELWALL_ACTIVE,
2229 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2230 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2231 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2232 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2233 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2234 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2235 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2236 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2237 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2238 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2239 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2240 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2242 EL_LIGHT_SWITCH_ACTIVE,
2243 EL_SIGN_EXCLAMATION,
2244 EL_SIGN_RADIOACTIVITY,
2251 EL_SIGN_ENTRY_FORBIDDEN,
2252 EL_SIGN_EMERGENCY_EXIT,
2260 EL_STEEL_EXIT_CLOSED,
2262 EL_EM_STEEL_EXIT_CLOSED,
2263 EL_EM_STEEL_EXIT_OPEN,
2264 EL_DC_STEELWALL_1_LEFT,
2265 EL_DC_STEELWALL_1_RIGHT,
2266 EL_DC_STEELWALL_1_TOP,
2267 EL_DC_STEELWALL_1_BOTTOM,
2268 EL_DC_STEELWALL_1_HORIZONTAL,
2269 EL_DC_STEELWALL_1_VERTICAL,
2270 EL_DC_STEELWALL_1_TOPLEFT,
2271 EL_DC_STEELWALL_1_TOPRIGHT,
2272 EL_DC_STEELWALL_1_BOTTOMLEFT,
2273 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2274 EL_DC_STEELWALL_1_TOPLEFT_2,
2275 EL_DC_STEELWALL_1_TOPRIGHT_2,
2276 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2277 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2278 EL_DC_STEELWALL_2_LEFT,
2279 EL_DC_STEELWALL_2_RIGHT,
2280 EL_DC_STEELWALL_2_TOP,
2281 EL_DC_STEELWALL_2_BOTTOM,
2282 EL_DC_STEELWALL_2_HORIZONTAL,
2283 EL_DC_STEELWALL_2_VERTICAL,
2284 EL_DC_STEELWALL_2_MIDDLE,
2285 EL_DC_STEELWALL_2_SINGLE,
2286 EL_STEELWALL_SLIPPERY,
2300 EL_GATE_1_GRAY_ACTIVE,
2301 EL_GATE_2_GRAY_ACTIVE,
2302 EL_GATE_3_GRAY_ACTIVE,
2303 EL_GATE_4_GRAY_ACTIVE,
2312 EL_EM_GATE_1_GRAY_ACTIVE,
2313 EL_EM_GATE_2_GRAY_ACTIVE,
2314 EL_EM_GATE_3_GRAY_ACTIVE,
2315 EL_EM_GATE_4_GRAY_ACTIVE,
2324 EL_EMC_GATE_5_GRAY_ACTIVE,
2325 EL_EMC_GATE_6_GRAY_ACTIVE,
2326 EL_EMC_GATE_7_GRAY_ACTIVE,
2327 EL_EMC_GATE_8_GRAY_ACTIVE,
2329 EL_DC_GATE_WHITE_GRAY,
2330 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2331 EL_DC_GATE_FAKE_GRAY,
2333 EL_SWITCHGATE_OPENING,
2334 EL_SWITCHGATE_CLOSED,
2335 EL_SWITCHGATE_CLOSING,
2337 EL_DC_SWITCHGATE_SWITCH_UP,
2338 EL_DC_SWITCHGATE_SWITCH_DOWN,
2341 EL_TIMEGATE_OPENING,
2343 EL_TIMEGATE_CLOSING,
2345 EL_DC_TIMEGATE_SWITCH,
2346 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2351 EL_TUBE_VERTICAL_LEFT,
2352 EL_TUBE_VERTICAL_RIGHT,
2353 EL_TUBE_HORIZONTAL_UP,
2354 EL_TUBE_HORIZONTAL_DOWN,
2359 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2360 EL_EXPANDABLE_STEELWALL_VERTICAL,
2361 EL_EXPANDABLE_STEELWALL_ANY,
2366 static int ep_slippery[] =
2380 EL_ROBOT_WHEEL_ACTIVE,
2386 EL_ACID_POOL_TOPLEFT,
2387 EL_ACID_POOL_TOPRIGHT,
2397 EL_STEELWALL_SLIPPERY,
2400 EL_EMC_WALL_SLIPPERY_1,
2401 EL_EMC_WALL_SLIPPERY_2,
2402 EL_EMC_WALL_SLIPPERY_3,
2403 EL_EMC_WALL_SLIPPERY_4,
2405 EL_EMC_MAGIC_BALL_ACTIVE,
2410 static int ep_can_change[] =
2415 static int ep_can_move[] =
2417 /* same elements as in 'pb_can_move_into_acid' */
2440 static int ep_can_fall[] =
2454 EL_QUICKSAND_FAST_FULL,
2456 EL_BD_MAGIC_WALL_FULL,
2457 EL_DC_MAGIC_WALL_FULL,
2471 static int ep_can_smash_player[] =
2497 static int ep_can_smash_enemies[] =
2506 static int ep_can_smash_everything[] =
2515 static int ep_explodes_by_fire[] =
2517 /* same elements as in 'ep_explodes_impact' */
2522 /* same elements as in 'ep_explodes_smashed' */
2532 EL_EM_DYNAMITE_ACTIVE,
2533 EL_DYNABOMB_PLAYER_1_ACTIVE,
2534 EL_DYNABOMB_PLAYER_2_ACTIVE,
2535 EL_DYNABOMB_PLAYER_3_ACTIVE,
2536 EL_DYNABOMB_PLAYER_4_ACTIVE,
2537 EL_DYNABOMB_INCREASE_NUMBER,
2538 EL_DYNABOMB_INCREASE_SIZE,
2539 EL_DYNABOMB_INCREASE_POWER,
2540 EL_SP_DISK_RED_ACTIVE,
2554 static int ep_explodes_smashed[] =
2556 /* same elements as in 'ep_explodes_impact' */
2570 static int ep_explodes_impact[] =
2579 static int ep_walkable_over[] =
2583 EL_SOKOBAN_FIELD_EMPTY,
2589 EL_EM_STEEL_EXIT_OPEN,
2598 EL_GATE_1_GRAY_ACTIVE,
2599 EL_GATE_2_GRAY_ACTIVE,
2600 EL_GATE_3_GRAY_ACTIVE,
2601 EL_GATE_4_GRAY_ACTIVE,
2609 static int ep_walkable_inside[] =
2614 EL_TUBE_VERTICAL_LEFT,
2615 EL_TUBE_VERTICAL_RIGHT,
2616 EL_TUBE_HORIZONTAL_UP,
2617 EL_TUBE_HORIZONTAL_DOWN,
2626 static int ep_walkable_under[] =
2631 static int ep_passable_over[] =
2641 EL_EM_GATE_1_GRAY_ACTIVE,
2642 EL_EM_GATE_2_GRAY_ACTIVE,
2643 EL_EM_GATE_3_GRAY_ACTIVE,
2644 EL_EM_GATE_4_GRAY_ACTIVE,
2653 EL_EMC_GATE_5_GRAY_ACTIVE,
2654 EL_EMC_GATE_6_GRAY_ACTIVE,
2655 EL_EMC_GATE_7_GRAY_ACTIVE,
2656 EL_EMC_GATE_8_GRAY_ACTIVE,
2658 EL_DC_GATE_WHITE_GRAY,
2659 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2666 static int ep_passable_inside[] =
2672 EL_SP_PORT_HORIZONTAL,
2673 EL_SP_PORT_VERTICAL,
2675 EL_SP_GRAVITY_PORT_LEFT,
2676 EL_SP_GRAVITY_PORT_RIGHT,
2677 EL_SP_GRAVITY_PORT_UP,
2678 EL_SP_GRAVITY_PORT_DOWN,
2679 EL_SP_GRAVITY_ON_PORT_LEFT,
2680 EL_SP_GRAVITY_ON_PORT_RIGHT,
2681 EL_SP_GRAVITY_ON_PORT_UP,
2682 EL_SP_GRAVITY_ON_PORT_DOWN,
2683 EL_SP_GRAVITY_OFF_PORT_LEFT,
2684 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2685 EL_SP_GRAVITY_OFF_PORT_UP,
2686 EL_SP_GRAVITY_OFF_PORT_DOWN,
2691 static int ep_passable_under[] =
2696 static int ep_droppable[] =
2701 static int ep_explodes_1x1_old[] =
2706 static int ep_pushable[] =
2718 EL_SOKOBAN_FIELD_FULL,
2727 static int ep_explodes_cross_old[] =
2732 static int ep_protected[] =
2734 /* same elements as in 'ep_walkable_inside' */
2738 EL_TUBE_VERTICAL_LEFT,
2739 EL_TUBE_VERTICAL_RIGHT,
2740 EL_TUBE_HORIZONTAL_UP,
2741 EL_TUBE_HORIZONTAL_DOWN,
2747 /* same elements as in 'ep_passable_over' */
2756 EL_EM_GATE_1_GRAY_ACTIVE,
2757 EL_EM_GATE_2_GRAY_ACTIVE,
2758 EL_EM_GATE_3_GRAY_ACTIVE,
2759 EL_EM_GATE_4_GRAY_ACTIVE,
2768 EL_EMC_GATE_5_GRAY_ACTIVE,
2769 EL_EMC_GATE_6_GRAY_ACTIVE,
2770 EL_EMC_GATE_7_GRAY_ACTIVE,
2771 EL_EMC_GATE_8_GRAY_ACTIVE,
2773 EL_DC_GATE_WHITE_GRAY,
2774 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2778 /* same elements as in 'ep_passable_inside' */
2783 EL_SP_PORT_HORIZONTAL,
2784 EL_SP_PORT_VERTICAL,
2786 EL_SP_GRAVITY_PORT_LEFT,
2787 EL_SP_GRAVITY_PORT_RIGHT,
2788 EL_SP_GRAVITY_PORT_UP,
2789 EL_SP_GRAVITY_PORT_DOWN,
2790 EL_SP_GRAVITY_ON_PORT_LEFT,
2791 EL_SP_GRAVITY_ON_PORT_RIGHT,
2792 EL_SP_GRAVITY_ON_PORT_UP,
2793 EL_SP_GRAVITY_ON_PORT_DOWN,
2794 EL_SP_GRAVITY_OFF_PORT_LEFT,
2795 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2796 EL_SP_GRAVITY_OFF_PORT_UP,
2797 EL_SP_GRAVITY_OFF_PORT_DOWN,
2802 static int ep_throwable[] =
2807 static int ep_can_explode[] =
2809 /* same elements as in 'ep_explodes_impact' */
2814 /* same elements as in 'ep_explodes_smashed' */
2820 /* elements that can explode by explosion or by dragonfire */
2824 EL_EM_DYNAMITE_ACTIVE,
2825 EL_DYNABOMB_PLAYER_1_ACTIVE,
2826 EL_DYNABOMB_PLAYER_2_ACTIVE,
2827 EL_DYNABOMB_PLAYER_3_ACTIVE,
2828 EL_DYNABOMB_PLAYER_4_ACTIVE,
2829 EL_DYNABOMB_INCREASE_NUMBER,
2830 EL_DYNABOMB_INCREASE_SIZE,
2831 EL_DYNABOMB_INCREASE_POWER,
2832 EL_SP_DISK_RED_ACTIVE,
2840 /* elements that can explode only by explosion */
2846 static int ep_gravity_reachable[] =
2852 EL_INVISIBLE_SAND_ACTIVE,
2857 EL_SP_PORT_HORIZONTAL,
2858 EL_SP_PORT_VERTICAL,
2860 EL_SP_GRAVITY_PORT_LEFT,
2861 EL_SP_GRAVITY_PORT_RIGHT,
2862 EL_SP_GRAVITY_PORT_UP,
2863 EL_SP_GRAVITY_PORT_DOWN,
2864 EL_SP_GRAVITY_ON_PORT_LEFT,
2865 EL_SP_GRAVITY_ON_PORT_RIGHT,
2866 EL_SP_GRAVITY_ON_PORT_UP,
2867 EL_SP_GRAVITY_ON_PORT_DOWN,
2868 EL_SP_GRAVITY_OFF_PORT_LEFT,
2869 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2870 EL_SP_GRAVITY_OFF_PORT_UP,
2871 EL_SP_GRAVITY_OFF_PORT_DOWN,
2877 static int ep_player[] =
2884 EL_SOKOBAN_FIELD_PLAYER,
2890 static int ep_can_pass_magic_wall[] =
2904 static int ep_can_pass_dc_magic_wall[] =
2920 static int ep_switchable[] =
2924 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2925 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2926 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2927 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2928 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2929 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2930 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2931 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2932 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2933 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2934 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2935 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2936 EL_SWITCHGATE_SWITCH_UP,
2937 EL_SWITCHGATE_SWITCH_DOWN,
2938 EL_DC_SWITCHGATE_SWITCH_UP,
2939 EL_DC_SWITCHGATE_SWITCH_DOWN,
2941 EL_LIGHT_SWITCH_ACTIVE,
2943 EL_DC_TIMEGATE_SWITCH,
2944 EL_BALLOON_SWITCH_LEFT,
2945 EL_BALLOON_SWITCH_RIGHT,
2946 EL_BALLOON_SWITCH_UP,
2947 EL_BALLOON_SWITCH_DOWN,
2948 EL_BALLOON_SWITCH_ANY,
2949 EL_BALLOON_SWITCH_NONE,
2952 EL_EMC_MAGIC_BALL_SWITCH,
2953 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
2958 static int ep_bd_element[] =
2992 static int ep_sp_element[] =
2994 /* should always be valid */
2997 /* standard classic Supaplex elements */
3004 EL_SP_HARDWARE_GRAY,
3012 EL_SP_GRAVITY_PORT_RIGHT,
3013 EL_SP_GRAVITY_PORT_DOWN,
3014 EL_SP_GRAVITY_PORT_LEFT,
3015 EL_SP_GRAVITY_PORT_UP,
3020 EL_SP_PORT_VERTICAL,
3021 EL_SP_PORT_HORIZONTAL,
3027 EL_SP_HARDWARE_BASE_1,
3028 EL_SP_HARDWARE_GREEN,
3029 EL_SP_HARDWARE_BLUE,
3031 EL_SP_HARDWARE_YELLOW,
3032 EL_SP_HARDWARE_BASE_2,
3033 EL_SP_HARDWARE_BASE_3,
3034 EL_SP_HARDWARE_BASE_4,
3035 EL_SP_HARDWARE_BASE_5,
3036 EL_SP_HARDWARE_BASE_6,
3040 /* additional elements that appeared in newer Supaplex levels */
3043 /* additional gravity port elements (not switching, but setting gravity) */
3044 EL_SP_GRAVITY_ON_PORT_LEFT,
3045 EL_SP_GRAVITY_ON_PORT_RIGHT,
3046 EL_SP_GRAVITY_ON_PORT_UP,
3047 EL_SP_GRAVITY_ON_PORT_DOWN,
3048 EL_SP_GRAVITY_OFF_PORT_LEFT,
3049 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3050 EL_SP_GRAVITY_OFF_PORT_UP,
3051 EL_SP_GRAVITY_OFF_PORT_DOWN,
3053 /* more than one Murphy in a level results in an inactive clone */
3056 /* runtime Supaplex elements */
3057 EL_SP_DISK_RED_ACTIVE,
3058 EL_SP_TERMINAL_ACTIVE,
3059 EL_SP_BUGGY_BASE_ACTIVATING,
3060 EL_SP_BUGGY_BASE_ACTIVE,
3067 static int ep_sb_element[] =
3072 EL_SOKOBAN_FIELD_EMPTY,
3073 EL_SOKOBAN_FIELD_FULL,
3074 EL_SOKOBAN_FIELD_PLAYER,
3079 EL_INVISIBLE_STEELWALL,
3084 static int ep_gem[] =
3096 static int ep_food_dark_yamyam[] =
3124 static int ep_food_penguin[] =
3138 static int ep_food_pig[] =
3150 static int ep_historic_wall[] =
3161 EL_GATE_1_GRAY_ACTIVE,
3162 EL_GATE_2_GRAY_ACTIVE,
3163 EL_GATE_3_GRAY_ACTIVE,
3164 EL_GATE_4_GRAY_ACTIVE,
3173 EL_EM_GATE_1_GRAY_ACTIVE,
3174 EL_EM_GATE_2_GRAY_ACTIVE,
3175 EL_EM_GATE_3_GRAY_ACTIVE,
3176 EL_EM_GATE_4_GRAY_ACTIVE,
3183 EL_EXPANDABLE_WALL_HORIZONTAL,
3184 EL_EXPANDABLE_WALL_VERTICAL,
3185 EL_EXPANDABLE_WALL_ANY,
3186 EL_EXPANDABLE_WALL_GROWING,
3187 EL_BD_EXPANDABLE_WALL,
3194 EL_SP_HARDWARE_GRAY,
3195 EL_SP_HARDWARE_GREEN,
3196 EL_SP_HARDWARE_BLUE,
3198 EL_SP_HARDWARE_YELLOW,
3199 EL_SP_HARDWARE_BASE_1,
3200 EL_SP_HARDWARE_BASE_2,
3201 EL_SP_HARDWARE_BASE_3,
3202 EL_SP_HARDWARE_BASE_4,
3203 EL_SP_HARDWARE_BASE_5,
3204 EL_SP_HARDWARE_BASE_6,
3206 EL_SP_TERMINAL_ACTIVE,
3209 EL_INVISIBLE_STEELWALL,
3210 EL_INVISIBLE_STEELWALL_ACTIVE,
3212 EL_INVISIBLE_WALL_ACTIVE,
3213 EL_STEELWALL_SLIPPERY,
3230 static int ep_historic_solid[] =
3234 EL_EXPANDABLE_WALL_HORIZONTAL,
3235 EL_EXPANDABLE_WALL_VERTICAL,
3236 EL_EXPANDABLE_WALL_ANY,
3237 EL_BD_EXPANDABLE_WALL,
3250 EL_QUICKSAND_FILLING,
3251 EL_QUICKSAND_EMPTYING,
3253 EL_MAGIC_WALL_ACTIVE,
3254 EL_MAGIC_WALL_EMPTYING,
3255 EL_MAGIC_WALL_FILLING,
3259 EL_BD_MAGIC_WALL_ACTIVE,
3260 EL_BD_MAGIC_WALL_EMPTYING,
3261 EL_BD_MAGIC_WALL_FULL,
3262 EL_BD_MAGIC_WALL_FILLING,
3263 EL_BD_MAGIC_WALL_DEAD,
3272 EL_SP_TERMINAL_ACTIVE,
3276 EL_INVISIBLE_WALL_ACTIVE,
3277 EL_SWITCHGATE_SWITCH_UP,
3278 EL_SWITCHGATE_SWITCH_DOWN,
3279 EL_DC_SWITCHGATE_SWITCH_UP,
3280 EL_DC_SWITCHGATE_SWITCH_DOWN,
3282 EL_TIMEGATE_SWITCH_ACTIVE,
3283 EL_DC_TIMEGATE_SWITCH,
3284 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3296 /* the following elements are a direct copy of "indestructible" elements,
3297 except "EL_ACID", which is "indestructible", but not "solid"! */
3302 EL_ACID_POOL_TOPLEFT,
3303 EL_ACID_POOL_TOPRIGHT,
3304 EL_ACID_POOL_BOTTOMLEFT,
3305 EL_ACID_POOL_BOTTOM,
3306 EL_ACID_POOL_BOTTOMRIGHT,
3307 EL_SP_HARDWARE_GRAY,
3308 EL_SP_HARDWARE_GREEN,
3309 EL_SP_HARDWARE_BLUE,
3311 EL_SP_HARDWARE_YELLOW,
3312 EL_SP_HARDWARE_BASE_1,
3313 EL_SP_HARDWARE_BASE_2,
3314 EL_SP_HARDWARE_BASE_3,
3315 EL_SP_HARDWARE_BASE_4,
3316 EL_SP_HARDWARE_BASE_5,
3317 EL_SP_HARDWARE_BASE_6,
3318 EL_INVISIBLE_STEELWALL,
3319 EL_INVISIBLE_STEELWALL_ACTIVE,
3320 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3321 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3322 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3323 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3324 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3325 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3326 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3327 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3328 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3329 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3330 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3331 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3333 EL_LIGHT_SWITCH_ACTIVE,
3334 EL_SIGN_EXCLAMATION,
3335 EL_SIGN_RADIOACTIVITY,
3342 EL_SIGN_ENTRY_FORBIDDEN,
3343 EL_SIGN_EMERGENCY_EXIT,
3351 EL_STEEL_EXIT_CLOSED,
3353 EL_DC_STEELWALL_1_LEFT,
3354 EL_DC_STEELWALL_1_RIGHT,
3355 EL_DC_STEELWALL_1_TOP,
3356 EL_DC_STEELWALL_1_BOTTOM,
3357 EL_DC_STEELWALL_1_HORIZONTAL,
3358 EL_DC_STEELWALL_1_VERTICAL,
3359 EL_DC_STEELWALL_1_TOPLEFT,
3360 EL_DC_STEELWALL_1_TOPRIGHT,
3361 EL_DC_STEELWALL_1_BOTTOMLEFT,
3362 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3363 EL_DC_STEELWALL_1_TOPLEFT_2,
3364 EL_DC_STEELWALL_1_TOPRIGHT_2,
3365 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3366 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3367 EL_DC_STEELWALL_2_LEFT,
3368 EL_DC_STEELWALL_2_RIGHT,
3369 EL_DC_STEELWALL_2_TOP,
3370 EL_DC_STEELWALL_2_BOTTOM,
3371 EL_DC_STEELWALL_2_HORIZONTAL,
3372 EL_DC_STEELWALL_2_VERTICAL,
3373 EL_DC_STEELWALL_2_MIDDLE,
3374 EL_DC_STEELWALL_2_SINGLE,
3375 EL_STEELWALL_SLIPPERY,
3389 EL_GATE_1_GRAY_ACTIVE,
3390 EL_GATE_2_GRAY_ACTIVE,
3391 EL_GATE_3_GRAY_ACTIVE,
3392 EL_GATE_4_GRAY_ACTIVE,
3401 EL_EM_GATE_1_GRAY_ACTIVE,
3402 EL_EM_GATE_2_GRAY_ACTIVE,
3403 EL_EM_GATE_3_GRAY_ACTIVE,
3404 EL_EM_GATE_4_GRAY_ACTIVE,
3406 EL_SWITCHGATE_OPENING,
3407 EL_SWITCHGATE_CLOSED,
3408 EL_SWITCHGATE_CLOSING,
3410 EL_TIMEGATE_OPENING,
3412 EL_TIMEGATE_CLOSING,
3416 EL_TUBE_VERTICAL_LEFT,
3417 EL_TUBE_VERTICAL_RIGHT,
3418 EL_TUBE_HORIZONTAL_UP,
3419 EL_TUBE_HORIZONTAL_DOWN,
3428 static int ep_classic_enemy[] =
3445 static int ep_belt[] =
3447 EL_CONVEYOR_BELT_1_LEFT,
3448 EL_CONVEYOR_BELT_1_MIDDLE,
3449 EL_CONVEYOR_BELT_1_RIGHT,
3450 EL_CONVEYOR_BELT_2_LEFT,
3451 EL_CONVEYOR_BELT_2_MIDDLE,
3452 EL_CONVEYOR_BELT_2_RIGHT,
3453 EL_CONVEYOR_BELT_3_LEFT,
3454 EL_CONVEYOR_BELT_3_MIDDLE,
3455 EL_CONVEYOR_BELT_3_RIGHT,
3456 EL_CONVEYOR_BELT_4_LEFT,
3457 EL_CONVEYOR_BELT_4_MIDDLE,
3458 EL_CONVEYOR_BELT_4_RIGHT,
3463 static int ep_belt_active[] =
3465 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3466 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3467 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3468 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3469 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3470 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3471 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3472 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3473 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3474 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3475 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3476 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3481 static int ep_belt_switch[] =
3483 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3484 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3485 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3486 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3487 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3488 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3489 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3490 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3491 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3492 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3493 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3494 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3499 static int ep_tube[] =
3506 EL_TUBE_HORIZONTAL_UP,
3507 EL_TUBE_HORIZONTAL_DOWN,
3509 EL_TUBE_VERTICAL_LEFT,
3510 EL_TUBE_VERTICAL_RIGHT,
3516 static int ep_acid_pool[] =
3518 EL_ACID_POOL_TOPLEFT,
3519 EL_ACID_POOL_TOPRIGHT,
3520 EL_ACID_POOL_BOTTOMLEFT,
3521 EL_ACID_POOL_BOTTOM,
3522 EL_ACID_POOL_BOTTOMRIGHT,
3527 static int ep_keygate[] =
3537 EL_GATE_1_GRAY_ACTIVE,
3538 EL_GATE_2_GRAY_ACTIVE,
3539 EL_GATE_3_GRAY_ACTIVE,
3540 EL_GATE_4_GRAY_ACTIVE,
3549 EL_EM_GATE_1_GRAY_ACTIVE,
3550 EL_EM_GATE_2_GRAY_ACTIVE,
3551 EL_EM_GATE_3_GRAY_ACTIVE,
3552 EL_EM_GATE_4_GRAY_ACTIVE,
3561 EL_EMC_GATE_5_GRAY_ACTIVE,
3562 EL_EMC_GATE_6_GRAY_ACTIVE,
3563 EL_EMC_GATE_7_GRAY_ACTIVE,
3564 EL_EMC_GATE_8_GRAY_ACTIVE,
3566 EL_DC_GATE_WHITE_GRAY,
3567 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3572 static int ep_amoeboid[] =
3584 static int ep_amoebalive[] =
3595 static int ep_has_editor_content[] =
3617 static int ep_can_turn_each_move[] =
3619 /* !!! do something with this one !!! */
3623 static int ep_can_grow[] =
3637 static int ep_active_bomb[] =
3640 EL_EM_DYNAMITE_ACTIVE,
3641 EL_DYNABOMB_PLAYER_1_ACTIVE,
3642 EL_DYNABOMB_PLAYER_2_ACTIVE,
3643 EL_DYNABOMB_PLAYER_3_ACTIVE,
3644 EL_DYNABOMB_PLAYER_4_ACTIVE,
3645 EL_SP_DISK_RED_ACTIVE,
3650 static int ep_inactive[] =
3660 EL_QUICKSAND_FAST_EMPTY,
3683 EL_GATE_1_GRAY_ACTIVE,
3684 EL_GATE_2_GRAY_ACTIVE,
3685 EL_GATE_3_GRAY_ACTIVE,
3686 EL_GATE_4_GRAY_ACTIVE,
3695 EL_EM_GATE_1_GRAY_ACTIVE,
3696 EL_EM_GATE_2_GRAY_ACTIVE,
3697 EL_EM_GATE_3_GRAY_ACTIVE,
3698 EL_EM_GATE_4_GRAY_ACTIVE,
3707 EL_EMC_GATE_5_GRAY_ACTIVE,
3708 EL_EMC_GATE_6_GRAY_ACTIVE,
3709 EL_EMC_GATE_7_GRAY_ACTIVE,
3710 EL_EMC_GATE_8_GRAY_ACTIVE,
3712 EL_DC_GATE_WHITE_GRAY,
3713 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3714 EL_DC_GATE_FAKE_GRAY,
3717 EL_INVISIBLE_STEELWALL,
3725 EL_WALL_EMERALD_YELLOW,
3726 EL_DYNABOMB_INCREASE_NUMBER,
3727 EL_DYNABOMB_INCREASE_SIZE,
3728 EL_DYNABOMB_INCREASE_POWER,
3732 EL_SOKOBAN_FIELD_EMPTY,
3733 EL_SOKOBAN_FIELD_FULL,
3734 EL_WALL_EMERALD_RED,
3735 EL_WALL_EMERALD_PURPLE,
3736 EL_ACID_POOL_TOPLEFT,
3737 EL_ACID_POOL_TOPRIGHT,
3738 EL_ACID_POOL_BOTTOMLEFT,
3739 EL_ACID_POOL_BOTTOM,
3740 EL_ACID_POOL_BOTTOMRIGHT,
3744 EL_BD_MAGIC_WALL_DEAD,
3746 EL_DC_MAGIC_WALL_DEAD,
3747 EL_AMOEBA_TO_DIAMOND,
3755 EL_SP_GRAVITY_PORT_RIGHT,
3756 EL_SP_GRAVITY_PORT_DOWN,
3757 EL_SP_GRAVITY_PORT_LEFT,
3758 EL_SP_GRAVITY_PORT_UP,
3759 EL_SP_PORT_HORIZONTAL,
3760 EL_SP_PORT_VERTICAL,
3771 EL_SP_HARDWARE_GRAY,
3772 EL_SP_HARDWARE_GREEN,
3773 EL_SP_HARDWARE_BLUE,
3775 EL_SP_HARDWARE_YELLOW,
3776 EL_SP_HARDWARE_BASE_1,
3777 EL_SP_HARDWARE_BASE_2,
3778 EL_SP_HARDWARE_BASE_3,
3779 EL_SP_HARDWARE_BASE_4,
3780 EL_SP_HARDWARE_BASE_5,
3781 EL_SP_HARDWARE_BASE_6,
3782 EL_SP_GRAVITY_ON_PORT_LEFT,
3783 EL_SP_GRAVITY_ON_PORT_RIGHT,
3784 EL_SP_GRAVITY_ON_PORT_UP,
3785 EL_SP_GRAVITY_ON_PORT_DOWN,
3786 EL_SP_GRAVITY_OFF_PORT_LEFT,
3787 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3788 EL_SP_GRAVITY_OFF_PORT_UP,
3789 EL_SP_GRAVITY_OFF_PORT_DOWN,
3790 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3791 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3792 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3793 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3794 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3795 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3796 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3797 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3798 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3799 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3800 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3801 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3802 EL_SIGN_EXCLAMATION,
3803 EL_SIGN_RADIOACTIVITY,
3810 EL_SIGN_ENTRY_FORBIDDEN,
3811 EL_SIGN_EMERGENCY_EXIT,
3819 EL_DC_STEELWALL_1_LEFT,
3820 EL_DC_STEELWALL_1_RIGHT,
3821 EL_DC_STEELWALL_1_TOP,
3822 EL_DC_STEELWALL_1_BOTTOM,
3823 EL_DC_STEELWALL_1_HORIZONTAL,
3824 EL_DC_STEELWALL_1_VERTICAL,
3825 EL_DC_STEELWALL_1_TOPLEFT,
3826 EL_DC_STEELWALL_1_TOPRIGHT,
3827 EL_DC_STEELWALL_1_BOTTOMLEFT,
3828 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3829 EL_DC_STEELWALL_1_TOPLEFT_2,
3830 EL_DC_STEELWALL_1_TOPRIGHT_2,
3831 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3832 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3833 EL_DC_STEELWALL_2_LEFT,
3834 EL_DC_STEELWALL_2_RIGHT,
3835 EL_DC_STEELWALL_2_TOP,
3836 EL_DC_STEELWALL_2_BOTTOM,
3837 EL_DC_STEELWALL_2_HORIZONTAL,
3838 EL_DC_STEELWALL_2_VERTICAL,
3839 EL_DC_STEELWALL_2_MIDDLE,
3840 EL_DC_STEELWALL_2_SINGLE,
3841 EL_STEELWALL_SLIPPERY,
3846 EL_EMC_WALL_SLIPPERY_1,
3847 EL_EMC_WALL_SLIPPERY_2,
3848 EL_EMC_WALL_SLIPPERY_3,
3849 EL_EMC_WALL_SLIPPERY_4,
3870 static int ep_em_slippery_wall[] =
3875 static int ep_gfx_crumbled[] =
3886 static int ep_editor_cascade_active[] =
3888 EL_INTERNAL_CASCADE_BD_ACTIVE,
3889 EL_INTERNAL_CASCADE_EM_ACTIVE,
3890 EL_INTERNAL_CASCADE_EMC_ACTIVE,
3891 EL_INTERNAL_CASCADE_RND_ACTIVE,
3892 EL_INTERNAL_CASCADE_SB_ACTIVE,
3893 EL_INTERNAL_CASCADE_SP_ACTIVE,
3894 EL_INTERNAL_CASCADE_DC_ACTIVE,
3895 EL_INTERNAL_CASCADE_DX_ACTIVE,
3896 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
3897 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
3898 EL_INTERNAL_CASCADE_CE_ACTIVE,
3899 EL_INTERNAL_CASCADE_GE_ACTIVE,
3900 EL_INTERNAL_CASCADE_REF_ACTIVE,
3901 EL_INTERNAL_CASCADE_USER_ACTIVE,
3902 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
3907 static int ep_editor_cascade_inactive[] =
3909 EL_INTERNAL_CASCADE_BD,
3910 EL_INTERNAL_CASCADE_EM,
3911 EL_INTERNAL_CASCADE_EMC,
3912 EL_INTERNAL_CASCADE_RND,
3913 EL_INTERNAL_CASCADE_SB,
3914 EL_INTERNAL_CASCADE_SP,
3915 EL_INTERNAL_CASCADE_DC,
3916 EL_INTERNAL_CASCADE_DX,
3917 EL_INTERNAL_CASCADE_CHARS,
3918 EL_INTERNAL_CASCADE_STEEL_CHARS,
3919 EL_INTERNAL_CASCADE_CE,
3920 EL_INTERNAL_CASCADE_GE,
3921 EL_INTERNAL_CASCADE_REF,
3922 EL_INTERNAL_CASCADE_USER,
3923 EL_INTERNAL_CASCADE_DYNAMIC,
3928 static int ep_obsolete[] =
3932 EL_EM_KEY_1_FILE_OBSOLETE,
3933 EL_EM_KEY_2_FILE_OBSOLETE,
3934 EL_EM_KEY_3_FILE_OBSOLETE,
3935 EL_EM_KEY_4_FILE_OBSOLETE,
3936 EL_ENVELOPE_OBSOLETE,
3945 } element_properties[] =
3947 { ep_diggable, EP_DIGGABLE },
3948 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
3949 { ep_dont_run_into, EP_DONT_RUN_INTO },
3950 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
3951 { ep_dont_touch, EP_DONT_TOUCH },
3952 { ep_indestructible, EP_INDESTRUCTIBLE },
3953 { ep_slippery, EP_SLIPPERY },
3954 { ep_can_change, EP_CAN_CHANGE },
3955 { ep_can_move, EP_CAN_MOVE },
3956 { ep_can_fall, EP_CAN_FALL },
3957 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
3958 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
3959 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
3960 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
3961 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
3962 { ep_explodes_impact, EP_EXPLODES_IMPACT },
3963 { ep_walkable_over, EP_WALKABLE_OVER },
3964 { ep_walkable_inside, EP_WALKABLE_INSIDE },
3965 { ep_walkable_under, EP_WALKABLE_UNDER },
3966 { ep_passable_over, EP_PASSABLE_OVER },
3967 { ep_passable_inside, EP_PASSABLE_INSIDE },
3968 { ep_passable_under, EP_PASSABLE_UNDER },
3969 { ep_droppable, EP_DROPPABLE },
3970 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
3971 { ep_pushable, EP_PUSHABLE },
3972 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
3973 { ep_protected, EP_PROTECTED },
3974 { ep_throwable, EP_THROWABLE },
3975 { ep_can_explode, EP_CAN_EXPLODE },
3976 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
3978 { ep_player, EP_PLAYER },
3979 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
3980 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
3981 { ep_switchable, EP_SWITCHABLE },
3982 { ep_bd_element, EP_BD_ELEMENT },
3983 { ep_sp_element, EP_SP_ELEMENT },
3984 { ep_sb_element, EP_SB_ELEMENT },
3986 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
3987 { ep_food_penguin, EP_FOOD_PENGUIN },
3988 { ep_food_pig, EP_FOOD_PIG },
3989 { ep_historic_wall, EP_HISTORIC_WALL },
3990 { ep_historic_solid, EP_HISTORIC_SOLID },
3991 { ep_classic_enemy, EP_CLASSIC_ENEMY },
3992 { ep_belt, EP_BELT },
3993 { ep_belt_active, EP_BELT_ACTIVE },
3994 { ep_belt_switch, EP_BELT_SWITCH },
3995 { ep_tube, EP_TUBE },
3996 { ep_acid_pool, EP_ACID_POOL },
3997 { ep_keygate, EP_KEYGATE },
3998 { ep_amoeboid, EP_AMOEBOID },
3999 { ep_amoebalive, EP_AMOEBALIVE },
4000 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4001 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4002 { ep_can_grow, EP_CAN_GROW },
4003 { ep_active_bomb, EP_ACTIVE_BOMB },
4004 { ep_inactive, EP_INACTIVE },
4006 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4008 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4010 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4011 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4013 { ep_obsolete, EP_OBSOLETE },
4020 /* always start with reliable default values (element has no properties) */
4021 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4022 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4023 SET_PROPERTY(i, j, FALSE);
4025 /* set all base element properties from above array definitions */
4026 for (i = 0; element_properties[i].elements != NULL; i++)
4027 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4028 SET_PROPERTY((element_properties[i].elements)[j],
4029 element_properties[i].property, TRUE);
4031 /* copy properties to some elements that are only stored in level file */
4032 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4033 for (j = 0; copy_properties[j][0] != -1; j++)
4034 if (HAS_PROPERTY(copy_properties[j][0], i))
4035 for (k = 1; k <= 4; k++)
4036 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4038 /* set static element properties that are not listed in array definitions */
4039 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4040 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4043 void InitElementPropertiesEngine(int engine_version)
4045 static int no_wall_properties[] =
4048 EP_COLLECTIBLE_ONLY,
4050 EP_DONT_COLLIDE_WITH,
4053 EP_CAN_SMASH_PLAYER,
4054 EP_CAN_SMASH_ENEMIES,
4055 EP_CAN_SMASH_EVERYTHING,
4060 EP_FOOD_DARK_YAMYAM,
4076 /* important: after initialization in InitElementPropertiesStatic(), the
4077 elements are not again initialized to a default value; therefore all
4078 changes have to make sure that they leave the element with a defined
4079 property (which means that conditional property changes must be set to
4080 a reliable default value before) */
4082 /* resolve group elements */
4083 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4084 ResolveGroupElement(EL_GROUP_START + i);
4086 /* set all special, combined or engine dependent element properties */
4087 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4089 /* ---------- INACTIVE ------------------------------------------------- */
4090 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4091 i <= EL_CHAR_END) ||
4092 (i >= EL_STEEL_CHAR_START &&
4093 i <= EL_STEEL_CHAR_END)));
4095 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4096 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4097 IS_WALKABLE_INSIDE(i) ||
4098 IS_WALKABLE_UNDER(i)));
4100 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4101 IS_PASSABLE_INSIDE(i) ||
4102 IS_PASSABLE_UNDER(i)));
4104 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4105 IS_PASSABLE_OVER(i)));
4107 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4108 IS_PASSABLE_INSIDE(i)));
4110 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4111 IS_PASSABLE_UNDER(i)));
4113 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4116 /* ---------- COLLECTIBLE ---------------------------------------------- */
4117 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4121 /* ---------- SNAPPABLE ------------------------------------------------ */
4122 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4123 IS_COLLECTIBLE(i) ||
4127 /* ---------- WALL ----------------------------------------------------- */
4128 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4130 for (j = 0; no_wall_properties[j] != -1; j++)
4131 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4132 i >= EL_FIRST_RUNTIME_UNREAL)
4133 SET_PROPERTY(i, EP_WALL, FALSE);
4135 if (IS_HISTORIC_WALL(i))
4136 SET_PROPERTY(i, EP_WALL, TRUE);
4138 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4139 if (engine_version < VERSION_IDENT(2,2,0,0))
4140 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4142 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4144 !IS_COLLECTIBLE(i)));
4146 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4147 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4148 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4150 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4151 IS_INDESTRUCTIBLE(i)));
4153 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4155 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4156 else if (engine_version < VERSION_IDENT(2,2,0,0))
4157 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4159 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4163 if (IS_CUSTOM_ELEMENT(i))
4165 /* these are additional properties which are initially false when set */
4167 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4169 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4170 if (DONT_COLLIDE_WITH(i))
4171 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4173 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4174 if (CAN_SMASH_EVERYTHING(i))
4175 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4176 if (CAN_SMASH_ENEMIES(i))
4177 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4180 /* ---------- CAN_SMASH ------------------------------------------------ */
4181 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4182 CAN_SMASH_ENEMIES(i) ||
4183 CAN_SMASH_EVERYTHING(i)));
4185 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4186 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4187 EXPLODES_BY_FIRE(i)));
4189 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4190 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4191 EXPLODES_SMASHED(i)));
4193 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4194 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4195 EXPLODES_IMPACT(i)));
4197 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4198 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4200 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4201 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4202 i == EL_BLACK_ORB));
4204 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4205 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4207 IS_CUSTOM_ELEMENT(i)));
4209 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4210 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4211 i == EL_SP_ELECTRON));
4213 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4214 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4215 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4216 getMoveIntoAcidProperty(&level, i));
4218 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4219 if (MAYBE_DONT_COLLIDE_WITH(i))
4220 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4221 getDontCollideWithProperty(&level, i));
4223 /* ---------- SP_PORT -------------------------------------------------- */
4224 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4225 IS_PASSABLE_INSIDE(i)));
4227 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4228 for (j = 0; j < level.num_android_clone_elements; j++)
4229 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4231 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4233 /* ---------- CAN_CHANGE ----------------------------------------------- */
4234 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4235 for (j = 0; j < element_info[i].num_change_pages; j++)
4236 if (element_info[i].change_page[j].can_change)
4237 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4239 /* ---------- HAS_ACTION ----------------------------------------------- */
4240 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4241 for (j = 0; j < element_info[i].num_change_pages; j++)
4242 if (element_info[i].change_page[j].has_action)
4243 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4245 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4246 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4249 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4251 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4252 element_info[i].crumbled[ACTION_DEFAULT] !=
4253 element_info[i].graphic[ACTION_DEFAULT]);
4255 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
4256 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4257 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
4260 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4261 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4262 IS_EDITOR_CASCADE_INACTIVE(i)));
4265 /* dynamically adjust element properties according to game engine version */
4267 static int ep_em_slippery_wall[] =
4272 EL_EXPANDABLE_WALL_HORIZONTAL,
4273 EL_EXPANDABLE_WALL_VERTICAL,
4274 EL_EXPANDABLE_WALL_ANY,
4275 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4276 EL_EXPANDABLE_STEELWALL_VERTICAL,
4277 EL_EXPANDABLE_STEELWALL_ANY,
4278 EL_EXPANDABLE_STEELWALL_GROWING,
4282 /* special EM style gems behaviour */
4283 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4284 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4285 level.em_slippery_gems);
4287 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4288 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4289 (level.em_slippery_gems &&
4290 engine_version > VERSION_IDENT(2,0,1,0)));
4293 /* this is needed because some graphics depend on element properties */
4294 if (game_status == GAME_MODE_PLAYING)
4295 InitElementGraphicInfo();
4298 void InitElementPropertiesAfterLoading(int engine_version)
4302 /* set some other uninitialized values of custom elements in older levels */
4303 if (engine_version < VERSION_IDENT(3,1,0,0))
4305 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4307 int element = EL_CUSTOM_START + i;
4309 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4311 element_info[element].explosion_delay = 17;
4312 element_info[element].ignition_delay = 8;
4317 static void InitGlobal()
4321 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4323 /* check if element_name_info entry defined for each element in "main.h" */
4324 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4325 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4327 element_info[i].token_name = element_name_info[i].token_name;
4328 element_info[i].class_name = element_name_info[i].class_name;
4329 element_info[i].editor_description=element_name_info[i].editor_description;
4332 printf("%04d: %s\n", i, element_name_info[i].token_name);
4336 global.autoplay_leveldir = NULL;
4337 global.convert_leveldir = NULL;
4339 global.frames_per_second = 0;
4340 global.fps_slowdown = FALSE;
4341 global.fps_slowdown_factor = 1;
4344 void Execute_Command(char *command)
4348 if (strEqual(command, "print graphicsinfo.conf"))
4350 printf("# You can configure additional/alternative image files here.\n");
4351 printf("# (The entries below are default and therefore commented out.)\n");
4353 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4355 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4358 for (i = 0; image_config[i].token != NULL; i++)
4359 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
4360 image_config[i].value));
4364 else if (strEqual(command, "print soundsinfo.conf"))
4366 printf("# You can configure additional/alternative sound files here.\n");
4367 printf("# (The entries below are default and therefore commented out.)\n");
4369 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4371 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4374 for (i = 0; sound_config[i].token != NULL; i++)
4375 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4376 sound_config[i].value));
4380 else if (strEqual(command, "print musicinfo.conf"))
4382 printf("# You can configure additional/alternative music files here.\n");
4383 printf("# (The entries below are default and therefore commented out.)\n");
4385 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4387 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4390 for (i = 0; music_config[i].token != NULL; i++)
4391 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
4392 music_config[i].value));
4396 else if (strEqual(command, "print editorsetup.conf"))
4398 printf("# You can configure your personal editor element list here.\n");
4399 printf("# (The entries below are default and therefore commented out.)\n");
4402 /* this is needed to be able to check element list for cascade elements */
4403 InitElementPropertiesStatic();
4404 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4406 PrintEditorElementList();
4410 else if (strEqual(command, "print helpanim.conf"))
4412 printf("# You can configure different element help animations here.\n");
4413 printf("# (The entries below are default and therefore commented out.)\n");
4416 for (i = 0; helpanim_config[i].token != NULL; i++)
4418 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4419 helpanim_config[i].value));
4421 if (strEqual(helpanim_config[i].token, "end"))
4427 else if (strEqual(command, "print helptext.conf"))
4429 printf("# You can configure different element help text here.\n");
4430 printf("# (The entries below are default and therefore commented out.)\n");
4433 for (i = 0; helptext_config[i].token != NULL; i++)
4434 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4435 helptext_config[i].value));
4439 else if (strncmp(command, "dump level ", 11) == 0)
4441 char *filename = &command[11];
4443 if (!fileExists(filename))
4444 Error(ERR_EXIT, "cannot open file '%s'", filename);
4446 LoadLevelFromFilename(&level, filename);
4451 else if (strncmp(command, "dump tape ", 10) == 0)
4453 char *filename = &command[10];
4455 if (!fileExists(filename))
4456 Error(ERR_EXIT, "cannot open file '%s'", filename);
4458 LoadTapeFromFilename(filename);
4463 else if (strncmp(command, "autoplay ", 9) == 0)
4465 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
4467 while (*str_ptr != '\0') /* continue parsing string */
4469 /* cut leading whitespace from string, replace it by string terminator */
4470 while (*str_ptr == ' ' || *str_ptr == '\t')
4473 if (*str_ptr == '\0') /* end of string reached */
4476 if (global.autoplay_leveldir == NULL) /* read level set string */
4478 global.autoplay_leveldir = str_ptr;
4479 global.autoplay_all = TRUE; /* default: play all tapes */
4481 for (i = 0; i < MAX_TAPES_PER_SET; i++)
4482 global.autoplay_level[i] = FALSE;
4484 else /* read level number string */
4486 int level_nr = atoi(str_ptr); /* get level_nr value */
4488 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
4489 global.autoplay_level[level_nr] = TRUE;
4491 global.autoplay_all = FALSE;
4494 /* advance string pointer to the next whitespace (or end of string) */
4495 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
4499 else if (strncmp(command, "convert ", 8) == 0)
4501 char *str_copy = getStringCopy(&command[8]);
4502 char *str_ptr = strchr(str_copy, ' ');
4504 global.convert_leveldir = str_copy;
4505 global.convert_level_nr = -1;
4507 if (str_ptr != NULL) /* level number follows */
4509 *str_ptr++ = '\0'; /* terminate leveldir string */
4510 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
4515 #if defined(TARGET_SDL)
4516 else if (strEqual(command, "SDL_ListModes"))
4521 SDL_Init(SDL_INIT_VIDEO);
4523 /* get available fullscreen/hardware modes */
4524 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
4526 /* check if there are any modes available */
4529 printf("No modes available!\n");
4534 /* check if our resolution is restricted */
4535 if (modes == (SDL_Rect **)-1)
4537 printf("All resolutions available.\n");
4541 printf("Available Modes:\n");
4543 for(i = 0; modes[i]; i++)
4544 printf(" %d x %d\n", modes[i]->w, modes[i]->h);
4554 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4558 static void InitSetup()
4560 LoadSetup(); /* global setup info */
4562 /* set some options from setup file */
4564 if (setup.options.verbose)
4565 options.verbose = TRUE;
4568 static void InitGameInfo()
4570 game.restart_level = FALSE;
4573 static void InitPlayerInfo()
4577 /* choose default local player */
4578 local_player = &stored_player[0];
4580 for (i = 0; i < MAX_PLAYERS; i++)
4581 stored_player[i].connected = FALSE;
4583 local_player->connected = TRUE;
4586 static void InitArtworkInfo()
4591 static char *get_string_in_brackets(char *string)
4593 char *string_in_brackets = checked_malloc(strlen(string) + 3);
4595 sprintf(string_in_brackets, "[%s]", string);
4597 return string_in_brackets;
4600 static char *get_level_id_suffix(int id_nr)
4602 char *id_suffix = checked_malloc(1 + 3 + 1);
4604 if (id_nr < 0 || id_nr > 999)
4607 sprintf(id_suffix, ".%03d", id_nr);
4613 static char *get_element_class_token(int element)
4615 char *element_class_name = element_info[element].class_name;
4616 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
4618 sprintf(element_class_token, "[%s]", element_class_name);
4620 return element_class_token;
4623 static char *get_action_class_token(int action)
4625 char *action_class_name = &element_action_info[action].suffix[1];
4626 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
4628 sprintf(action_class_token, "[%s]", action_class_name);
4630 return action_class_token;
4634 static void InitArtworkConfig()
4636 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
4637 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
4638 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
4639 static char *action_id_suffix[NUM_ACTIONS + 1];
4640 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
4641 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
4642 static char *level_id_suffix[MAX_LEVELS + 1];
4643 static char *dummy[1] = { NULL };
4644 static char *ignore_generic_tokens[] =
4650 static char **ignore_image_tokens;
4651 static char **ignore_sound_tokens;
4652 static char **ignore_music_tokens;
4653 int num_ignore_generic_tokens;
4654 int num_ignore_image_tokens;
4655 int num_ignore_sound_tokens;
4656 int num_ignore_music_tokens;
4659 /* dynamically determine list of generic tokens to be ignored */
4660 num_ignore_generic_tokens = 0;
4661 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
4662 num_ignore_generic_tokens++;
4664 /* dynamically determine list of image tokens to be ignored */
4665 num_ignore_image_tokens = num_ignore_generic_tokens;
4666 for (i = 0; image_config_vars[i].token != NULL; i++)
4667 num_ignore_image_tokens++;
4668 ignore_image_tokens =
4669 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
4670 for (i = 0; i < num_ignore_generic_tokens; i++)
4671 ignore_image_tokens[i] = ignore_generic_tokens[i];
4672 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
4673 ignore_image_tokens[num_ignore_generic_tokens + i] =
4674 image_config_vars[i].token;
4675 ignore_image_tokens[num_ignore_image_tokens] = NULL;
4677 /* dynamically determine list of sound tokens to be ignored */
4678 num_ignore_sound_tokens = num_ignore_generic_tokens;
4679 ignore_sound_tokens =
4680 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
4681 for (i = 0; i < num_ignore_generic_tokens; i++)
4682 ignore_sound_tokens[i] = ignore_generic_tokens[i];
4683 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
4685 /* dynamically determine list of music tokens to be ignored */
4686 num_ignore_music_tokens = num_ignore_generic_tokens;
4687 ignore_music_tokens =
4688 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
4689 for (i = 0; i < num_ignore_generic_tokens; i++)
4690 ignore_music_tokens[i] = ignore_generic_tokens[i];
4691 ignore_music_tokens[num_ignore_music_tokens] = NULL;
4693 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4694 image_id_prefix[i] = element_info[i].token_name;
4695 for (i = 0; i < NUM_FONTS; i++)
4696 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
4697 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
4699 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4700 sound_id_prefix[i] = element_info[i].token_name;
4701 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4702 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
4703 get_string_in_brackets(element_info[i].class_name);
4704 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
4706 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
4707 music_id_prefix[i] = music_prefix_info[i].prefix;
4708 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
4710 for (i = 0; i < NUM_ACTIONS; i++)
4711 action_id_suffix[i] = element_action_info[i].suffix;
4712 action_id_suffix[NUM_ACTIONS] = NULL;
4714 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
4715 direction_id_suffix[i] = element_direction_info[i].suffix;
4716 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
4718 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
4719 special_id_suffix[i] = special_suffix_info[i].suffix;
4720 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
4722 for (i = 0; i < MAX_LEVELS; i++)
4723 level_id_suffix[i] = get_level_id_suffix(i);
4724 level_id_suffix[MAX_LEVELS] = NULL;
4726 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
4727 image_id_prefix, action_id_suffix, direction_id_suffix,
4728 special_id_suffix, ignore_image_tokens);
4729 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
4730 sound_id_prefix, action_id_suffix, dummy,
4731 special_id_suffix, ignore_sound_tokens);
4732 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
4733 music_id_prefix, special_id_suffix, level_id_suffix,
4734 dummy, ignore_music_tokens);
4737 static void InitMixer()
4745 char *filename_font_initial = NULL;
4746 Bitmap *bitmap_font_initial = NULL;
4750 /* determine settings for initial font (for displaying startup messages) */
4751 for (i = 0; image_config[i].token != NULL; i++)
4753 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4755 char font_token[128];
4758 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
4759 len_font_token = strlen(font_token);
4761 if (strEqual(image_config[i].token, font_token))
4762 filename_font_initial = image_config[i].value;
4763 else if (strlen(image_config[i].token) > len_font_token &&
4764 strncmp(image_config[i].token, font_token, len_font_token) == 0)
4766 if (strEqual(&image_config[i].token[len_font_token], ".x"))
4767 font_initial[j].src_x = atoi(image_config[i].value);
4768 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
4769 font_initial[j].src_y = atoi(image_config[i].value);
4770 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
4771 font_initial[j].width = atoi(image_config[i].value);
4772 else if (strEqual(&image_config[i].token[len_font_token],".height"))
4773 font_initial[j].height = atoi(image_config[i].value);
4778 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4780 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
4781 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
4784 if (filename_font_initial == NULL) /* should not happen */
4785 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
4787 /* create additional image buffers for double-buffering and cross-fading */
4788 bitmap_db_cross = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
4789 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
4790 bitmap_db_panel = CreateBitmap(DXSIZE, DYSIZE, DEFAULT_DEPTH);
4791 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
4793 /* initialize screen properties */
4794 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
4795 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
4797 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
4798 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
4799 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
4801 bitmap_font_initial = LoadCustomImage(filename_font_initial);
4803 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4804 font_initial[j].bitmap = bitmap_font_initial;
4806 InitFontGraphicInfo();
4808 font_height = getFontHeight(FC_RED);
4811 DrawInitText(getWindowTitleString(), 20, FC_YELLOW);
4813 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
4815 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
4816 DrawInitText(PROGRAM_WEBSITE_STRING, WIN_YSIZE - 20 - font_height, FC_RED);
4818 DrawInitText("Loading graphics", 120, FC_GREEN);
4821 void RedrawBackground()
4823 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
4824 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
4826 redraw_mask = REDRAW_ALL;
4829 void InitGfxBackground()
4833 fieldbuffer = bitmap_db_field;
4834 SetDrawtoField(DRAW_BACKBUFFER);
4838 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
4839 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
4841 for (x = 0; x < MAX_BUF_XSIZE; x++)
4842 for (y = 0; y < MAX_BUF_YSIZE; y++)
4845 redraw_mask = REDRAW_ALL;
4848 static void InitLevelInfo()
4850 LoadLevelInfo(); /* global level info */
4851 LoadLevelSetup_LastSeries(); /* last played series info */
4852 LoadLevelSetup_SeriesInfo(); /* last played level info */
4855 void InitLevelArtworkInfo()
4857 LoadLevelArtworkInfo();
4860 static void InitImages()
4862 setLevelArtworkDir(artwork.gfx_first);
4865 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
4866 leveldir_current->identifier,
4867 artwork.gfx_current_identifier,
4868 artwork.gfx_current->identifier,
4869 leveldir_current->graphics_set,
4870 leveldir_current->graphics_path);
4873 ReloadCustomImages();
4875 LoadCustomElementDescriptions();
4876 LoadSpecialMenuDesignSettings();
4878 ReinitializeGraphics();
4881 static void InitSound(char *identifier)
4883 if (identifier == NULL)
4884 identifier = artwork.snd_current->identifier;
4886 /* set artwork path to send it to the sound server process */
4887 setLevelArtworkDir(artwork.snd_first);
4889 InitReloadCustomSounds(identifier);
4890 ReinitializeSounds();
4893 static void InitMusic(char *identifier)
4895 if (identifier == NULL)
4896 identifier = artwork.mus_current->identifier;
4898 /* set artwork path to send it to the sound server process */
4899 setLevelArtworkDir(artwork.mus_first);
4901 InitReloadCustomMusic(identifier);
4902 ReinitializeMusic();
4905 void InitNetworkServer()
4907 #if defined(NETWORK_AVALIABLE)
4911 if (!options.network)
4914 #if defined(NETWORK_AVALIABLE)
4915 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
4917 if (!ConnectToServer(options.server_host, options.server_port))
4918 Error(ERR_EXIT, "cannot connect to network game server");
4920 SendToServer_PlayerName(setup.player_name);
4921 SendToServer_ProtocolVersion();
4924 SendToServer_NrWanted(nr_wanted);
4928 static char *getNewArtworkIdentifier(int type)
4930 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
4931 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
4932 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
4933 static boolean initialized[3] = { FALSE, FALSE, FALSE };
4934 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
4935 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
4936 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
4937 char *leveldir_identifier = leveldir_current->identifier;
4939 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
4940 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
4942 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
4944 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
4945 char *artwork_current_identifier;
4946 char *artwork_new_identifier = NULL; /* default: nothing has changed */
4948 /* leveldir_current may be invalid (level group, parent link) */
4949 if (!validLevelSeries(leveldir_current))
4952 /* 1st step: determine artwork set to be activated in descending order:
4953 --------------------------------------------------------------------
4954 1. setup artwork (when configured to override everything else)
4955 2. artwork set configured in "levelinfo.conf" of current level set
4956 (artwork in level directory will have priority when loading later)
4957 3. artwork in level directory (stored in artwork sub-directory)
4958 4. setup artwork (currently configured in setup menu) */
4960 if (setup_override_artwork)
4961 artwork_current_identifier = setup_artwork_set;
4962 else if (leveldir_artwork_set != NULL)
4963 artwork_current_identifier = leveldir_artwork_set;
4964 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
4965 artwork_current_identifier = leveldir_identifier;
4967 artwork_current_identifier = setup_artwork_set;
4970 /* 2nd step: check if it is really needed to reload artwork set
4971 ------------------------------------------------------------ */
4974 if (type == ARTWORK_TYPE_GRAPHICS)
4975 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
4976 artwork_new_identifier,
4977 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4978 artwork_current_identifier,
4979 leveldir_current->graphics_set,
4980 leveldir_current->identifier);
4983 /* ---------- reload if level set and also artwork set has changed ------- */
4984 if (leveldir_current_identifier[type] != leveldir_identifier &&
4985 (last_has_level_artwork_set[type] || has_level_artwork_set))
4986 artwork_new_identifier = artwork_current_identifier;
4988 leveldir_current_identifier[type] = leveldir_identifier;
4989 last_has_level_artwork_set[type] = has_level_artwork_set;
4992 if (type == ARTWORK_TYPE_GRAPHICS)
4993 printf("::: 1: '%s'\n", artwork_new_identifier);
4996 /* ---------- reload if "override artwork" setting has changed ----------- */
4997 if (last_override_level_artwork[type] != setup_override_artwork)
4998 artwork_new_identifier = artwork_current_identifier;
5000 last_override_level_artwork[type] = setup_override_artwork;
5003 if (type == ARTWORK_TYPE_GRAPHICS)
5004 printf("::: 2: '%s'\n", artwork_new_identifier);
5007 /* ---------- reload if current artwork identifier has changed ----------- */
5008 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5009 artwork_current_identifier))
5010 artwork_new_identifier = artwork_current_identifier;
5012 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5015 if (type == ARTWORK_TYPE_GRAPHICS)
5016 printf("::: 3: '%s'\n", artwork_new_identifier);
5019 /* ---------- do not reload directly after starting ---------------------- */
5020 if (!initialized[type])
5021 artwork_new_identifier = NULL;
5023 initialized[type] = TRUE;
5026 if (type == ARTWORK_TYPE_GRAPHICS)
5027 printf("::: 4: '%s'\n", artwork_new_identifier);
5031 if (type == ARTWORK_TYPE_GRAPHICS)
5032 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
5033 artwork.gfx_current_identifier, artwork_current_identifier,
5034 artwork.gfx_current->identifier, leveldir_current->graphics_set,
5035 artwork_new_identifier);
5038 return artwork_new_identifier;
5041 void ReloadCustomArtwork(int force_reload)
5043 char *gfx_new_identifier;
5044 char *snd_new_identifier;
5045 char *mus_new_identifier;
5046 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5047 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5048 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5049 boolean redraw_screen = FALSE;
5051 force_reload_gfx |= AdjustGraphicsForEMC();
5053 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5054 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5055 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5057 if (gfx_new_identifier != NULL || force_reload_gfx)
5060 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5061 artwork.gfx_current_identifier,
5063 artwork.gfx_current->identifier,
5064 leveldir_current->graphics_set);
5067 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
5071 redraw_screen = TRUE;
5074 if (snd_new_identifier != NULL || force_reload_snd)
5076 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
5078 InitSound(snd_new_identifier);
5080 redraw_screen = TRUE;
5083 if (mus_new_identifier != NULL || force_reload_mus)
5085 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
5087 InitMusic(mus_new_identifier);
5089 redraw_screen = TRUE;
5096 /* force redraw of (open or closed) door graphics */
5097 SetDoorState(DOOR_OPEN_ALL);
5098 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5102 void KeyboardAutoRepeatOffUnlessAutoplay()
5104 if (global.autoplay_leveldir == NULL)
5105 KeyboardAutoRepeatOff();
5109 /* ========================================================================= */
5111 /* ========================================================================= */
5115 InitGlobal(); /* initialize some global variables */
5117 if (options.execute_command)
5118 Execute_Command(options.execute_command);
5120 if (options.serveronly)
5122 #if defined(PLATFORM_UNIX)
5123 NetworkServer(options.server_port, options.serveronly);
5125 Error(ERR_WARN, "networking only supported in Unix version");
5128 exit(0); /* never reached, server loops forever */
5135 InitArtworkInfo(); /* needed before loading gfx, sound & music */
5136 InitArtworkConfig(); /* needed before forking sound child process */
5141 InitRND(NEW_RANDOMIZE);
5142 InitSimpleRandom(NEW_RANDOMIZE);
5147 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
5149 InitEventFilter(FilterMouseMotionEvents);
5151 InitElementPropertiesStatic();
5152 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5156 // debug_print_timestamp(0, "INIT");
5158 // debug_print_timestamp(0, "TIME InitLevelInfo: ");
5159 InitLevelArtworkInfo();
5160 // debug_print_timestamp(0, "TIME InitLevelArtworkInfo: ");
5162 InitImages(); /* needs to know current level directory */
5163 InitSound(NULL); /* needs to know current level directory */
5164 InitMusic(NULL); /* needs to know current level directory */
5166 InitGfxBackground();
5172 if (global.autoplay_leveldir)
5177 else if (global.convert_leveldir)
5183 game_status = GAME_MODE_MAIN;
5187 InitNetworkServer();
5190 void CloseAllAndExit(int exit_value)
5195 CloseAudio(); /* called after freeing sounds (needed for SDL) */
5203 #if defined(TARGET_SDL)
5204 if (network_server) /* terminate network server */
5205 SDL_KillThread(server_thread);
5208 CloseVideoDisplay();
5209 ClosePlatformDependentStuff();
5211 if (exit_value != 0)
5212 NotifyUserAboutErrorFile();