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 && game_status <= GAME_MODE_PSEUDO_PREVIEW)
171 special = game_status;
172 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
173 special = GFX_SPECIAL_ARG_MAIN;
175 else if (game_status == GAME_MODE_PLAYING)
176 special = GFX_SPECIAL_ARG_DOOR;
180 return font_info[font_nr].special_bitmap_id[special];
185 void InitFontGraphicInfo()
187 static struct FontBitmapInfo *font_bitmap_info = NULL;
188 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
189 int num_property_mappings = getImageListPropertyMappingSize();
190 int num_font_bitmaps = NUM_FONTS;
193 if (graphic_info == NULL) /* still at startup phase */
195 InitFontInfo(font_initial, NUM_INITIAL_FONTS, getFontBitmapID);
200 /* ---------- initialize font graphic definitions ---------- */
202 /* always start with reliable default values (normal font graphics) */
203 for (i = 0; i < NUM_FONTS; i++)
204 font_info[i].graphic = IMG_FONT_INITIAL_1;
206 /* initialize normal font/graphic mapping from static configuration */
207 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
209 int font_nr = font_to_graphic[i].font_nr;
210 int special = font_to_graphic[i].special;
211 int graphic = font_to_graphic[i].graphic;
216 font_info[font_nr].graphic = graphic;
219 /* always start with reliable default values (special font graphics) */
220 for (i = 0; i < NUM_FONTS; i++)
222 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
224 font_info[i].special_graphic[j] = font_info[i].graphic;
225 font_info[i].special_bitmap_id[j] = i;
229 /* initialize special font/graphic mapping from static configuration */
230 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
232 int font_nr = font_to_graphic[i].font_nr;
233 int special = font_to_graphic[i].special;
234 int graphic = font_to_graphic[i].graphic;
235 int base_graphic = font2baseimg(font_nr);
237 if (IS_SPECIAL_GFX_ARG(special))
239 boolean base_redefined =
240 getImageListEntryFromImageID(base_graphic)->redefined;
241 boolean special_redefined =
242 getImageListEntryFromImageID(graphic)->redefined;
243 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
245 /* if the base font ("font.title_1", for example) has been redefined,
246 but not the special font ("font.title_1.LEVELS", for example), do not
247 use an existing (in this case considered obsolete) special font
248 anymore, but use the automatically determined default font */
249 /* special case: cloned special fonts must be explicitly redefined,
250 but are not automatically redefined by redefining base font */
251 if (base_redefined && !special_redefined && !special_cloned)
254 font_info[font_nr].special_graphic[special] = graphic;
255 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
260 /* initialize special font/graphic mapping from dynamic configuration */
261 for (i = 0; i < num_property_mappings; i++)
263 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
264 int special = property_mapping[i].ext3_index;
265 int graphic = property_mapping[i].artwork_index;
270 if (IS_SPECIAL_GFX_ARG(special))
272 font_info[font_nr].special_graphic[special] = graphic;
273 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
278 /* correct special font/graphic mapping for cloned fonts for downwards
279 compatibility of PREVIEW fonts -- this is only needed for implicit
280 redefinition of special font by redefined base font, and only if other
281 fonts are cloned from this special font (like in the "Zelda" level set) */
282 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
284 int font_nr = font_to_graphic[i].font_nr;
285 int special = font_to_graphic[i].special;
286 int graphic = font_to_graphic[i].graphic;
288 if (IS_SPECIAL_GFX_ARG(special))
290 boolean special_redefined =
291 getImageListEntryFromImageID(graphic)->redefined;
292 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
294 if (special_cloned && !special_redefined)
298 for (j = 0; font_to_graphic[j].font_nr > -1; j++)
300 int font_nr2 = font_to_graphic[j].font_nr;
301 int special2 = font_to_graphic[j].special;
302 int graphic2 = font_to_graphic[j].graphic;
304 if (IS_SPECIAL_GFX_ARG(special2) &&
305 graphic2 == graphic_info[graphic].clone_from)
307 font_info[font_nr].special_graphic[special] =
308 font_info[font_nr2].special_graphic[special2];
309 font_info[font_nr].special_bitmap_id[special] =
310 font_info[font_nr2].special_bitmap_id[special2];
317 /* reset non-redefined ".active" font graphics if normal font is redefined */
318 /* (this different treatment is needed because normal and active fonts are
319 independently defined ("active" is not a property of font definitions!) */
320 for (i = 0; i < NUM_FONTS; i++)
322 int font_nr_base = i;
323 int font_nr_active = FONT_ACTIVE(font_nr_base);
325 /* check only those fonts with exist as normal and ".active" variant */
326 if (font_nr_base != font_nr_active)
328 int base_graphic = font_info[font_nr_base].graphic;
329 int active_graphic = font_info[font_nr_active].graphic;
330 boolean base_redefined =
331 getImageListEntryFromImageID(base_graphic)->redefined;
332 boolean active_redefined =
333 getImageListEntryFromImageID(active_graphic)->redefined;
335 /* if the base font ("font.menu_1", for example) has been redefined,
336 but not the active font ("font.menu_1.active", for example), do not
337 use an existing (in this case considered obsolete) active font
338 anymore, but use the automatically determined default font */
339 if (base_redefined && !active_redefined)
340 font_info[font_nr_active].graphic = base_graphic;
342 /* now also check each "special" font (which may be the same as above) */
343 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
345 int base_graphic = font_info[font_nr_base].special_graphic[j];
346 int active_graphic = font_info[font_nr_active].special_graphic[j];
347 boolean base_redefined =
348 getImageListEntryFromImageID(base_graphic)->redefined;
349 boolean active_redefined =
350 getImageListEntryFromImageID(active_graphic)->redefined;
352 /* same as above, but check special graphic definitions, for example:
353 redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN" */
354 if (base_redefined && !active_redefined)
356 font_info[font_nr_active].special_graphic[j] =
357 font_info[font_nr_base].special_graphic[j];
358 font_info[font_nr_active].special_bitmap_id[j] =
359 font_info[font_nr_base].special_bitmap_id[j];
365 /* ---------- initialize font bitmap array ---------- */
367 if (font_bitmap_info != NULL)
368 FreeFontInfo(font_bitmap_info);
371 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
373 /* ---------- initialize font bitmap definitions ---------- */
375 for (i = 0; i < NUM_FONTS; i++)
377 if (i < NUM_INITIAL_FONTS)
379 font_bitmap_info[i] = font_initial[i];
383 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
385 int font_bitmap_id = font_info[i].special_bitmap_id[j];
386 int graphic = font_info[i].special_graphic[j];
388 /* set 'graphic_info' for font entries, if uninitialized (guessed) */
389 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
391 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
392 graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
395 /* copy font relevant information from graphics information */
396 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
397 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
398 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
399 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
400 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
402 font_bitmap_info[font_bitmap_id].draw_xoffset =
403 graphic_info[graphic].draw_xoffset;
404 font_bitmap_info[font_bitmap_id].draw_yoffset =
405 graphic_info[graphic].draw_yoffset;
407 font_bitmap_info[font_bitmap_id].num_chars =
408 graphic_info[graphic].anim_frames;
409 font_bitmap_info[font_bitmap_id].num_chars_per_line =
410 graphic_info[graphic].anim_frames_per_line;
414 InitFontInfo(font_bitmap_info, num_font_bitmaps, getFontBitmapID);
417 void InitElementGraphicInfo()
419 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
420 int num_property_mappings = getImageListPropertyMappingSize();
423 if (graphic_info == NULL) /* still at startup phase */
426 /* set values to -1 to identify later as "uninitialized" values */
427 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
429 for (act = 0; act < NUM_ACTIONS; act++)
431 element_info[i].graphic[act] = -1;
432 element_info[i].crumbled[act] = -1;
434 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
436 element_info[i].direction_graphic[act][dir] = -1;
437 element_info[i].direction_crumbled[act][dir] = -1;
442 /* initialize normal element/graphic mapping from static configuration */
443 for (i = 0; element_to_graphic[i].element > -1; i++)
445 int element = element_to_graphic[i].element;
446 int action = element_to_graphic[i].action;
447 int direction = element_to_graphic[i].direction;
448 boolean crumbled = element_to_graphic[i].crumbled;
449 int graphic = element_to_graphic[i].graphic;
450 int base_graphic = el2baseimg(element);
452 if (graphic_info[graphic].bitmap == NULL)
455 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
458 boolean base_redefined =
459 getImageListEntryFromImageID(base_graphic)->redefined;
460 boolean act_dir_redefined =
461 getImageListEntryFromImageID(graphic)->redefined;
463 /* if the base graphic ("emerald", for example) has been redefined,
464 but not the action graphic ("emerald.falling", for example), do not
465 use an existing (in this case considered obsolete) action graphic
466 anymore, but use the automatically determined default graphic */
467 if (base_redefined && !act_dir_redefined)
472 action = ACTION_DEFAULT;
477 element_info[element].direction_crumbled[action][direction] = graphic;
479 element_info[element].crumbled[action] = graphic;
484 element_info[element].direction_graphic[action][direction] = graphic;
486 element_info[element].graphic[action] = graphic;
490 /* initialize normal element/graphic mapping from dynamic configuration */
491 for (i = 0; i < num_property_mappings; i++)
493 int element = property_mapping[i].base_index;
494 int action = property_mapping[i].ext1_index;
495 int direction = property_mapping[i].ext2_index;
496 int special = property_mapping[i].ext3_index;
497 int graphic = property_mapping[i].artwork_index;
498 boolean crumbled = FALSE;
500 if (special == GFX_SPECIAL_ARG_CRUMBLED)
506 if (graphic_info[graphic].bitmap == NULL)
509 if (element >= MAX_NUM_ELEMENTS || special != -1)
513 action = ACTION_DEFAULT;
518 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
519 element_info[element].direction_crumbled[action][dir] = -1;
522 element_info[element].direction_crumbled[action][direction] = graphic;
524 element_info[element].crumbled[action] = graphic;
529 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
530 element_info[element].direction_graphic[action][dir] = -1;
533 element_info[element].direction_graphic[action][direction] = graphic;
535 element_info[element].graphic[action] = graphic;
539 /* now copy all graphics that are defined to be cloned from other graphics */
540 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
542 int graphic = element_info[i].graphic[ACTION_DEFAULT];
543 int crumbled_like, diggable_like;
548 crumbled_like = graphic_info[graphic].crumbled_like;
549 diggable_like = graphic_info[graphic].diggable_like;
551 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
553 for (act = 0; act < NUM_ACTIONS; act++)
554 element_info[i].crumbled[act] =
555 element_info[crumbled_like].crumbled[act];
556 for (act = 0; act < NUM_ACTIONS; act++)
557 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
558 element_info[i].direction_crumbled[act][dir] =
559 element_info[crumbled_like].direction_crumbled[act][dir];
562 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
564 element_info[i].graphic[ACTION_DIGGING] =
565 element_info[diggable_like].graphic[ACTION_DIGGING];
566 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
567 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
568 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
573 /* set hardcoded definitions for some runtime elements without graphic */
574 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
578 /* set hardcoded definitions for some internal elements without graphic */
579 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
581 if (IS_EDITOR_CASCADE_INACTIVE(i))
582 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
583 else if (IS_EDITOR_CASCADE_ACTIVE(i))
584 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
588 /* now set all undefined/invalid graphics to -1 to set to default after it */
589 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
591 for (act = 0; act < NUM_ACTIONS; act++)
595 graphic = element_info[i].graphic[act];
596 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
597 element_info[i].graphic[act] = -1;
599 graphic = element_info[i].crumbled[act];
600 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
601 element_info[i].crumbled[act] = -1;
603 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
605 graphic = element_info[i].direction_graphic[act][dir];
606 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
607 element_info[i].direction_graphic[act][dir] = -1;
609 graphic = element_info[i].direction_crumbled[act][dir];
610 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
611 element_info[i].direction_crumbled[act][dir] = -1;
616 /* adjust graphics with 2nd tile for movement according to direction
617 (do this before correcting '-1' values to minimize calculations) */
618 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
620 for (act = 0; act < NUM_ACTIONS; act++)
622 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
624 int graphic = element_info[i].direction_graphic[act][dir];
625 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
627 if (act == ACTION_FALLING) /* special case */
628 graphic = element_info[i].graphic[act];
631 graphic_info[graphic].double_movement &&
632 graphic_info[graphic].swap_double_tiles != 0)
634 struct GraphicInfo *g = &graphic_info[graphic];
635 int src_x_front = g->src_x;
636 int src_y_front = g->src_y;
637 int src_x_back = g->src_x + g->offset2_x;
638 int src_y_back = g->src_y + g->offset2_y;
639 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
641 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
642 src_y_front < src_y_back);
643 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
644 boolean swap_movement_tiles_autodetected =
645 (!frames_are_ordered_diagonally &&
646 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
647 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
648 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
649 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
652 /* swap frontside and backside graphic tile coordinates, if needed */
653 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
655 /* get current (wrong) backside tile coordinates */
656 getGraphicSourceExt(graphic, 0, &dummy, &src_x_back, &src_y_back,
659 /* set frontside tile coordinates to backside tile coordinates */
660 g->src_x = src_x_back;
661 g->src_y = src_y_back;
663 /* invert tile offset to point to new backside tile coordinates */
667 /* do not swap front and backside tiles again after correction */
668 g->swap_double_tiles = 0;
675 /* now set all '-1' values to element specific default values */
676 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
678 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
679 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
680 int default_direction_graphic[NUM_DIRECTIONS_FULL];
681 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
683 if (default_graphic == -1)
684 default_graphic = IMG_UNKNOWN;
686 if (default_crumbled == -1)
687 default_crumbled = default_graphic;
689 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
690 if (default_crumbled == -1)
691 default_crumbled = IMG_EMPTY;
694 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
696 default_direction_graphic[dir] =
697 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
698 default_direction_crumbled[dir] =
699 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
701 if (default_direction_graphic[dir] == -1)
702 default_direction_graphic[dir] = default_graphic;
704 if (default_direction_crumbled[dir] == -1)
705 default_direction_crumbled[dir] = default_direction_graphic[dir];
707 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
708 if (default_direction_crumbled[dir] == -1)
709 default_direction_crumbled[dir] = default_crumbled;
713 for (act = 0; act < NUM_ACTIONS; act++)
715 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
716 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
717 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
718 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
719 act == ACTION_TURNING_FROM_RIGHT ||
720 act == ACTION_TURNING_FROM_UP ||
721 act == ACTION_TURNING_FROM_DOWN);
723 /* generic default action graphic (defined by "[default]" directive) */
724 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
725 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
726 int default_remove_graphic = IMG_EMPTY;
728 if (act_remove && default_action_graphic != -1)
729 default_remove_graphic = default_action_graphic;
731 /* look for special default action graphic (classic game specific) */
732 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
733 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
734 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
735 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
736 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
737 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
739 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
740 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
741 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
742 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
743 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
744 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
747 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
748 /* !!! make this better !!! */
749 if (i == EL_EMPTY_SPACE)
751 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
752 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
756 if (default_action_graphic == -1)
757 default_action_graphic = default_graphic;
759 if (default_action_crumbled == -1)
760 default_action_crumbled = default_action_graphic;
762 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
763 if (default_action_crumbled == -1)
764 default_action_crumbled = default_crumbled;
767 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
769 /* use action graphic as the default direction graphic, if undefined */
770 int default_action_direction_graphic = element_info[i].graphic[act];
771 int default_action_direction_crumbled = element_info[i].crumbled[act];
773 /* no graphic for current action -- use default direction graphic */
774 if (default_action_direction_graphic == -1)
775 default_action_direction_graphic =
776 (act_remove ? default_remove_graphic :
778 element_info[i].direction_graphic[ACTION_TURNING][dir] :
779 default_action_graphic != default_graphic ?
780 default_action_graphic :
781 default_direction_graphic[dir]);
783 if (element_info[i].direction_graphic[act][dir] == -1)
784 element_info[i].direction_graphic[act][dir] =
785 default_action_direction_graphic;
788 if (default_action_direction_crumbled == -1)
789 default_action_direction_crumbled =
790 element_info[i].direction_graphic[act][dir];
792 if (default_action_direction_crumbled == -1)
793 default_action_direction_crumbled =
794 (act_remove ? default_remove_graphic :
796 element_info[i].direction_crumbled[ACTION_TURNING][dir] :
797 default_action_crumbled != default_crumbled ?
798 default_action_crumbled :
799 default_direction_crumbled[dir]);
802 if (element_info[i].direction_crumbled[act][dir] == -1)
803 element_info[i].direction_crumbled[act][dir] =
804 default_action_direction_crumbled;
807 /* no graphic for this specific action -- use default action graphic */
808 if (element_info[i].graphic[act] == -1)
809 element_info[i].graphic[act] =
810 (act_remove ? default_remove_graphic :
811 act_turning ? element_info[i].graphic[ACTION_TURNING] :
812 default_action_graphic);
814 if (element_info[i].crumbled[act] == -1)
815 element_info[i].crumbled[act] = element_info[i].graphic[act];
817 if (element_info[i].crumbled[act] == -1)
818 element_info[i].crumbled[act] =
819 (act_remove ? default_remove_graphic :
820 act_turning ? element_info[i].crumbled[ACTION_TURNING] :
821 default_action_crumbled);
827 /* !!! THIS ALSO CLEARS SPECIAL FLAGS (AND IS NOT NEEDED ANYWAY) !!! */
828 /* set animation mode to "none" for each graphic with only 1 frame */
829 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
831 for (act = 0; act < NUM_ACTIONS; act++)
833 int graphic = element_info[i].graphic[act];
834 int crumbled = element_info[i].crumbled[act];
836 if (graphic_info[graphic].anim_frames == 1)
837 graphic_info[graphic].anim_mode = ANIM_NONE;
838 if (graphic_info[crumbled].anim_frames == 1)
839 graphic_info[crumbled].anim_mode = ANIM_NONE;
841 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
843 graphic = element_info[i].direction_graphic[act][dir];
844 crumbled = element_info[i].direction_crumbled[act][dir];
846 if (graphic_info[graphic].anim_frames == 1)
847 graphic_info[graphic].anim_mode = ANIM_NONE;
848 if (graphic_info[crumbled].anim_frames == 1)
849 graphic_info[crumbled].anim_mode = ANIM_NONE;
859 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
860 if (element_info[i].graphic[ACTION_DEFAULT] == IMG_UNKNOWN &&
862 Error(ERR_INFO, "warning: no graphic for element '%s' (%d)",
863 element_info[i].token_name, i);
869 void InitElementSpecialGraphicInfo()
871 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
872 int num_property_mappings = getImageListPropertyMappingSize();
875 /* always start with reliable default values */
876 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
877 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
878 element_info[i].special_graphic[j] =
879 element_info[i].graphic[ACTION_DEFAULT];
881 /* initialize special element/graphic mapping from static configuration */
882 for (i = 0; element_to_special_graphic[i].element > -1; i++)
884 int element = element_to_special_graphic[i].element;
885 int special = element_to_special_graphic[i].special;
886 int graphic = element_to_special_graphic[i].graphic;
887 int base_graphic = el2baseimg(element);
888 boolean base_redefined =
889 getImageListEntryFromImageID(base_graphic)->redefined;
890 boolean special_redefined =
891 getImageListEntryFromImageID(graphic)->redefined;
893 /* if the base graphic ("emerald", for example) has been redefined,
894 but not the special graphic ("emerald.EDITOR", for example), do not
895 use an existing (in this case considered obsolete) special graphic
896 anymore, but use the automatically created (down-scaled) graphic */
897 if (base_redefined && !special_redefined)
900 element_info[element].special_graphic[special] = graphic;
903 /* initialize special element/graphic mapping from dynamic configuration */
904 for (i = 0; i < num_property_mappings; i++)
906 int element = property_mapping[i].base_index;
907 int special = property_mapping[i].ext3_index;
908 int graphic = property_mapping[i].artwork_index;
910 if (element >= MAX_NUM_ELEMENTS)
913 if (IS_SPECIAL_GFX_ARG(special))
914 element_info[element].special_graphic[special] = graphic;
917 /* now set all undefined/invalid graphics to default */
918 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
919 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
920 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
921 element_info[i].special_graphic[j] =
922 element_info[i].graphic[ACTION_DEFAULT];
925 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
930 if (type != TYPE_TOKEN)
931 return get_parameter_value(value_raw, suffix, type);
933 if (strEqual(value_raw, ARG_UNDEFINED))
934 return ARG_UNDEFINED_VALUE;
936 /* !!! OPTIMIZE THIS BY USING HASH !!! */
937 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
938 if (strEqual(element_info[i].token_name, value_raw))
941 /* !!! OPTIMIZE THIS BY USING HASH !!! */
942 for (i = 0; image_config[i].token != NULL; i++)
944 int len_config_value = strlen(image_config[i].value);
946 if (!strEqual(&image_config[i].value[len_config_value - 4], ".pcx") &&
947 !strEqual(&image_config[i].value[len_config_value - 4], ".wav") &&
948 !strEqual(image_config[i].value, UNDEFINED_FILENAME))
951 if (strEqual(image_config[i].token, value_raw))
960 static int get_scaled_graphic_width(int graphic)
962 int original_width = getOriginalImageWidthFromImageID(graphic);
963 int scale_up_factor = graphic_info[graphic].scale_up_factor;
965 return original_width * scale_up_factor;
968 static int get_scaled_graphic_height(int graphic)
970 int original_height = getOriginalImageHeightFromImageID(graphic);
971 int scale_up_factor = graphic_info[graphic].scale_up_factor;
973 return original_height * scale_up_factor;
976 static void set_graphic_parameters(int graphic)
978 struct FileInfo *image = getImageListEntryFromImageID(graphic);
979 char **parameter_raw = image->parameter;
980 Bitmap *src_bitmap = getBitmapFromImageID(graphic);
981 int parameter[NUM_GFX_ARGS];
982 int anim_frames_per_row = 1, anim_frames_per_col = 1;
983 int anim_frames_per_line = 1;
986 /* if fallback to default artwork is done, also use the default parameters */
987 if (image->fallback_to_default)
988 parameter_raw = image->default_parameter;
990 /* get integer values from string parameters */
991 for (i = 0; i < NUM_GFX_ARGS; i++)
992 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
993 image_config_suffix[i].token,
994 image_config_suffix[i].type);
996 graphic_info[graphic].bitmap = src_bitmap;
998 /* always start with reliable default values */
999 graphic_info[graphic].src_image_width = 0;
1000 graphic_info[graphic].src_image_height = 0;
1001 graphic_info[graphic].src_x = 0;
1002 graphic_info[graphic].src_y = 0;
1003 graphic_info[graphic].width = TILEX; /* default for element graphics */
1004 graphic_info[graphic].height = TILEY; /* default for element graphics */
1005 graphic_info[graphic].offset_x = 0; /* one or both of these values ... */
1006 graphic_info[graphic].offset_y = 0; /* ... will be corrected later */
1007 graphic_info[graphic].offset2_x = 0; /* one or both of these values ... */
1008 graphic_info[graphic].offset2_y = 0; /* ... will be corrected later */
1009 graphic_info[graphic].swap_double_tiles = -1; /* auto-detect tile swapping */
1010 graphic_info[graphic].crumbled_like = -1; /* do not use clone element */
1011 graphic_info[graphic].diggable_like = -1; /* do not use clone element */
1012 graphic_info[graphic].border_size = TILEX / 8; /* "CRUMBLED" border size */
1013 graphic_info[graphic].scale_up_factor = 1; /* default: no scaling up */
1014 graphic_info[graphic].clone_from = -1; /* do not use clone graphic */
1015 graphic_info[graphic].anim_delay_fixed = 0;
1016 graphic_info[graphic].anim_delay_random = 0;
1017 graphic_info[graphic].post_delay_fixed = 0;
1018 graphic_info[graphic].post_delay_random = 0;
1019 graphic_info[graphic].fade_delay = -1;
1020 graphic_info[graphic].post_delay = -1;
1021 graphic_info[graphic].auto_delay = -1;
1022 graphic_info[graphic].align = ALIGN_CENTER; /* default for title screens */
1023 graphic_info[graphic].sort_priority = 0; /* default for title screens */
1026 /* optional zoom factor for scaling up the image to a larger size */
1027 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1028 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1029 if (graphic_info[graphic].scale_up_factor < 1)
1030 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
1034 if (graphic_info[graphic].use_image_size)
1036 /* set new default bitmap size (with scaling, but without small images) */
1037 graphic_info[graphic].width = get_scaled_graphic_width(graphic);
1038 graphic_info[graphic].height = get_scaled_graphic_height(graphic);
1042 /* optional x and y tile position of animation frame sequence */
1043 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1044 graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
1045 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1046 graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
1048 /* optional x and y pixel position of animation frame sequence */
1049 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1050 graphic_info[graphic].src_x = parameter[GFX_ARG_X];
1051 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1052 graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
1054 /* optional width and height of each animation frame */
1055 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1056 graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
1057 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1058 graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
1061 /* optional zoom factor for scaling up the image to a larger size */
1062 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1063 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1064 if (graphic_info[graphic].scale_up_factor < 1)
1065 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
1070 /* get final bitmap size (with scaling, but without small images) */
1071 int src_image_width = get_scaled_graphic_width(graphic);
1072 int src_image_height = get_scaled_graphic_height(graphic);
1074 anim_frames_per_row = src_image_width / graphic_info[graphic].width;
1075 anim_frames_per_col = src_image_height / graphic_info[graphic].height;
1077 graphic_info[graphic].src_image_width = src_image_width;
1078 graphic_info[graphic].src_image_height = src_image_height;
1081 /* correct x or y offset dependent of vertical or horizontal frame order */
1082 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1084 graphic_info[graphic].offset_y =
1085 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1086 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
1087 anim_frames_per_line = anim_frames_per_col;
1089 else /* frames are ordered horizontally */
1091 graphic_info[graphic].offset_x =
1092 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1093 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
1094 anim_frames_per_line = anim_frames_per_row;
1097 /* optionally, the x and y offset of frames can be specified directly */
1098 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1099 graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
1100 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1101 graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
1103 /* optionally, moving animations may have separate start and end graphics */
1104 graphic_info[graphic].double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1106 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1107 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1109 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1110 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1111 graphic_info[graphic].offset2_y =
1112 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1113 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].height);
1114 else /* frames are ordered horizontally */
1115 graphic_info[graphic].offset2_x =
1116 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1117 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].width);
1119 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1120 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1121 graphic_info[graphic].offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1122 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1123 graphic_info[graphic].offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1125 /* optionally, the second movement tile can be specified as start tile */
1126 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1127 graphic_info[graphic].swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1129 /* automatically determine correct number of frames, if not defined */
1130 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1131 graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
1132 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1133 graphic_info[graphic].anim_frames = anim_frames_per_row;
1134 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1135 graphic_info[graphic].anim_frames = anim_frames_per_col;
1137 graphic_info[graphic].anim_frames = 1;
1139 if (graphic_info[graphic].anim_frames == 0) /* frames must be at least 1 */
1140 graphic_info[graphic].anim_frames = 1;
1142 graphic_info[graphic].anim_frames_per_line =
1143 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1144 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1146 graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
1147 if (graphic_info[graphic].anim_delay == 0) /* delay must be at least 1 */
1148 graphic_info[graphic].anim_delay = 1;
1150 graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
1152 if (graphic_info[graphic].anim_frames == 1)
1153 graphic_info[graphic].anim_mode = ANIM_NONE;
1156 /* automatically determine correct start frame, if not defined */
1157 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1158 graphic_info[graphic].anim_start_frame = 0;
1159 else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
1160 graphic_info[graphic].anim_start_frame =
1161 graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1163 graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
1165 /* animation synchronized with global frame counter, not move position */
1166 graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1168 /* optional element for cloning crumble graphics */
1169 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1170 graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1172 /* optional element for cloning digging graphics */
1173 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1174 graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1176 /* optional border size for "crumbling" diggable graphics */
1177 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1178 graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
1180 /* this is only used for player "boring" and "sleeping" actions */
1181 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1182 graphic_info[graphic].anim_delay_fixed =
1183 parameter[GFX_ARG_ANIM_DELAY_FIXED];
1184 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1185 graphic_info[graphic].anim_delay_random =
1186 parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1187 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1188 graphic_info[graphic].post_delay_fixed =
1189 parameter[GFX_ARG_POST_DELAY_FIXED];
1190 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1191 graphic_info[graphic].post_delay_random =
1192 parameter[GFX_ARG_POST_DELAY_RANDOM];
1194 /* this is only used for toon animations */
1195 graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
1196 graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY];
1198 /* this is only used for drawing font characters */
1199 graphic_info[graphic].draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1200 graphic_info[graphic].draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1202 /* this is only used for drawing envelope graphics */
1203 graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1205 /* optional graphic for cloning all graphics settings */
1206 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1207 graphic_info[graphic].clone_from = parameter[GFX_ARG_CLONE_FROM];
1209 /* optional settings for drawing title screens */
1210 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1211 graphic_info[graphic].fade_delay = parameter[GFX_ARG_FADE_DELAY];
1212 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1213 graphic_info[graphic].post_delay = parameter[GFX_ARG_POST_DELAY];
1214 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1215 graphic_info[graphic].auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1216 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1217 graphic_info[graphic].align = parameter[GFX_ARG_ALIGN];
1218 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1219 graphic_info[graphic].sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1222 static void set_cloned_graphic_parameters(int graphic)
1224 int fallback_graphic = IMG_CHAR_EXCLAM;
1225 int max_num_images = getImageListSize();
1226 int clone_graphic = graphic_info[graphic].clone_from;
1227 int num_references_followed = 1;
1229 while (graphic_info[clone_graphic].clone_from != -1 &&
1230 num_references_followed < max_num_images)
1232 clone_graphic = graphic_info[clone_graphic].clone_from;
1234 num_references_followed++;
1237 if (num_references_followed >= max_num_images)
1239 Error(ERR_INFO_LINE, "-");
1240 Error(ERR_INFO, "warning: error found in config file:");
1241 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1242 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1243 Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1244 Error(ERR_INFO, "custom graphic rejected for this element/action");
1246 if (graphic == fallback_graphic)
1247 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1249 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1250 Error(ERR_INFO_LINE, "-");
1252 graphic_info[graphic] = graphic_info[fallback_graphic];
1256 graphic_info[graphic] = graphic_info[clone_graphic];
1257 graphic_info[graphic].clone_from = clone_graphic;
1261 static void InitGraphicInfo()
1263 int fallback_graphic = IMG_CHAR_EXCLAM;
1264 int num_images = getImageListSize();
1267 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1268 static boolean clipmasks_initialized = FALSE;
1270 XGCValues clip_gc_values;
1271 unsigned long clip_gc_valuemask;
1272 GC copy_clipmask_gc = None;
1275 /* use image size as default values for width and height for these images */
1276 static int full_size_graphics[] =
1281 IMG_BACKGROUND_ENVELOPE_1,
1282 IMG_BACKGROUND_ENVELOPE_2,
1283 IMG_BACKGROUND_ENVELOPE_3,
1284 IMG_BACKGROUND_ENVELOPE_4,
1287 IMG_BACKGROUND_TITLE,
1288 IMG_BACKGROUND_MESSAGE,
1289 IMG_BACKGROUND_MAIN,
1290 IMG_BACKGROUND_LEVELS,
1291 IMG_BACKGROUND_SCORES,
1292 IMG_BACKGROUND_EDITOR,
1293 IMG_BACKGROUND_INFO,
1294 IMG_BACKGROUND_INFO_ELEMENTS,
1295 IMG_BACKGROUND_INFO_MUSIC,
1296 IMG_BACKGROUND_INFO_CREDITS,
1297 IMG_BACKGROUND_INFO_PROGRAM,
1298 IMG_BACKGROUND_INFO_LEVELSET,
1299 IMG_BACKGROUND_SETUP,
1300 IMG_BACKGROUND_DOOR,
1302 IMG_TITLESCREEN_INITIAL_1,
1303 IMG_TITLESCREEN_INITIAL_2,
1304 IMG_TITLESCREEN_INITIAL_3,
1305 IMG_TITLESCREEN_INITIAL_4,
1306 IMG_TITLESCREEN_INITIAL_5,
1316 checked_free(graphic_info);
1318 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1321 /* initialize "use_image_size" flag with default value */
1322 for (i = 0; i < num_images; i++)
1323 graphic_info[i].use_image_size = FALSE;
1325 /* initialize "use_image_size" flag from static configuration above */
1326 for (i = 0; full_size_graphics[i] != -1; i++)
1327 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1330 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1331 if (clipmasks_initialized)
1333 for (i = 0; i < num_images; i++)
1335 if (graphic_info[i].clip_mask)
1336 XFreePixmap(display, graphic_info[i].clip_mask);
1337 if (graphic_info[i].clip_gc)
1338 XFreeGC(display, graphic_info[i].clip_gc);
1340 graphic_info[i].clip_mask = None;
1341 graphic_info[i].clip_gc = None;
1346 /* first set all graphic paramaters ... */
1347 for (i = 0; i < num_images; i++)
1348 set_graphic_parameters(i);
1350 /* ... then copy these parameters for cloned graphics */
1351 for (i = 0; i < num_images; i++)
1352 if (graphic_info[i].clone_from != -1)
1353 set_cloned_graphic_parameters(i);
1355 for (i = 0; i < num_images; i++)
1360 int first_frame, last_frame;
1361 int src_bitmap_width, src_bitmap_height;
1363 /* now check if no animation frames are outside of the loaded image */
1365 if (graphic_info[i].bitmap == NULL)
1366 continue; /* skip check for optional images that are undefined */
1368 /* get image size (this can differ from the standard element tile size!) */
1369 width = graphic_info[i].width;
1370 height = graphic_info[i].height;
1372 /* get final bitmap size (with scaling, but without small images) */
1373 src_bitmap_width = graphic_info[i].src_image_width;
1374 src_bitmap_height = graphic_info[i].src_image_height;
1376 /* check if first animation frame is inside specified bitmap */
1379 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1382 /* this avoids calculating wrong start position for out-of-bounds frame */
1383 src_x = graphic_info[i].src_x;
1384 src_y = graphic_info[i].src_y;
1387 if (src_x < 0 || src_y < 0 ||
1388 src_x + width > src_bitmap_width ||
1389 src_y + height > src_bitmap_height)
1391 Error(ERR_INFO_LINE, "-");
1392 Error(ERR_INFO, "warning: error found in config file:");
1393 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1394 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1395 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1397 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1398 src_x, src_y, src_bitmap_width, src_bitmap_height);
1399 Error(ERR_INFO, "custom graphic rejected for this element/action");
1401 if (i == fallback_graphic)
1402 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1404 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1405 Error(ERR_INFO_LINE, "-");
1407 graphic_info[i] = graphic_info[fallback_graphic];
1410 /* check if last animation frame is inside specified bitmap */
1412 last_frame = graphic_info[i].anim_frames - 1;
1413 getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1415 if (src_x < 0 || src_y < 0 ||
1416 src_x + width > src_bitmap_width ||
1417 src_y + height > src_bitmap_height)
1419 Error(ERR_INFO_LINE, "-");
1420 Error(ERR_INFO, "warning: error found in config file:");
1421 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1422 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1423 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1425 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1426 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1427 Error(ERR_INFO, "custom graphic rejected for this element/action");
1429 if (i == fallback_graphic)
1430 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1432 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1433 Error(ERR_INFO_LINE, "-");
1435 graphic_info[i] = graphic_info[fallback_graphic];
1438 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1439 /* currently we only need a tile clip mask from the first frame */
1440 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1442 if (copy_clipmask_gc == None)
1444 clip_gc_values.graphics_exposures = False;
1445 clip_gc_valuemask = GCGraphicsExposures;
1446 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
1447 clip_gc_valuemask, &clip_gc_values);
1450 graphic_info[i].clip_mask =
1451 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
1453 src_pixmap = src_bitmap->clip_mask;
1454 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
1455 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
1457 clip_gc_values.graphics_exposures = False;
1458 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
1459 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
1461 graphic_info[i].clip_gc =
1462 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
1466 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1467 if (copy_clipmask_gc)
1468 XFreeGC(display, copy_clipmask_gc);
1470 clipmasks_initialized = TRUE;
1474 static void InitElementSoundInfo()
1476 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1477 int num_property_mappings = getSoundListPropertyMappingSize();
1480 /* set values to -1 to identify later as "uninitialized" values */
1481 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1482 for (act = 0; act < NUM_ACTIONS; act++)
1483 element_info[i].sound[act] = -1;
1485 /* initialize element/sound mapping from static configuration */
1486 for (i = 0; element_to_sound[i].element > -1; i++)
1488 int element = element_to_sound[i].element;
1489 int action = element_to_sound[i].action;
1490 int sound = element_to_sound[i].sound;
1491 boolean is_class = element_to_sound[i].is_class;
1494 action = ACTION_DEFAULT;
1497 element_info[element].sound[action] = sound;
1499 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1500 if (strEqual(element_info[j].class_name,
1501 element_info[element].class_name))
1502 element_info[j].sound[action] = sound;
1505 /* initialize element class/sound mapping from dynamic configuration */
1506 for (i = 0; i < num_property_mappings; i++)
1508 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1509 int action = property_mapping[i].ext1_index;
1510 int sound = property_mapping[i].artwork_index;
1512 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1516 action = ACTION_DEFAULT;
1518 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1519 if (strEqual(element_info[j].class_name,
1520 element_info[element_class].class_name))
1521 element_info[j].sound[action] = sound;
1524 /* initialize element/sound mapping from dynamic configuration */
1525 for (i = 0; i < num_property_mappings; i++)
1527 int element = property_mapping[i].base_index;
1528 int action = property_mapping[i].ext1_index;
1529 int sound = property_mapping[i].artwork_index;
1531 if (element >= MAX_NUM_ELEMENTS)
1535 action = ACTION_DEFAULT;
1537 element_info[element].sound[action] = sound;
1540 /* now set all '-1' values to element specific default values */
1541 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1543 for (act = 0; act < NUM_ACTIONS; act++)
1545 /* generic default action sound (defined by "[default]" directive) */
1546 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1548 /* look for special default action sound (classic game specific) */
1549 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1550 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1551 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1552 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1553 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1554 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1556 /* !!! there's no such thing as a "default action sound" !!! */
1558 /* look for element specific default sound (independent from action) */
1559 if (element_info[i].sound[ACTION_DEFAULT] != -1)
1560 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
1564 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1565 /* !!! make this better !!! */
1566 if (i == EL_EMPTY_SPACE)
1567 default_action_sound = element_info[EL_DEFAULT].sound[act];
1570 /* no sound for this specific action -- use default action sound */
1571 if (element_info[i].sound[act] == -1)
1572 element_info[i].sound[act] = default_action_sound;
1576 /* copy sound settings to some elements that are only stored in level file
1577 in native R'n'D levels, but are used by game engine in native EM levels */
1578 for (i = 0; copy_properties[i][0] != -1; i++)
1579 for (j = 1; j <= 4; j++)
1580 for (act = 0; act < NUM_ACTIONS; act++)
1581 element_info[copy_properties[i][j]].sound[act] =
1582 element_info[copy_properties[i][0]].sound[act];
1585 static void InitGameModeSoundInfo()
1589 /* set values to -1 to identify later as "uninitialized" values */
1590 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1593 /* initialize gamemode/sound mapping from static configuration */
1594 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1596 int gamemode = gamemode_to_sound[i].gamemode;
1597 int sound = gamemode_to_sound[i].sound;
1600 gamemode = GAME_MODE_DEFAULT;
1602 menu.sound[gamemode] = sound;
1605 /* now set all '-1' values to levelset specific default values */
1606 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1607 if (menu.sound[i] == -1)
1608 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1611 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1612 if (menu.sound[i] != -1)
1613 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
1617 static void set_sound_parameters(int sound, char **parameter_raw)
1619 int parameter[NUM_SND_ARGS];
1622 /* get integer values from string parameters */
1623 for (i = 0; i < NUM_SND_ARGS; i++)
1625 get_parameter_value(parameter_raw[i],
1626 sound_config_suffix[i].token,
1627 sound_config_suffix[i].type);
1629 /* explicit loop mode setting in configuration overrides default value */
1630 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1631 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1633 /* sound volume to change the original volume when loading the sound file */
1634 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1636 /* sound priority to give certain sounds a higher or lower priority */
1637 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1640 static void InitSoundInfo()
1642 int *sound_effect_properties;
1643 int num_sounds = getSoundListSize();
1646 checked_free(sound_info);
1648 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1649 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1651 /* initialize sound effect for all elements to "no sound" */
1652 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1653 for (j = 0; j < NUM_ACTIONS; j++)
1654 element_info[i].sound[j] = SND_UNDEFINED;
1656 for (i = 0; i < num_sounds; i++)
1658 struct FileInfo *sound = getSoundListEntry(i);
1659 int len_effect_text = strlen(sound->token);
1661 sound_effect_properties[i] = ACTION_OTHER;
1662 sound_info[i].loop = FALSE; /* default: play sound only once */
1665 printf("::: sound %d: '%s'\n", i, sound->token);
1668 /* determine all loop sounds and identify certain sound classes */
1670 for (j = 0; element_action_info[j].suffix; j++)
1672 int len_action_text = strlen(element_action_info[j].suffix);
1674 if (len_action_text < len_effect_text &&
1675 strEqual(&sound->token[len_effect_text - len_action_text],
1676 element_action_info[j].suffix))
1678 sound_effect_properties[i] = element_action_info[j].value;
1679 sound_info[i].loop = element_action_info[j].is_loop_sound;
1685 /* associate elements and some selected sound actions */
1687 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1689 if (element_info[j].class_name)
1691 int len_class_text = strlen(element_info[j].class_name);
1693 if (len_class_text + 1 < len_effect_text &&
1694 strncmp(sound->token,
1695 element_info[j].class_name, len_class_text) == 0 &&
1696 sound->token[len_class_text] == '.')
1698 int sound_action_value = sound_effect_properties[i];
1700 element_info[j].sound[sound_action_value] = i;
1705 set_sound_parameters(i, sound->parameter);
1708 free(sound_effect_properties);
1711 static void InitGameModeMusicInfo()
1713 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1714 int num_property_mappings = getMusicListPropertyMappingSize();
1715 int default_levelset_music = -1;
1718 /* set values to -1 to identify later as "uninitialized" values */
1719 for (i = 0; i < MAX_LEVELS; i++)
1720 levelset.music[i] = -1;
1721 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1724 /* initialize gamemode/music mapping from static configuration */
1725 for (i = 0; gamemode_to_music[i].music > -1; i++)
1727 int gamemode = gamemode_to_music[i].gamemode;
1728 int music = gamemode_to_music[i].music;
1731 printf("::: gamemode == %d, music == %d\n", gamemode, music);
1735 gamemode = GAME_MODE_DEFAULT;
1737 menu.music[gamemode] = music;
1740 /* initialize gamemode/music mapping from dynamic configuration */
1741 for (i = 0; i < num_property_mappings; i++)
1743 int prefix = property_mapping[i].base_index;
1744 int gamemode = property_mapping[i].ext1_index;
1745 int level = property_mapping[i].ext2_index;
1746 int music = property_mapping[i].artwork_index;
1749 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
1750 prefix, gamemode, level, music);
1753 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1757 gamemode = GAME_MODE_DEFAULT;
1759 /* level specific music only allowed for in-game music */
1760 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1761 gamemode = GAME_MODE_PLAYING;
1766 default_levelset_music = music;
1769 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1770 levelset.music[level] = music;
1771 if (gamemode != GAME_MODE_PLAYING)
1772 menu.music[gamemode] = music;
1775 /* now set all '-1' values to menu specific default values */
1776 /* (undefined values of "levelset.music[]" might stay at "-1" to
1777 allow dynamic selection of music files from music directory!) */
1778 for (i = 0; i < MAX_LEVELS; i++)
1779 if (levelset.music[i] == -1)
1780 levelset.music[i] = default_levelset_music;
1781 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1782 if (menu.music[i] == -1)
1783 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1786 for (i = 0; i < MAX_LEVELS; i++)
1787 if (levelset.music[i] != -1)
1788 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
1789 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1790 if (menu.music[i] != -1)
1791 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
1795 static void set_music_parameters(int music, char **parameter_raw)
1797 int parameter[NUM_MUS_ARGS];
1800 /* get integer values from string parameters */
1801 for (i = 0; i < NUM_MUS_ARGS; i++)
1803 get_parameter_value(parameter_raw[i],
1804 music_config_suffix[i].token,
1805 music_config_suffix[i].type);
1807 /* explicit loop mode setting in configuration overrides default value */
1808 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1809 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1812 static void InitMusicInfo()
1814 int num_music = getMusicListSize();
1817 checked_free(music_info);
1819 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1821 for (i = 0; i < num_music; i++)
1823 struct FileInfo *music = getMusicListEntry(i);
1824 int len_music_text = strlen(music->token);
1826 music_info[i].loop = TRUE; /* default: play music in loop mode */
1828 /* determine all loop music */
1830 for (j = 0; music_prefix_info[j].prefix; j++)
1832 int len_prefix_text = strlen(music_prefix_info[j].prefix);
1834 if (len_prefix_text < len_music_text &&
1835 strncmp(music->token,
1836 music_prefix_info[j].prefix, len_prefix_text) == 0)
1838 music_info[i].loop = music_prefix_info[j].is_loop_music;
1844 set_music_parameters(i, music->parameter);
1848 static void ReinitializeGraphics()
1850 InitGraphicInfo(); /* graphic properties mapping */
1851 InitElementGraphicInfo(); /* element game graphic mapping */
1852 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
1854 InitElementSmallImages(); /* scale elements to all needed sizes */
1855 InitScaledImages(); /* scale all other images, if needed */
1856 InitFontGraphicInfo(); /* initialize text drawing functions */
1858 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
1860 SetMainBackgroundImage(IMG_BACKGROUND);
1861 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1867 static void ReinitializeSounds()
1869 InitSoundInfo(); /* sound properties mapping */
1870 InitElementSoundInfo(); /* element game sound mapping */
1871 InitGameModeSoundInfo(); /* game mode sound mapping */
1873 InitPlayLevelSound(); /* internal game sound settings */
1876 static void ReinitializeMusic()
1878 InitMusicInfo(); /* music properties mapping */
1879 InitGameModeMusicInfo(); /* game mode music mapping */
1882 static int get_special_property_bit(int element, int property_bit_nr)
1884 struct PropertyBitInfo
1890 static struct PropertyBitInfo pb_can_move_into_acid[] =
1892 /* the player may be able fall into acid when gravity is activated */
1897 { EL_SP_MURPHY, 0 },
1898 { EL_SOKOBAN_FIELD_PLAYER, 0 },
1900 /* all elements that can move may be able to also move into acid */
1903 { EL_BUG_RIGHT, 1 },
1906 { EL_SPACESHIP, 2 },
1907 { EL_SPACESHIP_LEFT, 2 },
1908 { EL_SPACESHIP_RIGHT, 2 },
1909 { EL_SPACESHIP_UP, 2 },
1910 { EL_SPACESHIP_DOWN, 2 },
1911 { EL_BD_BUTTERFLY, 3 },
1912 { EL_BD_BUTTERFLY_LEFT, 3 },
1913 { EL_BD_BUTTERFLY_RIGHT, 3 },
1914 { EL_BD_BUTTERFLY_UP, 3 },
1915 { EL_BD_BUTTERFLY_DOWN, 3 },
1916 { EL_BD_FIREFLY, 4 },
1917 { EL_BD_FIREFLY_LEFT, 4 },
1918 { EL_BD_FIREFLY_RIGHT, 4 },
1919 { EL_BD_FIREFLY_UP, 4 },
1920 { EL_BD_FIREFLY_DOWN, 4 },
1922 { EL_YAMYAM_LEFT, 5 },
1923 { EL_YAMYAM_RIGHT, 5 },
1924 { EL_YAMYAM_UP, 5 },
1925 { EL_YAMYAM_DOWN, 5 },
1926 { EL_DARK_YAMYAM, 6 },
1929 { EL_PACMAN_LEFT, 8 },
1930 { EL_PACMAN_RIGHT, 8 },
1931 { EL_PACMAN_UP, 8 },
1932 { EL_PACMAN_DOWN, 8 },
1934 { EL_MOLE_LEFT, 9 },
1935 { EL_MOLE_RIGHT, 9 },
1937 { EL_MOLE_DOWN, 9 },
1941 { EL_SATELLITE, 13 },
1942 { EL_SP_SNIKSNAK, 14 },
1943 { EL_SP_ELECTRON, 15 },
1946 { EL_EMC_ANDROID, 18 },
1951 static struct PropertyBitInfo pb_dont_collide_with[] =
1953 { EL_SP_SNIKSNAK, 0 },
1954 { EL_SP_ELECTRON, 1 },
1962 struct PropertyBitInfo *pb_info;
1965 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
1966 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
1971 struct PropertyBitInfo *pb_info = NULL;
1974 for (i = 0; pb_definition[i].bit_nr != -1; i++)
1975 if (pb_definition[i].bit_nr == property_bit_nr)
1976 pb_info = pb_definition[i].pb_info;
1978 if (pb_info == NULL)
1981 for (i = 0; pb_info[i].element != -1; i++)
1982 if (pb_info[i].element == element)
1983 return pb_info[i].bit_nr;
1988 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
1989 boolean property_value)
1991 int bit_nr = get_special_property_bit(element, property_bit_nr);
1996 *bitfield |= (1 << bit_nr);
1998 *bitfield &= ~(1 << bit_nr);
2002 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2004 int bit_nr = get_special_property_bit(element, property_bit_nr);
2007 return ((*bitfield & (1 << bit_nr)) != 0);
2012 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2014 static int group_nr;
2015 static struct ElementGroupInfo *group;
2016 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2019 if (actual_group == NULL) /* not yet initialized */
2022 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
2024 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2025 group_element - EL_GROUP_START + 1);
2027 /* replace element which caused too deep recursion by question mark */
2028 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2033 if (recursion_depth == 0) /* initialization */
2035 group = actual_group;
2036 group_nr = GROUP_NR(group_element);
2038 group->num_elements_resolved = 0;
2039 group->choice_pos = 0;
2041 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2042 element_info[i].in_group[group_nr] = FALSE;
2045 for (i = 0; i < actual_group->num_elements; i++)
2047 int element = actual_group->element[i];
2049 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2052 if (IS_GROUP_ELEMENT(element))
2053 ResolveGroupElementExt(element, recursion_depth + 1);
2056 group->element_resolved[group->num_elements_resolved++] = element;
2057 element_info[element].in_group[group_nr] = TRUE;
2062 void ResolveGroupElement(int group_element)
2064 ResolveGroupElementExt(group_element, 0);
2067 void InitElementPropertiesStatic()
2069 static int ep_diggable[] =
2074 EL_SP_BUGGY_BASE_ACTIVATING,
2077 EL_INVISIBLE_SAND_ACTIVE,
2080 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2081 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2086 EL_SP_BUGGY_BASE_ACTIVE,
2093 static int ep_collectible_only[] =
2115 EL_DYNABOMB_INCREASE_NUMBER,
2116 EL_DYNABOMB_INCREASE_SIZE,
2117 EL_DYNABOMB_INCREASE_POWER,
2135 /* !!! handle separately !!! */
2136 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2142 static int ep_dont_run_into[] =
2144 /* same elements as in 'ep_dont_touch' */
2150 /* same elements as in 'ep_dont_collide_with' */
2162 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2167 EL_SP_BUGGY_BASE_ACTIVE,
2174 static int ep_dont_collide_with[] =
2176 /* same elements as in 'ep_dont_touch' */
2193 static int ep_dont_touch[] =
2203 static int ep_indestructible[] =
2207 EL_ACID_POOL_TOPLEFT,
2208 EL_ACID_POOL_TOPRIGHT,
2209 EL_ACID_POOL_BOTTOMLEFT,
2210 EL_ACID_POOL_BOTTOM,
2211 EL_ACID_POOL_BOTTOMRIGHT,
2212 EL_SP_HARDWARE_GRAY,
2213 EL_SP_HARDWARE_GREEN,
2214 EL_SP_HARDWARE_BLUE,
2216 EL_SP_HARDWARE_YELLOW,
2217 EL_SP_HARDWARE_BASE_1,
2218 EL_SP_HARDWARE_BASE_2,
2219 EL_SP_HARDWARE_BASE_3,
2220 EL_SP_HARDWARE_BASE_4,
2221 EL_SP_HARDWARE_BASE_5,
2222 EL_SP_HARDWARE_BASE_6,
2223 EL_INVISIBLE_STEELWALL,
2224 EL_INVISIBLE_STEELWALL_ACTIVE,
2225 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2226 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2227 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2228 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2229 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2230 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2231 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2232 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2233 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2234 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2235 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2236 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2238 EL_LIGHT_SWITCH_ACTIVE,
2239 EL_SIGN_EXCLAMATION,
2240 EL_SIGN_RADIOACTIVITY,
2247 EL_SIGN_ENTRY_FORBIDDEN,
2248 EL_SIGN_EMERGENCY_EXIT,
2256 EL_STEEL_EXIT_CLOSED,
2258 EL_EM_STEEL_EXIT_CLOSED,
2259 EL_EM_STEEL_EXIT_OPEN,
2260 EL_DC_STEELWALL_1_LEFT,
2261 EL_DC_STEELWALL_1_RIGHT,
2262 EL_DC_STEELWALL_1_TOP,
2263 EL_DC_STEELWALL_1_BOTTOM,
2264 EL_DC_STEELWALL_1_HORIZONTAL,
2265 EL_DC_STEELWALL_1_VERTICAL,
2266 EL_DC_STEELWALL_1_TOPLEFT,
2267 EL_DC_STEELWALL_1_TOPRIGHT,
2268 EL_DC_STEELWALL_1_BOTTOMLEFT,
2269 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2270 EL_DC_STEELWALL_1_TOPLEFT_2,
2271 EL_DC_STEELWALL_1_TOPRIGHT_2,
2272 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2273 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2274 EL_DC_STEELWALL_2_LEFT,
2275 EL_DC_STEELWALL_2_RIGHT,
2276 EL_DC_STEELWALL_2_TOP,
2277 EL_DC_STEELWALL_2_BOTTOM,
2278 EL_DC_STEELWALL_2_HORIZONTAL,
2279 EL_DC_STEELWALL_2_VERTICAL,
2280 EL_DC_STEELWALL_2_MIDDLE,
2281 EL_DC_STEELWALL_2_SINGLE,
2282 EL_STEELWALL_SLIPPERY,
2296 EL_GATE_1_GRAY_ACTIVE,
2297 EL_GATE_2_GRAY_ACTIVE,
2298 EL_GATE_3_GRAY_ACTIVE,
2299 EL_GATE_4_GRAY_ACTIVE,
2308 EL_EM_GATE_1_GRAY_ACTIVE,
2309 EL_EM_GATE_2_GRAY_ACTIVE,
2310 EL_EM_GATE_3_GRAY_ACTIVE,
2311 EL_EM_GATE_4_GRAY_ACTIVE,
2320 EL_EMC_GATE_5_GRAY_ACTIVE,
2321 EL_EMC_GATE_6_GRAY_ACTIVE,
2322 EL_EMC_GATE_7_GRAY_ACTIVE,
2323 EL_EMC_GATE_8_GRAY_ACTIVE,
2325 EL_DC_GATE_WHITE_GRAY,
2326 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2327 EL_DC_GATE_FAKE_GRAY,
2329 EL_SWITCHGATE_OPENING,
2330 EL_SWITCHGATE_CLOSED,
2331 EL_SWITCHGATE_CLOSING,
2333 EL_DC_SWITCHGATE_SWITCH_UP,
2334 EL_DC_SWITCHGATE_SWITCH_DOWN,
2337 EL_TIMEGATE_OPENING,
2339 EL_TIMEGATE_CLOSING,
2341 EL_DC_TIMEGATE_SWITCH,
2342 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2347 EL_TUBE_VERTICAL_LEFT,
2348 EL_TUBE_VERTICAL_RIGHT,
2349 EL_TUBE_HORIZONTAL_UP,
2350 EL_TUBE_HORIZONTAL_DOWN,
2355 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2356 EL_EXPANDABLE_STEELWALL_VERTICAL,
2357 EL_EXPANDABLE_STEELWALL_ANY,
2362 static int ep_slippery[] =
2376 EL_ROBOT_WHEEL_ACTIVE,
2382 EL_ACID_POOL_TOPLEFT,
2383 EL_ACID_POOL_TOPRIGHT,
2393 EL_STEELWALL_SLIPPERY,
2396 EL_EMC_WALL_SLIPPERY_1,
2397 EL_EMC_WALL_SLIPPERY_2,
2398 EL_EMC_WALL_SLIPPERY_3,
2399 EL_EMC_WALL_SLIPPERY_4,
2401 EL_EMC_MAGIC_BALL_ACTIVE,
2406 static int ep_can_change[] =
2411 static int ep_can_move[] =
2413 /* same elements as in 'pb_can_move_into_acid' */
2436 static int ep_can_fall[] =
2450 EL_QUICKSAND_FAST_FULL,
2452 EL_BD_MAGIC_WALL_FULL,
2453 EL_DC_MAGIC_WALL_FULL,
2467 static int ep_can_smash_player[] =
2493 static int ep_can_smash_enemies[] =
2502 static int ep_can_smash_everything[] =
2511 static int ep_explodes_by_fire[] =
2513 /* same elements as in 'ep_explodes_impact' */
2518 /* same elements as in 'ep_explodes_smashed' */
2528 EL_EM_DYNAMITE_ACTIVE,
2529 EL_DYNABOMB_PLAYER_1_ACTIVE,
2530 EL_DYNABOMB_PLAYER_2_ACTIVE,
2531 EL_DYNABOMB_PLAYER_3_ACTIVE,
2532 EL_DYNABOMB_PLAYER_4_ACTIVE,
2533 EL_DYNABOMB_INCREASE_NUMBER,
2534 EL_DYNABOMB_INCREASE_SIZE,
2535 EL_DYNABOMB_INCREASE_POWER,
2536 EL_SP_DISK_RED_ACTIVE,
2550 static int ep_explodes_smashed[] =
2552 /* same elements as in 'ep_explodes_impact' */
2566 static int ep_explodes_impact[] =
2575 static int ep_walkable_over[] =
2579 EL_SOKOBAN_FIELD_EMPTY,
2585 EL_EM_STEEL_EXIT_OPEN,
2594 EL_GATE_1_GRAY_ACTIVE,
2595 EL_GATE_2_GRAY_ACTIVE,
2596 EL_GATE_3_GRAY_ACTIVE,
2597 EL_GATE_4_GRAY_ACTIVE,
2605 static int ep_walkable_inside[] =
2610 EL_TUBE_VERTICAL_LEFT,
2611 EL_TUBE_VERTICAL_RIGHT,
2612 EL_TUBE_HORIZONTAL_UP,
2613 EL_TUBE_HORIZONTAL_DOWN,
2622 static int ep_walkable_under[] =
2627 static int ep_passable_over[] =
2637 EL_EM_GATE_1_GRAY_ACTIVE,
2638 EL_EM_GATE_2_GRAY_ACTIVE,
2639 EL_EM_GATE_3_GRAY_ACTIVE,
2640 EL_EM_GATE_4_GRAY_ACTIVE,
2649 EL_EMC_GATE_5_GRAY_ACTIVE,
2650 EL_EMC_GATE_6_GRAY_ACTIVE,
2651 EL_EMC_GATE_7_GRAY_ACTIVE,
2652 EL_EMC_GATE_8_GRAY_ACTIVE,
2654 EL_DC_GATE_WHITE_GRAY,
2655 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2662 static int ep_passable_inside[] =
2668 EL_SP_PORT_HORIZONTAL,
2669 EL_SP_PORT_VERTICAL,
2671 EL_SP_GRAVITY_PORT_LEFT,
2672 EL_SP_GRAVITY_PORT_RIGHT,
2673 EL_SP_GRAVITY_PORT_UP,
2674 EL_SP_GRAVITY_PORT_DOWN,
2675 EL_SP_GRAVITY_ON_PORT_LEFT,
2676 EL_SP_GRAVITY_ON_PORT_RIGHT,
2677 EL_SP_GRAVITY_ON_PORT_UP,
2678 EL_SP_GRAVITY_ON_PORT_DOWN,
2679 EL_SP_GRAVITY_OFF_PORT_LEFT,
2680 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2681 EL_SP_GRAVITY_OFF_PORT_UP,
2682 EL_SP_GRAVITY_OFF_PORT_DOWN,
2687 static int ep_passable_under[] =
2692 static int ep_droppable[] =
2697 static int ep_explodes_1x1_old[] =
2702 static int ep_pushable[] =
2714 EL_SOKOBAN_FIELD_FULL,
2723 static int ep_explodes_cross_old[] =
2728 static int ep_protected[] =
2730 /* same elements as in 'ep_walkable_inside' */
2734 EL_TUBE_VERTICAL_LEFT,
2735 EL_TUBE_VERTICAL_RIGHT,
2736 EL_TUBE_HORIZONTAL_UP,
2737 EL_TUBE_HORIZONTAL_DOWN,
2743 /* same elements as in 'ep_passable_over' */
2752 EL_EM_GATE_1_GRAY_ACTIVE,
2753 EL_EM_GATE_2_GRAY_ACTIVE,
2754 EL_EM_GATE_3_GRAY_ACTIVE,
2755 EL_EM_GATE_4_GRAY_ACTIVE,
2764 EL_EMC_GATE_5_GRAY_ACTIVE,
2765 EL_EMC_GATE_6_GRAY_ACTIVE,
2766 EL_EMC_GATE_7_GRAY_ACTIVE,
2767 EL_EMC_GATE_8_GRAY_ACTIVE,
2769 EL_DC_GATE_WHITE_GRAY,
2770 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2774 /* same elements as in 'ep_passable_inside' */
2779 EL_SP_PORT_HORIZONTAL,
2780 EL_SP_PORT_VERTICAL,
2782 EL_SP_GRAVITY_PORT_LEFT,
2783 EL_SP_GRAVITY_PORT_RIGHT,
2784 EL_SP_GRAVITY_PORT_UP,
2785 EL_SP_GRAVITY_PORT_DOWN,
2786 EL_SP_GRAVITY_ON_PORT_LEFT,
2787 EL_SP_GRAVITY_ON_PORT_RIGHT,
2788 EL_SP_GRAVITY_ON_PORT_UP,
2789 EL_SP_GRAVITY_ON_PORT_DOWN,
2790 EL_SP_GRAVITY_OFF_PORT_LEFT,
2791 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2792 EL_SP_GRAVITY_OFF_PORT_UP,
2793 EL_SP_GRAVITY_OFF_PORT_DOWN,
2798 static int ep_throwable[] =
2803 static int ep_can_explode[] =
2805 /* same elements as in 'ep_explodes_impact' */
2810 /* same elements as in 'ep_explodes_smashed' */
2816 /* elements that can explode by explosion or by dragonfire */
2820 EL_EM_DYNAMITE_ACTIVE,
2821 EL_DYNABOMB_PLAYER_1_ACTIVE,
2822 EL_DYNABOMB_PLAYER_2_ACTIVE,
2823 EL_DYNABOMB_PLAYER_3_ACTIVE,
2824 EL_DYNABOMB_PLAYER_4_ACTIVE,
2825 EL_DYNABOMB_INCREASE_NUMBER,
2826 EL_DYNABOMB_INCREASE_SIZE,
2827 EL_DYNABOMB_INCREASE_POWER,
2828 EL_SP_DISK_RED_ACTIVE,
2836 /* elements that can explode only by explosion */
2842 static int ep_gravity_reachable[] =
2848 EL_INVISIBLE_SAND_ACTIVE,
2853 EL_SP_PORT_HORIZONTAL,
2854 EL_SP_PORT_VERTICAL,
2856 EL_SP_GRAVITY_PORT_LEFT,
2857 EL_SP_GRAVITY_PORT_RIGHT,
2858 EL_SP_GRAVITY_PORT_UP,
2859 EL_SP_GRAVITY_PORT_DOWN,
2860 EL_SP_GRAVITY_ON_PORT_LEFT,
2861 EL_SP_GRAVITY_ON_PORT_RIGHT,
2862 EL_SP_GRAVITY_ON_PORT_UP,
2863 EL_SP_GRAVITY_ON_PORT_DOWN,
2864 EL_SP_GRAVITY_OFF_PORT_LEFT,
2865 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2866 EL_SP_GRAVITY_OFF_PORT_UP,
2867 EL_SP_GRAVITY_OFF_PORT_DOWN,
2873 static int ep_player[] =
2880 EL_SOKOBAN_FIELD_PLAYER,
2886 static int ep_can_pass_magic_wall[] =
2900 static int ep_can_pass_dc_magic_wall[] =
2916 static int ep_switchable[] =
2920 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2921 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2922 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2923 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2924 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2925 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2926 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2927 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2928 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2929 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2930 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2931 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2932 EL_SWITCHGATE_SWITCH_UP,
2933 EL_SWITCHGATE_SWITCH_DOWN,
2934 EL_DC_SWITCHGATE_SWITCH_UP,
2935 EL_DC_SWITCHGATE_SWITCH_DOWN,
2937 EL_LIGHT_SWITCH_ACTIVE,
2939 EL_DC_TIMEGATE_SWITCH,
2940 EL_BALLOON_SWITCH_LEFT,
2941 EL_BALLOON_SWITCH_RIGHT,
2942 EL_BALLOON_SWITCH_UP,
2943 EL_BALLOON_SWITCH_DOWN,
2944 EL_BALLOON_SWITCH_ANY,
2945 EL_BALLOON_SWITCH_NONE,
2948 EL_EMC_MAGIC_BALL_SWITCH,
2949 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
2954 static int ep_bd_element[] =
2988 static int ep_sp_element[] =
2990 /* should always be valid */
2993 /* standard classic Supaplex elements */
3000 EL_SP_HARDWARE_GRAY,
3008 EL_SP_GRAVITY_PORT_RIGHT,
3009 EL_SP_GRAVITY_PORT_DOWN,
3010 EL_SP_GRAVITY_PORT_LEFT,
3011 EL_SP_GRAVITY_PORT_UP,
3016 EL_SP_PORT_VERTICAL,
3017 EL_SP_PORT_HORIZONTAL,
3023 EL_SP_HARDWARE_BASE_1,
3024 EL_SP_HARDWARE_GREEN,
3025 EL_SP_HARDWARE_BLUE,
3027 EL_SP_HARDWARE_YELLOW,
3028 EL_SP_HARDWARE_BASE_2,
3029 EL_SP_HARDWARE_BASE_3,
3030 EL_SP_HARDWARE_BASE_4,
3031 EL_SP_HARDWARE_BASE_5,
3032 EL_SP_HARDWARE_BASE_6,
3036 /* additional elements that appeared in newer Supaplex levels */
3039 /* additional gravity port elements (not switching, but setting gravity) */
3040 EL_SP_GRAVITY_ON_PORT_LEFT,
3041 EL_SP_GRAVITY_ON_PORT_RIGHT,
3042 EL_SP_GRAVITY_ON_PORT_UP,
3043 EL_SP_GRAVITY_ON_PORT_DOWN,
3044 EL_SP_GRAVITY_OFF_PORT_LEFT,
3045 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3046 EL_SP_GRAVITY_OFF_PORT_UP,
3047 EL_SP_GRAVITY_OFF_PORT_DOWN,
3049 /* more than one Murphy in a level results in an inactive clone */
3052 /* runtime Supaplex elements */
3053 EL_SP_DISK_RED_ACTIVE,
3054 EL_SP_TERMINAL_ACTIVE,
3055 EL_SP_BUGGY_BASE_ACTIVATING,
3056 EL_SP_BUGGY_BASE_ACTIVE,
3063 static int ep_sb_element[] =
3068 EL_SOKOBAN_FIELD_EMPTY,
3069 EL_SOKOBAN_FIELD_FULL,
3070 EL_SOKOBAN_FIELD_PLAYER,
3075 EL_INVISIBLE_STEELWALL,
3080 static int ep_gem[] =
3092 static int ep_food_dark_yamyam[] =
3120 static int ep_food_penguin[] =
3134 static int ep_food_pig[] =
3146 static int ep_historic_wall[] =
3157 EL_GATE_1_GRAY_ACTIVE,
3158 EL_GATE_2_GRAY_ACTIVE,
3159 EL_GATE_3_GRAY_ACTIVE,
3160 EL_GATE_4_GRAY_ACTIVE,
3169 EL_EM_GATE_1_GRAY_ACTIVE,
3170 EL_EM_GATE_2_GRAY_ACTIVE,
3171 EL_EM_GATE_3_GRAY_ACTIVE,
3172 EL_EM_GATE_4_GRAY_ACTIVE,
3179 EL_EXPANDABLE_WALL_HORIZONTAL,
3180 EL_EXPANDABLE_WALL_VERTICAL,
3181 EL_EXPANDABLE_WALL_ANY,
3182 EL_EXPANDABLE_WALL_GROWING,
3183 EL_BD_EXPANDABLE_WALL,
3190 EL_SP_HARDWARE_GRAY,
3191 EL_SP_HARDWARE_GREEN,
3192 EL_SP_HARDWARE_BLUE,
3194 EL_SP_HARDWARE_YELLOW,
3195 EL_SP_HARDWARE_BASE_1,
3196 EL_SP_HARDWARE_BASE_2,
3197 EL_SP_HARDWARE_BASE_3,
3198 EL_SP_HARDWARE_BASE_4,
3199 EL_SP_HARDWARE_BASE_5,
3200 EL_SP_HARDWARE_BASE_6,
3202 EL_SP_TERMINAL_ACTIVE,
3205 EL_INVISIBLE_STEELWALL,
3206 EL_INVISIBLE_STEELWALL_ACTIVE,
3208 EL_INVISIBLE_WALL_ACTIVE,
3209 EL_STEELWALL_SLIPPERY,
3226 static int ep_historic_solid[] =
3230 EL_EXPANDABLE_WALL_HORIZONTAL,
3231 EL_EXPANDABLE_WALL_VERTICAL,
3232 EL_EXPANDABLE_WALL_ANY,
3233 EL_BD_EXPANDABLE_WALL,
3246 EL_QUICKSAND_FILLING,
3247 EL_QUICKSAND_EMPTYING,
3249 EL_MAGIC_WALL_ACTIVE,
3250 EL_MAGIC_WALL_EMPTYING,
3251 EL_MAGIC_WALL_FILLING,
3255 EL_BD_MAGIC_WALL_ACTIVE,
3256 EL_BD_MAGIC_WALL_EMPTYING,
3257 EL_BD_MAGIC_WALL_FULL,
3258 EL_BD_MAGIC_WALL_FILLING,
3259 EL_BD_MAGIC_WALL_DEAD,
3268 EL_SP_TERMINAL_ACTIVE,
3272 EL_INVISIBLE_WALL_ACTIVE,
3273 EL_SWITCHGATE_SWITCH_UP,
3274 EL_SWITCHGATE_SWITCH_DOWN,
3275 EL_DC_SWITCHGATE_SWITCH_UP,
3276 EL_DC_SWITCHGATE_SWITCH_DOWN,
3278 EL_TIMEGATE_SWITCH_ACTIVE,
3279 EL_DC_TIMEGATE_SWITCH,
3280 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3292 /* the following elements are a direct copy of "indestructible" elements,
3293 except "EL_ACID", which is "indestructible", but not "solid"! */
3298 EL_ACID_POOL_TOPLEFT,
3299 EL_ACID_POOL_TOPRIGHT,
3300 EL_ACID_POOL_BOTTOMLEFT,
3301 EL_ACID_POOL_BOTTOM,
3302 EL_ACID_POOL_BOTTOMRIGHT,
3303 EL_SP_HARDWARE_GRAY,
3304 EL_SP_HARDWARE_GREEN,
3305 EL_SP_HARDWARE_BLUE,
3307 EL_SP_HARDWARE_YELLOW,
3308 EL_SP_HARDWARE_BASE_1,
3309 EL_SP_HARDWARE_BASE_2,
3310 EL_SP_HARDWARE_BASE_3,
3311 EL_SP_HARDWARE_BASE_4,
3312 EL_SP_HARDWARE_BASE_5,
3313 EL_SP_HARDWARE_BASE_6,
3314 EL_INVISIBLE_STEELWALL,
3315 EL_INVISIBLE_STEELWALL_ACTIVE,
3316 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3317 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3318 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3319 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3320 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3321 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3322 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3323 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3324 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3325 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3326 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3327 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3329 EL_LIGHT_SWITCH_ACTIVE,
3330 EL_SIGN_EXCLAMATION,
3331 EL_SIGN_RADIOACTIVITY,
3338 EL_SIGN_ENTRY_FORBIDDEN,
3339 EL_SIGN_EMERGENCY_EXIT,
3347 EL_STEEL_EXIT_CLOSED,
3349 EL_DC_STEELWALL_1_LEFT,
3350 EL_DC_STEELWALL_1_RIGHT,
3351 EL_DC_STEELWALL_1_TOP,
3352 EL_DC_STEELWALL_1_BOTTOM,
3353 EL_DC_STEELWALL_1_HORIZONTAL,
3354 EL_DC_STEELWALL_1_VERTICAL,
3355 EL_DC_STEELWALL_1_TOPLEFT,
3356 EL_DC_STEELWALL_1_TOPRIGHT,
3357 EL_DC_STEELWALL_1_BOTTOMLEFT,
3358 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3359 EL_DC_STEELWALL_1_TOPLEFT_2,
3360 EL_DC_STEELWALL_1_TOPRIGHT_2,
3361 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3362 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3363 EL_DC_STEELWALL_2_LEFT,
3364 EL_DC_STEELWALL_2_RIGHT,
3365 EL_DC_STEELWALL_2_TOP,
3366 EL_DC_STEELWALL_2_BOTTOM,
3367 EL_DC_STEELWALL_2_HORIZONTAL,
3368 EL_DC_STEELWALL_2_VERTICAL,
3369 EL_DC_STEELWALL_2_MIDDLE,
3370 EL_DC_STEELWALL_2_SINGLE,
3371 EL_STEELWALL_SLIPPERY,
3385 EL_GATE_1_GRAY_ACTIVE,
3386 EL_GATE_2_GRAY_ACTIVE,
3387 EL_GATE_3_GRAY_ACTIVE,
3388 EL_GATE_4_GRAY_ACTIVE,
3397 EL_EM_GATE_1_GRAY_ACTIVE,
3398 EL_EM_GATE_2_GRAY_ACTIVE,
3399 EL_EM_GATE_3_GRAY_ACTIVE,
3400 EL_EM_GATE_4_GRAY_ACTIVE,
3402 EL_SWITCHGATE_OPENING,
3403 EL_SWITCHGATE_CLOSED,
3404 EL_SWITCHGATE_CLOSING,
3406 EL_TIMEGATE_OPENING,
3408 EL_TIMEGATE_CLOSING,
3412 EL_TUBE_VERTICAL_LEFT,
3413 EL_TUBE_VERTICAL_RIGHT,
3414 EL_TUBE_HORIZONTAL_UP,
3415 EL_TUBE_HORIZONTAL_DOWN,
3424 static int ep_classic_enemy[] =
3441 static int ep_belt[] =
3443 EL_CONVEYOR_BELT_1_LEFT,
3444 EL_CONVEYOR_BELT_1_MIDDLE,
3445 EL_CONVEYOR_BELT_1_RIGHT,
3446 EL_CONVEYOR_BELT_2_LEFT,
3447 EL_CONVEYOR_BELT_2_MIDDLE,
3448 EL_CONVEYOR_BELT_2_RIGHT,
3449 EL_CONVEYOR_BELT_3_LEFT,
3450 EL_CONVEYOR_BELT_3_MIDDLE,
3451 EL_CONVEYOR_BELT_3_RIGHT,
3452 EL_CONVEYOR_BELT_4_LEFT,
3453 EL_CONVEYOR_BELT_4_MIDDLE,
3454 EL_CONVEYOR_BELT_4_RIGHT,
3459 static int ep_belt_active[] =
3461 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3462 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3463 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3464 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3465 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3466 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3467 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3468 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3469 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3470 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3471 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3472 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3477 static int ep_belt_switch[] =
3479 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3480 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3481 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3482 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3483 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3484 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3485 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3486 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3487 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3488 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3489 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3490 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3495 static int ep_tube[] =
3502 EL_TUBE_HORIZONTAL_UP,
3503 EL_TUBE_HORIZONTAL_DOWN,
3505 EL_TUBE_VERTICAL_LEFT,
3506 EL_TUBE_VERTICAL_RIGHT,
3512 static int ep_acid_pool[] =
3514 EL_ACID_POOL_TOPLEFT,
3515 EL_ACID_POOL_TOPRIGHT,
3516 EL_ACID_POOL_BOTTOMLEFT,
3517 EL_ACID_POOL_BOTTOM,
3518 EL_ACID_POOL_BOTTOMRIGHT,
3523 static int ep_keygate[] =
3533 EL_GATE_1_GRAY_ACTIVE,
3534 EL_GATE_2_GRAY_ACTIVE,
3535 EL_GATE_3_GRAY_ACTIVE,
3536 EL_GATE_4_GRAY_ACTIVE,
3545 EL_EM_GATE_1_GRAY_ACTIVE,
3546 EL_EM_GATE_2_GRAY_ACTIVE,
3547 EL_EM_GATE_3_GRAY_ACTIVE,
3548 EL_EM_GATE_4_GRAY_ACTIVE,
3557 EL_EMC_GATE_5_GRAY_ACTIVE,
3558 EL_EMC_GATE_6_GRAY_ACTIVE,
3559 EL_EMC_GATE_7_GRAY_ACTIVE,
3560 EL_EMC_GATE_8_GRAY_ACTIVE,
3562 EL_DC_GATE_WHITE_GRAY,
3563 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3568 static int ep_amoeboid[] =
3580 static int ep_amoebalive[] =
3591 static int ep_has_editor_content[] =
3613 static int ep_can_turn_each_move[] =
3615 /* !!! do something with this one !!! */
3619 static int ep_can_grow[] =
3633 static int ep_active_bomb[] =
3636 EL_EM_DYNAMITE_ACTIVE,
3637 EL_DYNABOMB_PLAYER_1_ACTIVE,
3638 EL_DYNABOMB_PLAYER_2_ACTIVE,
3639 EL_DYNABOMB_PLAYER_3_ACTIVE,
3640 EL_DYNABOMB_PLAYER_4_ACTIVE,
3641 EL_SP_DISK_RED_ACTIVE,
3646 static int ep_inactive[] =
3656 EL_QUICKSAND_FAST_EMPTY,
3679 EL_GATE_1_GRAY_ACTIVE,
3680 EL_GATE_2_GRAY_ACTIVE,
3681 EL_GATE_3_GRAY_ACTIVE,
3682 EL_GATE_4_GRAY_ACTIVE,
3691 EL_EM_GATE_1_GRAY_ACTIVE,
3692 EL_EM_GATE_2_GRAY_ACTIVE,
3693 EL_EM_GATE_3_GRAY_ACTIVE,
3694 EL_EM_GATE_4_GRAY_ACTIVE,
3703 EL_EMC_GATE_5_GRAY_ACTIVE,
3704 EL_EMC_GATE_6_GRAY_ACTIVE,
3705 EL_EMC_GATE_7_GRAY_ACTIVE,
3706 EL_EMC_GATE_8_GRAY_ACTIVE,
3708 EL_DC_GATE_WHITE_GRAY,
3709 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3710 EL_DC_GATE_FAKE_GRAY,
3713 EL_INVISIBLE_STEELWALL,
3721 EL_WALL_EMERALD_YELLOW,
3722 EL_DYNABOMB_INCREASE_NUMBER,
3723 EL_DYNABOMB_INCREASE_SIZE,
3724 EL_DYNABOMB_INCREASE_POWER,
3728 EL_SOKOBAN_FIELD_EMPTY,
3729 EL_SOKOBAN_FIELD_FULL,
3730 EL_WALL_EMERALD_RED,
3731 EL_WALL_EMERALD_PURPLE,
3732 EL_ACID_POOL_TOPLEFT,
3733 EL_ACID_POOL_TOPRIGHT,
3734 EL_ACID_POOL_BOTTOMLEFT,
3735 EL_ACID_POOL_BOTTOM,
3736 EL_ACID_POOL_BOTTOMRIGHT,
3740 EL_BD_MAGIC_WALL_DEAD,
3742 EL_DC_MAGIC_WALL_DEAD,
3743 EL_AMOEBA_TO_DIAMOND,
3751 EL_SP_GRAVITY_PORT_RIGHT,
3752 EL_SP_GRAVITY_PORT_DOWN,
3753 EL_SP_GRAVITY_PORT_LEFT,
3754 EL_SP_GRAVITY_PORT_UP,
3755 EL_SP_PORT_HORIZONTAL,
3756 EL_SP_PORT_VERTICAL,
3767 EL_SP_HARDWARE_GRAY,
3768 EL_SP_HARDWARE_GREEN,
3769 EL_SP_HARDWARE_BLUE,
3771 EL_SP_HARDWARE_YELLOW,
3772 EL_SP_HARDWARE_BASE_1,
3773 EL_SP_HARDWARE_BASE_2,
3774 EL_SP_HARDWARE_BASE_3,
3775 EL_SP_HARDWARE_BASE_4,
3776 EL_SP_HARDWARE_BASE_5,
3777 EL_SP_HARDWARE_BASE_6,
3778 EL_SP_GRAVITY_ON_PORT_LEFT,
3779 EL_SP_GRAVITY_ON_PORT_RIGHT,
3780 EL_SP_GRAVITY_ON_PORT_UP,
3781 EL_SP_GRAVITY_ON_PORT_DOWN,
3782 EL_SP_GRAVITY_OFF_PORT_LEFT,
3783 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3784 EL_SP_GRAVITY_OFF_PORT_UP,
3785 EL_SP_GRAVITY_OFF_PORT_DOWN,
3786 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3787 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3788 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3789 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3790 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3791 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3792 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3793 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3794 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3795 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3796 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3797 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3798 EL_SIGN_EXCLAMATION,
3799 EL_SIGN_RADIOACTIVITY,
3806 EL_SIGN_ENTRY_FORBIDDEN,
3807 EL_SIGN_EMERGENCY_EXIT,
3815 EL_DC_STEELWALL_1_LEFT,
3816 EL_DC_STEELWALL_1_RIGHT,
3817 EL_DC_STEELWALL_1_TOP,
3818 EL_DC_STEELWALL_1_BOTTOM,
3819 EL_DC_STEELWALL_1_HORIZONTAL,
3820 EL_DC_STEELWALL_1_VERTICAL,
3821 EL_DC_STEELWALL_1_TOPLEFT,
3822 EL_DC_STEELWALL_1_TOPRIGHT,
3823 EL_DC_STEELWALL_1_BOTTOMLEFT,
3824 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3825 EL_DC_STEELWALL_1_TOPLEFT_2,
3826 EL_DC_STEELWALL_1_TOPRIGHT_2,
3827 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3828 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3829 EL_DC_STEELWALL_2_LEFT,
3830 EL_DC_STEELWALL_2_RIGHT,
3831 EL_DC_STEELWALL_2_TOP,
3832 EL_DC_STEELWALL_2_BOTTOM,
3833 EL_DC_STEELWALL_2_HORIZONTAL,
3834 EL_DC_STEELWALL_2_VERTICAL,
3835 EL_DC_STEELWALL_2_MIDDLE,
3836 EL_DC_STEELWALL_2_SINGLE,
3837 EL_STEELWALL_SLIPPERY,
3842 EL_EMC_WALL_SLIPPERY_1,
3843 EL_EMC_WALL_SLIPPERY_2,
3844 EL_EMC_WALL_SLIPPERY_3,
3845 EL_EMC_WALL_SLIPPERY_4,
3866 static int ep_em_slippery_wall[] =
3871 static int ep_gfx_crumbled[] =
3882 static int ep_editor_cascade_active[] =
3884 EL_INTERNAL_CASCADE_BD_ACTIVE,
3885 EL_INTERNAL_CASCADE_EM_ACTIVE,
3886 EL_INTERNAL_CASCADE_EMC_ACTIVE,
3887 EL_INTERNAL_CASCADE_RND_ACTIVE,
3888 EL_INTERNAL_CASCADE_SB_ACTIVE,
3889 EL_INTERNAL_CASCADE_SP_ACTIVE,
3890 EL_INTERNAL_CASCADE_DC_ACTIVE,
3891 EL_INTERNAL_CASCADE_DX_ACTIVE,
3892 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
3893 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
3894 EL_INTERNAL_CASCADE_CE_ACTIVE,
3895 EL_INTERNAL_CASCADE_GE_ACTIVE,
3896 EL_INTERNAL_CASCADE_REF_ACTIVE,
3897 EL_INTERNAL_CASCADE_USER_ACTIVE,
3898 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
3903 static int ep_editor_cascade_inactive[] =
3905 EL_INTERNAL_CASCADE_BD,
3906 EL_INTERNAL_CASCADE_EM,
3907 EL_INTERNAL_CASCADE_EMC,
3908 EL_INTERNAL_CASCADE_RND,
3909 EL_INTERNAL_CASCADE_SB,
3910 EL_INTERNAL_CASCADE_SP,
3911 EL_INTERNAL_CASCADE_DC,
3912 EL_INTERNAL_CASCADE_DX,
3913 EL_INTERNAL_CASCADE_CHARS,
3914 EL_INTERNAL_CASCADE_STEEL_CHARS,
3915 EL_INTERNAL_CASCADE_CE,
3916 EL_INTERNAL_CASCADE_GE,
3917 EL_INTERNAL_CASCADE_REF,
3918 EL_INTERNAL_CASCADE_USER,
3919 EL_INTERNAL_CASCADE_DYNAMIC,
3924 static int ep_obsolete[] =
3928 EL_EM_KEY_1_FILE_OBSOLETE,
3929 EL_EM_KEY_2_FILE_OBSOLETE,
3930 EL_EM_KEY_3_FILE_OBSOLETE,
3931 EL_EM_KEY_4_FILE_OBSOLETE,
3932 EL_ENVELOPE_OBSOLETE,
3941 } element_properties[] =
3943 { ep_diggable, EP_DIGGABLE },
3944 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
3945 { ep_dont_run_into, EP_DONT_RUN_INTO },
3946 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
3947 { ep_dont_touch, EP_DONT_TOUCH },
3948 { ep_indestructible, EP_INDESTRUCTIBLE },
3949 { ep_slippery, EP_SLIPPERY },
3950 { ep_can_change, EP_CAN_CHANGE },
3951 { ep_can_move, EP_CAN_MOVE },
3952 { ep_can_fall, EP_CAN_FALL },
3953 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
3954 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
3955 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
3956 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
3957 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
3958 { ep_explodes_impact, EP_EXPLODES_IMPACT },
3959 { ep_walkable_over, EP_WALKABLE_OVER },
3960 { ep_walkable_inside, EP_WALKABLE_INSIDE },
3961 { ep_walkable_under, EP_WALKABLE_UNDER },
3962 { ep_passable_over, EP_PASSABLE_OVER },
3963 { ep_passable_inside, EP_PASSABLE_INSIDE },
3964 { ep_passable_under, EP_PASSABLE_UNDER },
3965 { ep_droppable, EP_DROPPABLE },
3966 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
3967 { ep_pushable, EP_PUSHABLE },
3968 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
3969 { ep_protected, EP_PROTECTED },
3970 { ep_throwable, EP_THROWABLE },
3971 { ep_can_explode, EP_CAN_EXPLODE },
3972 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
3974 { ep_player, EP_PLAYER },
3975 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
3976 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
3977 { ep_switchable, EP_SWITCHABLE },
3978 { ep_bd_element, EP_BD_ELEMENT },
3979 { ep_sp_element, EP_SP_ELEMENT },
3980 { ep_sb_element, EP_SB_ELEMENT },
3982 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
3983 { ep_food_penguin, EP_FOOD_PENGUIN },
3984 { ep_food_pig, EP_FOOD_PIG },
3985 { ep_historic_wall, EP_HISTORIC_WALL },
3986 { ep_historic_solid, EP_HISTORIC_SOLID },
3987 { ep_classic_enemy, EP_CLASSIC_ENEMY },
3988 { ep_belt, EP_BELT },
3989 { ep_belt_active, EP_BELT_ACTIVE },
3990 { ep_belt_switch, EP_BELT_SWITCH },
3991 { ep_tube, EP_TUBE },
3992 { ep_acid_pool, EP_ACID_POOL },
3993 { ep_keygate, EP_KEYGATE },
3994 { ep_amoeboid, EP_AMOEBOID },
3995 { ep_amoebalive, EP_AMOEBALIVE },
3996 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
3997 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
3998 { ep_can_grow, EP_CAN_GROW },
3999 { ep_active_bomb, EP_ACTIVE_BOMB },
4000 { ep_inactive, EP_INACTIVE },
4002 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4004 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4006 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4007 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4009 { ep_obsolete, EP_OBSOLETE },
4016 /* always start with reliable default values (element has no properties) */
4017 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4018 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4019 SET_PROPERTY(i, j, FALSE);
4021 /* set all base element properties from above array definitions */
4022 for (i = 0; element_properties[i].elements != NULL; i++)
4023 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4024 SET_PROPERTY((element_properties[i].elements)[j],
4025 element_properties[i].property, TRUE);
4027 /* copy properties to some elements that are only stored in level file */
4028 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4029 for (j = 0; copy_properties[j][0] != -1; j++)
4030 if (HAS_PROPERTY(copy_properties[j][0], i))
4031 for (k = 1; k <= 4; k++)
4032 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4034 /* set static element properties that are not listed in array definitions */
4035 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4036 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4039 void InitElementPropertiesEngine(int engine_version)
4041 static int no_wall_properties[] =
4044 EP_COLLECTIBLE_ONLY,
4046 EP_DONT_COLLIDE_WITH,
4049 EP_CAN_SMASH_PLAYER,
4050 EP_CAN_SMASH_ENEMIES,
4051 EP_CAN_SMASH_EVERYTHING,
4056 EP_FOOD_DARK_YAMYAM,
4072 /* important: after initialization in InitElementPropertiesStatic(), the
4073 elements are not again initialized to a default value; therefore all
4074 changes have to make sure that they leave the element with a defined
4075 property (which means that conditional property changes must be set to
4076 a reliable default value before) */
4078 /* resolve group elements */
4079 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4080 ResolveGroupElement(EL_GROUP_START + i);
4082 /* set all special, combined or engine dependent element properties */
4083 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4085 /* ---------- INACTIVE ------------------------------------------------- */
4086 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4087 i <= EL_CHAR_END) ||
4088 (i >= EL_STEEL_CHAR_START &&
4089 i <= EL_STEEL_CHAR_END)));
4091 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4092 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4093 IS_WALKABLE_INSIDE(i) ||
4094 IS_WALKABLE_UNDER(i)));
4096 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4097 IS_PASSABLE_INSIDE(i) ||
4098 IS_PASSABLE_UNDER(i)));
4100 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4101 IS_PASSABLE_OVER(i)));
4103 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4104 IS_PASSABLE_INSIDE(i)));
4106 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4107 IS_PASSABLE_UNDER(i)));
4109 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4112 /* ---------- COLLECTIBLE ---------------------------------------------- */
4113 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4117 /* ---------- SNAPPABLE ------------------------------------------------ */
4118 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4119 IS_COLLECTIBLE(i) ||
4123 /* ---------- WALL ----------------------------------------------------- */
4124 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4126 for (j = 0; no_wall_properties[j] != -1; j++)
4127 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4128 i >= EL_FIRST_RUNTIME_UNREAL)
4129 SET_PROPERTY(i, EP_WALL, FALSE);
4131 if (IS_HISTORIC_WALL(i))
4132 SET_PROPERTY(i, EP_WALL, TRUE);
4134 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4135 if (engine_version < VERSION_IDENT(2,2,0,0))
4136 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4138 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4140 !IS_COLLECTIBLE(i)));
4142 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4143 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4144 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4146 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4147 IS_INDESTRUCTIBLE(i)));
4149 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4151 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4152 else if (engine_version < VERSION_IDENT(2,2,0,0))
4153 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4155 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4159 if (IS_CUSTOM_ELEMENT(i))
4161 /* these are additional properties which are initially false when set */
4163 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4165 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4166 if (DONT_COLLIDE_WITH(i))
4167 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4169 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4170 if (CAN_SMASH_EVERYTHING(i))
4171 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4172 if (CAN_SMASH_ENEMIES(i))
4173 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4176 /* ---------- CAN_SMASH ------------------------------------------------ */
4177 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4178 CAN_SMASH_ENEMIES(i) ||
4179 CAN_SMASH_EVERYTHING(i)));
4181 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4182 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4183 EXPLODES_BY_FIRE(i)));
4185 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4186 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4187 EXPLODES_SMASHED(i)));
4189 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4190 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4191 EXPLODES_IMPACT(i)));
4193 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4194 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4196 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4197 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4198 i == EL_BLACK_ORB));
4200 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4201 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4203 IS_CUSTOM_ELEMENT(i)));
4205 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4206 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4207 i == EL_SP_ELECTRON));
4209 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4210 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4211 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4212 getMoveIntoAcidProperty(&level, i));
4214 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4215 if (MAYBE_DONT_COLLIDE_WITH(i))
4216 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4217 getDontCollideWithProperty(&level, i));
4219 /* ---------- SP_PORT -------------------------------------------------- */
4220 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4221 IS_PASSABLE_INSIDE(i)));
4223 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4224 for (j = 0; j < level.num_android_clone_elements; j++)
4225 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4227 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4229 /* ---------- CAN_CHANGE ----------------------------------------------- */
4230 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4231 for (j = 0; j < element_info[i].num_change_pages; j++)
4232 if (element_info[i].change_page[j].can_change)
4233 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4235 /* ---------- HAS_ACTION ----------------------------------------------- */
4236 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4237 for (j = 0; j < element_info[i].num_change_pages; j++)
4238 if (element_info[i].change_page[j].has_action)
4239 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4241 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4242 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4245 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4247 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4248 element_info[i].crumbled[ACTION_DEFAULT] !=
4249 element_info[i].graphic[ACTION_DEFAULT]);
4251 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
4252 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4253 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
4256 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4257 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4258 IS_EDITOR_CASCADE_INACTIVE(i)));
4261 /* dynamically adjust element properties according to game engine version */
4263 static int ep_em_slippery_wall[] =
4268 EL_EXPANDABLE_WALL_HORIZONTAL,
4269 EL_EXPANDABLE_WALL_VERTICAL,
4270 EL_EXPANDABLE_WALL_ANY,
4271 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4272 EL_EXPANDABLE_STEELWALL_VERTICAL,
4273 EL_EXPANDABLE_STEELWALL_ANY,
4274 EL_EXPANDABLE_STEELWALL_GROWING,
4278 /* special EM style gems behaviour */
4279 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4280 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4281 level.em_slippery_gems);
4283 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4284 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4285 (level.em_slippery_gems &&
4286 engine_version > VERSION_IDENT(2,0,1,0)));
4289 /* this is needed because some graphics depend on element properties */
4290 if (game_status == GAME_MODE_PLAYING)
4291 InitElementGraphicInfo();
4294 void InitElementPropertiesAfterLoading(int engine_version)
4298 /* set some other uninitialized values of custom elements in older levels */
4299 if (engine_version < VERSION_IDENT(3,1,0,0))
4301 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4303 int element = EL_CUSTOM_START + i;
4305 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4307 element_info[element].explosion_delay = 17;
4308 element_info[element].ignition_delay = 8;
4313 static void InitGlobal()
4317 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4319 /* check if element_name_info entry defined for each element in "main.h" */
4320 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4321 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4323 element_info[i].token_name = element_name_info[i].token_name;
4324 element_info[i].class_name = element_name_info[i].class_name;
4325 element_info[i].editor_description=element_name_info[i].editor_description;
4328 printf("%04d: %s\n", i, element_name_info[i].token_name);
4332 global.autoplay_leveldir = NULL;
4333 global.convert_leveldir = NULL;
4335 global.frames_per_second = 0;
4336 global.fps_slowdown = FALSE;
4337 global.fps_slowdown_factor = 1;
4340 void Execute_Command(char *command)
4344 if (strEqual(command, "print graphicsinfo.conf"))
4346 printf("# You can configure additional/alternative image files here.\n");
4347 printf("# (The entries below are default and therefore commented out.)\n");
4349 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4351 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4354 for (i = 0; image_config[i].token != NULL; i++)
4355 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
4356 image_config[i].value));
4360 else if (strEqual(command, "print soundsinfo.conf"))
4362 printf("# You can configure additional/alternative sound files here.\n");
4363 printf("# (The entries below are default and therefore commented out.)\n");
4365 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4367 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4370 for (i = 0; sound_config[i].token != NULL; i++)
4371 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4372 sound_config[i].value));
4376 else if (strEqual(command, "print musicinfo.conf"))
4378 printf("# You can configure additional/alternative music files here.\n");
4379 printf("# (The entries below are default and therefore commented out.)\n");
4381 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4383 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4386 for (i = 0; music_config[i].token != NULL; i++)
4387 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
4388 music_config[i].value));
4392 else if (strEqual(command, "print editorsetup.conf"))
4394 printf("# You can configure your personal editor element list here.\n");
4395 printf("# (The entries below are default and therefore commented out.)\n");
4398 /* this is needed to be able to check element list for cascade elements */
4399 InitElementPropertiesStatic();
4400 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4402 PrintEditorElementList();
4406 else if (strEqual(command, "print helpanim.conf"))
4408 printf("# You can configure different element help animations here.\n");
4409 printf("# (The entries below are default and therefore commented out.)\n");
4412 for (i = 0; helpanim_config[i].token != NULL; i++)
4414 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4415 helpanim_config[i].value));
4417 if (strEqual(helpanim_config[i].token, "end"))
4423 else if (strEqual(command, "print helptext.conf"))
4425 printf("# You can configure different element help text here.\n");
4426 printf("# (The entries below are default and therefore commented out.)\n");
4429 for (i = 0; helptext_config[i].token != NULL; i++)
4430 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4431 helptext_config[i].value));
4435 else if (strncmp(command, "dump level ", 11) == 0)
4437 char *filename = &command[11];
4439 if (!fileExists(filename))
4440 Error(ERR_EXIT, "cannot open file '%s'", filename);
4442 LoadLevelFromFilename(&level, filename);
4447 else if (strncmp(command, "dump tape ", 10) == 0)
4449 char *filename = &command[10];
4451 if (!fileExists(filename))
4452 Error(ERR_EXIT, "cannot open file '%s'", filename);
4454 LoadTapeFromFilename(filename);
4459 else if (strncmp(command, "autoplay ", 9) == 0)
4461 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
4463 while (*str_ptr != '\0') /* continue parsing string */
4465 /* cut leading whitespace from string, replace it by string terminator */
4466 while (*str_ptr == ' ' || *str_ptr == '\t')
4469 if (*str_ptr == '\0') /* end of string reached */
4472 if (global.autoplay_leveldir == NULL) /* read level set string */
4474 global.autoplay_leveldir = str_ptr;
4475 global.autoplay_all = TRUE; /* default: play all tapes */
4477 for (i = 0; i < MAX_TAPES_PER_SET; i++)
4478 global.autoplay_level[i] = FALSE;
4480 else /* read level number string */
4482 int level_nr = atoi(str_ptr); /* get level_nr value */
4484 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
4485 global.autoplay_level[level_nr] = TRUE;
4487 global.autoplay_all = FALSE;
4490 /* advance string pointer to the next whitespace (or end of string) */
4491 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
4495 else if (strncmp(command, "convert ", 8) == 0)
4497 char *str_copy = getStringCopy(&command[8]);
4498 char *str_ptr = strchr(str_copy, ' ');
4500 global.convert_leveldir = str_copy;
4501 global.convert_level_nr = -1;
4503 if (str_ptr != NULL) /* level number follows */
4505 *str_ptr++ = '\0'; /* terminate leveldir string */
4506 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
4511 #if defined(TARGET_SDL)
4512 else if (strEqual(command, "SDL_ListModes"))
4517 SDL_Init(SDL_INIT_VIDEO);
4519 /* get available fullscreen/hardware modes */
4520 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
4522 /* check if there are any modes available */
4525 printf("No modes available!\n");
4530 /* check if our resolution is restricted */
4531 if (modes == (SDL_Rect **)-1)
4533 printf("All resolutions available.\n");
4537 printf("Available Modes:\n");
4539 for(i = 0; modes[i]; i++)
4540 printf(" %d x %d\n", modes[i]->w, modes[i]->h);
4550 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4554 static void InitSetup()
4556 LoadSetup(); /* global setup info */
4558 /* set some options from setup file */
4560 if (setup.options.verbose)
4561 options.verbose = TRUE;
4564 static void InitGameInfo()
4566 game.restart_level = FALSE;
4569 static void InitPlayerInfo()
4573 /* choose default local player */
4574 local_player = &stored_player[0];
4576 for (i = 0; i < MAX_PLAYERS; i++)
4577 stored_player[i].connected = FALSE;
4579 local_player->connected = TRUE;
4582 static void InitArtworkInfo()
4587 static char *get_string_in_brackets(char *string)
4589 char *string_in_brackets = checked_malloc(strlen(string) + 3);
4591 sprintf(string_in_brackets, "[%s]", string);
4593 return string_in_brackets;
4596 static char *get_level_id_suffix(int id_nr)
4598 char *id_suffix = checked_malloc(1 + 3 + 1);
4600 if (id_nr < 0 || id_nr > 999)
4603 sprintf(id_suffix, ".%03d", id_nr);
4609 static char *get_element_class_token(int element)
4611 char *element_class_name = element_info[element].class_name;
4612 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
4614 sprintf(element_class_token, "[%s]", element_class_name);
4616 return element_class_token;
4619 static char *get_action_class_token(int action)
4621 char *action_class_name = &element_action_info[action].suffix[1];
4622 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
4624 sprintf(action_class_token, "[%s]", action_class_name);
4626 return action_class_token;
4630 static void InitArtworkConfig()
4632 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
4633 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
4634 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
4635 static char *action_id_suffix[NUM_ACTIONS + 1];
4636 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
4637 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
4638 static char *level_id_suffix[MAX_LEVELS + 1];
4639 static char *dummy[1] = { NULL };
4640 static char *ignore_generic_tokens[] =
4646 static char **ignore_image_tokens;
4647 static char **ignore_sound_tokens;
4648 static char **ignore_music_tokens;
4649 int num_ignore_generic_tokens;
4650 int num_ignore_image_tokens;
4651 int num_ignore_sound_tokens;
4652 int num_ignore_music_tokens;
4655 /* dynamically determine list of generic tokens to be ignored */
4656 num_ignore_generic_tokens = 0;
4657 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
4658 num_ignore_generic_tokens++;
4660 /* dynamically determine list of image tokens to be ignored */
4661 num_ignore_image_tokens = num_ignore_generic_tokens;
4662 for (i = 0; image_config_vars[i].token != NULL; i++)
4663 num_ignore_image_tokens++;
4664 ignore_image_tokens =
4665 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
4666 for (i = 0; i < num_ignore_generic_tokens; i++)
4667 ignore_image_tokens[i] = ignore_generic_tokens[i];
4668 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
4669 ignore_image_tokens[num_ignore_generic_tokens + i] =
4670 image_config_vars[i].token;
4671 ignore_image_tokens[num_ignore_image_tokens] = NULL;
4673 /* dynamically determine list of sound tokens to be ignored */
4674 num_ignore_sound_tokens = num_ignore_generic_tokens;
4675 ignore_sound_tokens =
4676 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
4677 for (i = 0; i < num_ignore_generic_tokens; i++)
4678 ignore_sound_tokens[i] = ignore_generic_tokens[i];
4679 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
4681 /* dynamically determine list of music tokens to be ignored */
4682 num_ignore_music_tokens = num_ignore_generic_tokens;
4683 ignore_music_tokens =
4684 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
4685 for (i = 0; i < num_ignore_generic_tokens; i++)
4686 ignore_music_tokens[i] = ignore_generic_tokens[i];
4687 ignore_music_tokens[num_ignore_music_tokens] = NULL;
4689 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4690 image_id_prefix[i] = element_info[i].token_name;
4691 for (i = 0; i < NUM_FONTS; i++)
4692 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
4693 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
4695 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4696 sound_id_prefix[i] = element_info[i].token_name;
4697 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4698 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
4699 get_string_in_brackets(element_info[i].class_name);
4700 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
4702 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
4703 music_id_prefix[i] = music_prefix_info[i].prefix;
4704 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
4706 for (i = 0; i < NUM_ACTIONS; i++)
4707 action_id_suffix[i] = element_action_info[i].suffix;
4708 action_id_suffix[NUM_ACTIONS] = NULL;
4710 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
4711 direction_id_suffix[i] = element_direction_info[i].suffix;
4712 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
4714 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
4715 special_id_suffix[i] = special_suffix_info[i].suffix;
4716 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
4718 for (i = 0; i < MAX_LEVELS; i++)
4719 level_id_suffix[i] = get_level_id_suffix(i);
4720 level_id_suffix[MAX_LEVELS] = NULL;
4722 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
4723 image_id_prefix, action_id_suffix, direction_id_suffix,
4724 special_id_suffix, ignore_image_tokens);
4725 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
4726 sound_id_prefix, action_id_suffix, dummy,
4727 special_id_suffix, ignore_sound_tokens);
4728 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
4729 music_id_prefix, special_id_suffix, level_id_suffix,
4730 dummy, ignore_music_tokens);
4733 static void InitMixer()
4741 char *filename_font_initial = NULL;
4742 Bitmap *bitmap_font_initial = NULL;
4746 /* determine settings for initial font (for displaying startup messages) */
4747 for (i = 0; image_config[i].token != NULL; i++)
4749 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4751 char font_token[128];
4754 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
4755 len_font_token = strlen(font_token);
4757 if (strEqual(image_config[i].token, font_token))
4758 filename_font_initial = image_config[i].value;
4759 else if (strlen(image_config[i].token) > len_font_token &&
4760 strncmp(image_config[i].token, font_token, len_font_token) == 0)
4762 if (strEqual(&image_config[i].token[len_font_token], ".x"))
4763 font_initial[j].src_x = atoi(image_config[i].value);
4764 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
4765 font_initial[j].src_y = atoi(image_config[i].value);
4766 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
4767 font_initial[j].width = atoi(image_config[i].value);
4768 else if (strEqual(&image_config[i].token[len_font_token],".height"))
4769 font_initial[j].height = atoi(image_config[i].value);
4774 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4776 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
4777 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
4780 if (filename_font_initial == NULL) /* should not happen */
4781 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
4783 /* create additional image buffers for double-buffering and cross-fading */
4784 bitmap_db_cross = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
4785 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
4786 bitmap_db_panel = CreateBitmap(DXSIZE, DYSIZE, DEFAULT_DEPTH);
4787 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
4789 /* initialize screen properties */
4790 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
4791 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
4793 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
4794 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
4795 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
4797 bitmap_font_initial = LoadCustomImage(filename_font_initial);
4799 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4800 font_initial[j].bitmap = bitmap_font_initial;
4802 InitFontGraphicInfo();
4804 font_height = getFontHeight(FC_RED);
4807 DrawInitText(getWindowTitleString(), 20, FC_YELLOW);
4809 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
4811 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
4812 DrawInitText(PROGRAM_WEBSITE_STRING, WIN_YSIZE - 20 - font_height, FC_RED);
4814 DrawInitText("Loading graphics", 120, FC_GREEN);
4817 void RedrawBackground()
4819 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
4820 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
4822 redraw_mask = REDRAW_ALL;
4825 void InitGfxBackground()
4829 fieldbuffer = bitmap_db_field;
4830 SetDrawtoField(DRAW_BACKBUFFER);
4834 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
4835 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
4837 for (x = 0; x < MAX_BUF_XSIZE; x++)
4838 for (y = 0; y < MAX_BUF_YSIZE; y++)
4841 redraw_mask = REDRAW_ALL;
4844 static void InitLevelInfo()
4846 LoadLevelInfo(); /* global level info */
4847 LoadLevelSetup_LastSeries(); /* last played series info */
4848 LoadLevelSetup_SeriesInfo(); /* last played level info */
4851 void InitLevelArtworkInfo()
4853 LoadLevelArtworkInfo();
4856 static void InitImages()
4858 setLevelArtworkDir(artwork.gfx_first);
4861 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
4862 leveldir_current->identifier,
4863 artwork.gfx_current_identifier,
4864 artwork.gfx_current->identifier,
4865 leveldir_current->graphics_set,
4866 leveldir_current->graphics_path);
4869 ReloadCustomImages();
4871 LoadCustomElementDescriptions();
4872 LoadSpecialMenuDesignSettings();
4874 ReinitializeGraphics();
4877 static void InitSound(char *identifier)
4879 if (identifier == NULL)
4880 identifier = artwork.snd_current->identifier;
4882 /* set artwork path to send it to the sound server process */
4883 setLevelArtworkDir(artwork.snd_first);
4885 InitReloadCustomSounds(identifier);
4886 ReinitializeSounds();
4889 static void InitMusic(char *identifier)
4891 if (identifier == NULL)
4892 identifier = artwork.mus_current->identifier;
4894 /* set artwork path to send it to the sound server process */
4895 setLevelArtworkDir(artwork.mus_first);
4897 InitReloadCustomMusic(identifier);
4898 ReinitializeMusic();
4901 void InitNetworkServer()
4903 #if defined(NETWORK_AVALIABLE)
4907 if (!options.network)
4910 #if defined(NETWORK_AVALIABLE)
4911 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
4913 if (!ConnectToServer(options.server_host, options.server_port))
4914 Error(ERR_EXIT, "cannot connect to network game server");
4916 SendToServer_PlayerName(setup.player_name);
4917 SendToServer_ProtocolVersion();
4920 SendToServer_NrWanted(nr_wanted);
4924 static char *getNewArtworkIdentifier(int type)
4926 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
4927 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
4928 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
4929 static boolean initialized[3] = { FALSE, FALSE, FALSE };
4930 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
4931 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
4932 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
4933 char *leveldir_identifier = leveldir_current->identifier;
4935 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
4936 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
4938 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
4940 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
4941 char *artwork_current_identifier;
4942 char *artwork_new_identifier = NULL; /* default: nothing has changed */
4944 /* leveldir_current may be invalid (level group, parent link) */
4945 if (!validLevelSeries(leveldir_current))
4948 /* 1st step: determine artwork set to be activated in descending order:
4949 --------------------------------------------------------------------
4950 1. setup artwork (when configured to override everything else)
4951 2. artwork set configured in "levelinfo.conf" of current level set
4952 (artwork in level directory will have priority when loading later)
4953 3. artwork in level directory (stored in artwork sub-directory)
4954 4. setup artwork (currently configured in setup menu) */
4956 if (setup_override_artwork)
4957 artwork_current_identifier = setup_artwork_set;
4958 else if (leveldir_artwork_set != NULL)
4959 artwork_current_identifier = leveldir_artwork_set;
4960 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
4961 artwork_current_identifier = leveldir_identifier;
4963 artwork_current_identifier = setup_artwork_set;
4966 /* 2nd step: check if it is really needed to reload artwork set
4967 ------------------------------------------------------------ */
4970 if (type == ARTWORK_TYPE_GRAPHICS)
4971 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
4972 artwork_new_identifier,
4973 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4974 artwork_current_identifier,
4975 leveldir_current->graphics_set,
4976 leveldir_current->identifier);
4979 /* ---------- reload if level set and also artwork set has changed ------- */
4980 if (leveldir_current_identifier[type] != leveldir_identifier &&
4981 (last_has_level_artwork_set[type] || has_level_artwork_set))
4982 artwork_new_identifier = artwork_current_identifier;
4984 leveldir_current_identifier[type] = leveldir_identifier;
4985 last_has_level_artwork_set[type] = has_level_artwork_set;
4988 if (type == ARTWORK_TYPE_GRAPHICS)
4989 printf("::: 1: '%s'\n", artwork_new_identifier);
4992 /* ---------- reload if "override artwork" setting has changed ----------- */
4993 if (last_override_level_artwork[type] != setup_override_artwork)
4994 artwork_new_identifier = artwork_current_identifier;
4996 last_override_level_artwork[type] = setup_override_artwork;
4999 if (type == ARTWORK_TYPE_GRAPHICS)
5000 printf("::: 2: '%s'\n", artwork_new_identifier);
5003 /* ---------- reload if current artwork identifier has changed ----------- */
5004 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5005 artwork_current_identifier))
5006 artwork_new_identifier = artwork_current_identifier;
5008 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5011 if (type == ARTWORK_TYPE_GRAPHICS)
5012 printf("::: 3: '%s'\n", artwork_new_identifier);
5015 /* ---------- do not reload directly after starting ---------------------- */
5016 if (!initialized[type])
5017 artwork_new_identifier = NULL;
5019 initialized[type] = TRUE;
5022 if (type == ARTWORK_TYPE_GRAPHICS)
5023 printf("::: 4: '%s'\n", artwork_new_identifier);
5027 if (type == ARTWORK_TYPE_GRAPHICS)
5028 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
5029 artwork.gfx_current_identifier, artwork_current_identifier,
5030 artwork.gfx_current->identifier, leveldir_current->graphics_set,
5031 artwork_new_identifier);
5034 return artwork_new_identifier;
5037 void ReloadCustomArtwork(int force_reload)
5039 char *gfx_new_identifier;
5040 char *snd_new_identifier;
5041 char *mus_new_identifier;
5042 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5043 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5044 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5045 boolean redraw_screen = FALSE;
5047 force_reload_gfx |= AdjustGraphicsForEMC();
5049 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5050 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5051 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5053 if (gfx_new_identifier != NULL || force_reload_gfx)
5056 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5057 artwork.gfx_current_identifier,
5059 artwork.gfx_current->identifier,
5060 leveldir_current->graphics_set);
5063 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
5067 redraw_screen = TRUE;
5070 if (snd_new_identifier != NULL || force_reload_snd)
5072 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
5074 InitSound(snd_new_identifier);
5076 redraw_screen = TRUE;
5079 if (mus_new_identifier != NULL || force_reload_mus)
5081 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
5083 InitMusic(mus_new_identifier);
5085 redraw_screen = TRUE;
5092 /* force redraw of (open or closed) door graphics */
5093 SetDoorState(DOOR_OPEN_ALL);
5094 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5098 void KeyboardAutoRepeatOffUnlessAutoplay()
5100 if (global.autoplay_leveldir == NULL)
5101 KeyboardAutoRepeatOff();
5105 /* ========================================================================= */
5107 /* ========================================================================= */
5111 InitGlobal(); /* initialize some global variables */
5113 if (options.execute_command)
5114 Execute_Command(options.execute_command);
5116 if (options.serveronly)
5118 #if defined(PLATFORM_UNIX)
5119 NetworkServer(options.server_port, options.serveronly);
5121 Error(ERR_WARN, "networking only supported in Unix version");
5124 exit(0); /* never reached, server loops forever */
5131 InitArtworkInfo(); /* needed before loading gfx, sound & music */
5132 InitArtworkConfig(); /* needed before forking sound child process */
5137 InitRND(NEW_RANDOMIZE);
5138 InitSimpleRandom(NEW_RANDOMIZE);
5143 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
5145 InitEventFilter(FilterMouseMotionEvents);
5147 InitElementPropertiesStatic();
5148 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5152 // debug_print_timestamp(0, "INIT");
5154 // debug_print_timestamp(0, "TIME InitLevelInfo: ");
5155 InitLevelArtworkInfo();
5156 // debug_print_timestamp(0, "TIME InitLevelArtworkInfo: ");
5158 InitImages(); /* needs to know current level directory */
5159 InitSound(NULL); /* needs to know current level directory */
5160 InitMusic(NULL); /* needs to know current level directory */
5162 InitGfxBackground();
5168 if (global.autoplay_leveldir)
5173 else if (global.convert_leveldir)
5179 game_status = GAME_MODE_MAIN;
5183 InitNetworkServer();
5186 void CloseAllAndExit(int exit_value)
5191 CloseAudio(); /* called after freeing sounds (needed for SDL) */
5199 #if defined(TARGET_SDL)
5200 if (network_server) /* terminate network server */
5201 SDL_KillThread(server_thread);
5204 CloseVideoDisplay();
5205 ClosePlatformDependentStuff();
5207 if (exit_value != 0)
5208 NotifyUserAboutErrorFile();