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].valign = VALIGN_MIDDLE; /* default for title screens */
1024 graphic_info[graphic].sort_priority = 0; /* default for title screens */
1027 /* optional zoom factor for scaling up the image to a larger size */
1028 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1029 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1030 if (graphic_info[graphic].scale_up_factor < 1)
1031 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
1035 if (graphic_info[graphic].use_image_size)
1037 /* set new default bitmap size (with scaling, but without small images) */
1038 graphic_info[graphic].width = get_scaled_graphic_width(graphic);
1039 graphic_info[graphic].height = get_scaled_graphic_height(graphic);
1043 /* optional x and y tile position of animation frame sequence */
1044 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1045 graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
1046 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1047 graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
1049 /* optional x and y pixel position of animation frame sequence */
1050 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1051 graphic_info[graphic].src_x = parameter[GFX_ARG_X];
1052 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1053 graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
1055 /* optional width and height of each animation frame */
1056 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1057 graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
1058 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1059 graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
1062 /* optional zoom factor for scaling up the image to a larger size */
1063 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1064 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1065 if (graphic_info[graphic].scale_up_factor < 1)
1066 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
1071 /* get final bitmap size (with scaling, but without small images) */
1072 int src_image_width = get_scaled_graphic_width(graphic);
1073 int src_image_height = get_scaled_graphic_height(graphic);
1075 anim_frames_per_row = src_image_width / graphic_info[graphic].width;
1076 anim_frames_per_col = src_image_height / graphic_info[graphic].height;
1078 graphic_info[graphic].src_image_width = src_image_width;
1079 graphic_info[graphic].src_image_height = src_image_height;
1082 /* correct x or y offset dependent of vertical or horizontal frame order */
1083 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1085 graphic_info[graphic].offset_y =
1086 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1087 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
1088 anim_frames_per_line = anim_frames_per_col;
1090 else /* frames are ordered horizontally */
1092 graphic_info[graphic].offset_x =
1093 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1094 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
1095 anim_frames_per_line = anim_frames_per_row;
1098 /* optionally, the x and y offset of frames can be specified directly */
1099 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1100 graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
1101 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1102 graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
1104 /* optionally, moving animations may have separate start and end graphics */
1105 graphic_info[graphic].double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1107 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1108 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1110 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1111 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1112 graphic_info[graphic].offset2_y =
1113 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1114 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].height);
1115 else /* frames are ordered horizontally */
1116 graphic_info[graphic].offset2_x =
1117 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1118 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].width);
1120 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1121 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1122 graphic_info[graphic].offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1123 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1124 graphic_info[graphic].offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1126 /* optionally, the second movement tile can be specified as start tile */
1127 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1128 graphic_info[graphic].swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1130 /* automatically determine correct number of frames, if not defined */
1131 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1132 graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
1133 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1134 graphic_info[graphic].anim_frames = anim_frames_per_row;
1135 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1136 graphic_info[graphic].anim_frames = anim_frames_per_col;
1138 graphic_info[graphic].anim_frames = 1;
1140 if (graphic_info[graphic].anim_frames == 0) /* frames must be at least 1 */
1141 graphic_info[graphic].anim_frames = 1;
1143 graphic_info[graphic].anim_frames_per_line =
1144 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1145 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1147 graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
1148 if (graphic_info[graphic].anim_delay == 0) /* delay must be at least 1 */
1149 graphic_info[graphic].anim_delay = 1;
1151 graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
1153 if (graphic_info[graphic].anim_frames == 1)
1154 graphic_info[graphic].anim_mode = ANIM_NONE;
1157 /* automatically determine correct start frame, if not defined */
1158 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1159 graphic_info[graphic].anim_start_frame = 0;
1160 else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
1161 graphic_info[graphic].anim_start_frame =
1162 graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1164 graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
1166 /* animation synchronized with global frame counter, not move position */
1167 graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1169 /* optional element for cloning crumble graphics */
1170 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1171 graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1173 /* optional element for cloning digging graphics */
1174 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1175 graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1177 /* optional border size for "crumbling" diggable graphics */
1178 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1179 graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
1181 /* this is only used for player "boring" and "sleeping" actions */
1182 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1183 graphic_info[graphic].anim_delay_fixed =
1184 parameter[GFX_ARG_ANIM_DELAY_FIXED];
1185 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1186 graphic_info[graphic].anim_delay_random =
1187 parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1188 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1189 graphic_info[graphic].post_delay_fixed =
1190 parameter[GFX_ARG_POST_DELAY_FIXED];
1191 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1192 graphic_info[graphic].post_delay_random =
1193 parameter[GFX_ARG_POST_DELAY_RANDOM];
1195 /* this is only used for toon animations */
1196 graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
1197 graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY];
1199 /* this is only used for drawing font characters */
1200 graphic_info[graphic].draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1201 graphic_info[graphic].draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1203 /* this is only used for drawing envelope graphics */
1204 graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1206 /* optional graphic for cloning all graphics settings */
1207 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1208 graphic_info[graphic].clone_from = parameter[GFX_ARG_CLONE_FROM];
1210 /* optional settings for drawing title screens */
1211 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1212 graphic_info[graphic].fade_delay = parameter[GFX_ARG_FADE_DELAY];
1213 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1214 graphic_info[graphic].post_delay = parameter[GFX_ARG_POST_DELAY];
1215 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1216 graphic_info[graphic].auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1217 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1218 graphic_info[graphic].align = parameter[GFX_ARG_ALIGN];
1219 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1220 graphic_info[graphic].valign = parameter[GFX_ARG_VALIGN];
1221 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1222 graphic_info[graphic].sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1225 static void set_cloned_graphic_parameters(int graphic)
1227 int fallback_graphic = IMG_CHAR_EXCLAM;
1228 int max_num_images = getImageListSize();
1229 int clone_graphic = graphic_info[graphic].clone_from;
1230 int num_references_followed = 1;
1232 while (graphic_info[clone_graphic].clone_from != -1 &&
1233 num_references_followed < max_num_images)
1235 clone_graphic = graphic_info[clone_graphic].clone_from;
1237 num_references_followed++;
1240 if (num_references_followed >= max_num_images)
1242 Error(ERR_INFO_LINE, "-");
1243 Error(ERR_INFO, "warning: error found in config file:");
1244 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1245 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1246 Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1247 Error(ERR_INFO, "custom graphic rejected for this element/action");
1249 if (graphic == fallback_graphic)
1250 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1252 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1253 Error(ERR_INFO_LINE, "-");
1255 graphic_info[graphic] = graphic_info[fallback_graphic];
1259 graphic_info[graphic] = graphic_info[clone_graphic];
1260 graphic_info[graphic].clone_from = clone_graphic;
1264 static void InitGraphicInfo()
1266 int fallback_graphic = IMG_CHAR_EXCLAM;
1267 int num_images = getImageListSize();
1270 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1271 static boolean clipmasks_initialized = FALSE;
1273 XGCValues clip_gc_values;
1274 unsigned long clip_gc_valuemask;
1275 GC copy_clipmask_gc = None;
1278 /* use image size as default values for width and height for these images */
1279 static int full_size_graphics[] =
1284 IMG_BACKGROUND_ENVELOPE_1,
1285 IMG_BACKGROUND_ENVELOPE_2,
1286 IMG_BACKGROUND_ENVELOPE_3,
1287 IMG_BACKGROUND_ENVELOPE_4,
1290 IMG_BACKGROUND_TITLE,
1291 IMG_BACKGROUND_MESSAGE,
1292 IMG_BACKGROUND_MAIN,
1293 IMG_BACKGROUND_LEVELS,
1294 IMG_BACKGROUND_SCORES,
1295 IMG_BACKGROUND_EDITOR,
1296 IMG_BACKGROUND_INFO,
1297 IMG_BACKGROUND_INFO_ELEMENTS,
1298 IMG_BACKGROUND_INFO_MUSIC,
1299 IMG_BACKGROUND_INFO_CREDITS,
1300 IMG_BACKGROUND_INFO_PROGRAM,
1301 IMG_BACKGROUND_INFO_LEVELSET,
1302 IMG_BACKGROUND_SETUP,
1303 IMG_BACKGROUND_DOOR,
1305 IMG_TITLESCREEN_INITIAL_1,
1306 IMG_TITLESCREEN_INITIAL_2,
1307 IMG_TITLESCREEN_INITIAL_3,
1308 IMG_TITLESCREEN_INITIAL_4,
1309 IMG_TITLESCREEN_INITIAL_5,
1319 checked_free(graphic_info);
1321 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1324 /* initialize "use_image_size" flag with default value */
1325 for (i = 0; i < num_images; i++)
1326 graphic_info[i].use_image_size = FALSE;
1328 /* initialize "use_image_size" flag from static configuration above */
1329 for (i = 0; full_size_graphics[i] != -1; i++)
1330 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1333 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1334 if (clipmasks_initialized)
1336 for (i = 0; i < num_images; i++)
1338 if (graphic_info[i].clip_mask)
1339 XFreePixmap(display, graphic_info[i].clip_mask);
1340 if (graphic_info[i].clip_gc)
1341 XFreeGC(display, graphic_info[i].clip_gc);
1343 graphic_info[i].clip_mask = None;
1344 graphic_info[i].clip_gc = None;
1349 /* first set all graphic paramaters ... */
1350 for (i = 0; i < num_images; i++)
1351 set_graphic_parameters(i);
1353 /* ... then copy these parameters for cloned graphics */
1354 for (i = 0; i < num_images; i++)
1355 if (graphic_info[i].clone_from != -1)
1356 set_cloned_graphic_parameters(i);
1358 for (i = 0; i < num_images; i++)
1363 int first_frame, last_frame;
1364 int src_bitmap_width, src_bitmap_height;
1366 /* now check if no animation frames are outside of the loaded image */
1368 if (graphic_info[i].bitmap == NULL)
1369 continue; /* skip check for optional images that are undefined */
1371 /* get image size (this can differ from the standard element tile size!) */
1372 width = graphic_info[i].width;
1373 height = graphic_info[i].height;
1375 /* get final bitmap size (with scaling, but without small images) */
1376 src_bitmap_width = graphic_info[i].src_image_width;
1377 src_bitmap_height = graphic_info[i].src_image_height;
1379 /* check if first animation frame is inside specified bitmap */
1382 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1385 /* this avoids calculating wrong start position for out-of-bounds frame */
1386 src_x = graphic_info[i].src_x;
1387 src_y = graphic_info[i].src_y;
1390 if (src_x < 0 || src_y < 0 ||
1391 src_x + width > src_bitmap_width ||
1392 src_y + height > src_bitmap_height)
1394 Error(ERR_INFO_LINE, "-");
1395 Error(ERR_INFO, "warning: error found in config file:");
1396 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1397 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1398 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1400 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1401 src_x, src_y, src_bitmap_width, src_bitmap_height);
1402 Error(ERR_INFO, "custom graphic rejected for this element/action");
1404 if (i == fallback_graphic)
1405 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1407 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1408 Error(ERR_INFO_LINE, "-");
1410 graphic_info[i] = graphic_info[fallback_graphic];
1413 /* check if last animation frame is inside specified bitmap */
1415 last_frame = graphic_info[i].anim_frames - 1;
1416 getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1418 if (src_x < 0 || src_y < 0 ||
1419 src_x + width > src_bitmap_width ||
1420 src_y + height > src_bitmap_height)
1422 Error(ERR_INFO_LINE, "-");
1423 Error(ERR_INFO, "warning: error found in config file:");
1424 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1425 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1426 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1428 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1429 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1430 Error(ERR_INFO, "custom graphic rejected for this element/action");
1432 if (i == fallback_graphic)
1433 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1435 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1436 Error(ERR_INFO_LINE, "-");
1438 graphic_info[i] = graphic_info[fallback_graphic];
1441 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1442 /* currently we only need a tile clip mask from the first frame */
1443 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1445 if (copy_clipmask_gc == None)
1447 clip_gc_values.graphics_exposures = False;
1448 clip_gc_valuemask = GCGraphicsExposures;
1449 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
1450 clip_gc_valuemask, &clip_gc_values);
1453 graphic_info[i].clip_mask =
1454 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
1456 src_pixmap = src_bitmap->clip_mask;
1457 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
1458 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
1460 clip_gc_values.graphics_exposures = False;
1461 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
1462 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
1464 graphic_info[i].clip_gc =
1465 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
1469 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1470 if (copy_clipmask_gc)
1471 XFreeGC(display, copy_clipmask_gc);
1473 clipmasks_initialized = TRUE;
1477 static void InitElementSoundInfo()
1479 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1480 int num_property_mappings = getSoundListPropertyMappingSize();
1483 /* set values to -1 to identify later as "uninitialized" values */
1484 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1485 for (act = 0; act < NUM_ACTIONS; act++)
1486 element_info[i].sound[act] = -1;
1488 /* initialize element/sound mapping from static configuration */
1489 for (i = 0; element_to_sound[i].element > -1; i++)
1491 int element = element_to_sound[i].element;
1492 int action = element_to_sound[i].action;
1493 int sound = element_to_sound[i].sound;
1494 boolean is_class = element_to_sound[i].is_class;
1497 action = ACTION_DEFAULT;
1500 element_info[element].sound[action] = sound;
1502 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1503 if (strEqual(element_info[j].class_name,
1504 element_info[element].class_name))
1505 element_info[j].sound[action] = sound;
1508 /* initialize element class/sound mapping from dynamic configuration */
1509 for (i = 0; i < num_property_mappings; i++)
1511 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1512 int action = property_mapping[i].ext1_index;
1513 int sound = property_mapping[i].artwork_index;
1515 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1519 action = ACTION_DEFAULT;
1521 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1522 if (strEqual(element_info[j].class_name,
1523 element_info[element_class].class_name))
1524 element_info[j].sound[action] = sound;
1527 /* initialize element/sound mapping from dynamic configuration */
1528 for (i = 0; i < num_property_mappings; i++)
1530 int element = property_mapping[i].base_index;
1531 int action = property_mapping[i].ext1_index;
1532 int sound = property_mapping[i].artwork_index;
1534 if (element >= MAX_NUM_ELEMENTS)
1538 action = ACTION_DEFAULT;
1540 element_info[element].sound[action] = sound;
1543 /* now set all '-1' values to element specific default values */
1544 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1546 for (act = 0; act < NUM_ACTIONS; act++)
1548 /* generic default action sound (defined by "[default]" directive) */
1549 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1551 /* look for special default action sound (classic game specific) */
1552 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1553 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1554 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1555 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1556 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1557 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1559 /* !!! there's no such thing as a "default action sound" !!! */
1561 /* look for element specific default sound (independent from action) */
1562 if (element_info[i].sound[ACTION_DEFAULT] != -1)
1563 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
1567 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1568 /* !!! make this better !!! */
1569 if (i == EL_EMPTY_SPACE)
1570 default_action_sound = element_info[EL_DEFAULT].sound[act];
1573 /* no sound for this specific action -- use default action sound */
1574 if (element_info[i].sound[act] == -1)
1575 element_info[i].sound[act] = default_action_sound;
1579 /* copy sound settings to some elements that are only stored in level file
1580 in native R'n'D levels, but are used by game engine in native EM levels */
1581 for (i = 0; copy_properties[i][0] != -1; i++)
1582 for (j = 1; j <= 4; j++)
1583 for (act = 0; act < NUM_ACTIONS; act++)
1584 element_info[copy_properties[i][j]].sound[act] =
1585 element_info[copy_properties[i][0]].sound[act];
1588 static void InitGameModeSoundInfo()
1592 /* set values to -1 to identify later as "uninitialized" values */
1593 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1596 /* initialize gamemode/sound mapping from static configuration */
1597 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1599 int gamemode = gamemode_to_sound[i].gamemode;
1600 int sound = gamemode_to_sound[i].sound;
1603 gamemode = GAME_MODE_DEFAULT;
1605 menu.sound[gamemode] = sound;
1608 /* now set all '-1' values to levelset specific default values */
1609 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1610 if (menu.sound[i] == -1)
1611 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1614 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1615 if (menu.sound[i] != -1)
1616 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
1620 static void set_sound_parameters(int sound, char **parameter_raw)
1622 int parameter[NUM_SND_ARGS];
1625 /* get integer values from string parameters */
1626 for (i = 0; i < NUM_SND_ARGS; i++)
1628 get_parameter_value(parameter_raw[i],
1629 sound_config_suffix[i].token,
1630 sound_config_suffix[i].type);
1632 /* explicit loop mode setting in configuration overrides default value */
1633 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1634 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1636 /* sound volume to change the original volume when loading the sound file */
1637 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1639 /* sound priority to give certain sounds a higher or lower priority */
1640 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1643 static void InitSoundInfo()
1645 int *sound_effect_properties;
1646 int num_sounds = getSoundListSize();
1649 checked_free(sound_info);
1651 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1652 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1654 /* initialize sound effect for all elements to "no sound" */
1655 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1656 for (j = 0; j < NUM_ACTIONS; j++)
1657 element_info[i].sound[j] = SND_UNDEFINED;
1659 for (i = 0; i < num_sounds; i++)
1661 struct FileInfo *sound = getSoundListEntry(i);
1662 int len_effect_text = strlen(sound->token);
1664 sound_effect_properties[i] = ACTION_OTHER;
1665 sound_info[i].loop = FALSE; /* default: play sound only once */
1668 printf("::: sound %d: '%s'\n", i, sound->token);
1671 /* determine all loop sounds and identify certain sound classes */
1673 for (j = 0; element_action_info[j].suffix; j++)
1675 int len_action_text = strlen(element_action_info[j].suffix);
1677 if (len_action_text < len_effect_text &&
1678 strEqual(&sound->token[len_effect_text - len_action_text],
1679 element_action_info[j].suffix))
1681 sound_effect_properties[i] = element_action_info[j].value;
1682 sound_info[i].loop = element_action_info[j].is_loop_sound;
1688 /* associate elements and some selected sound actions */
1690 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1692 if (element_info[j].class_name)
1694 int len_class_text = strlen(element_info[j].class_name);
1696 if (len_class_text + 1 < len_effect_text &&
1697 strncmp(sound->token,
1698 element_info[j].class_name, len_class_text) == 0 &&
1699 sound->token[len_class_text] == '.')
1701 int sound_action_value = sound_effect_properties[i];
1703 element_info[j].sound[sound_action_value] = i;
1708 set_sound_parameters(i, sound->parameter);
1711 free(sound_effect_properties);
1714 static void InitGameModeMusicInfo()
1716 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1717 int num_property_mappings = getMusicListPropertyMappingSize();
1718 int default_levelset_music = -1;
1721 /* set values to -1 to identify later as "uninitialized" values */
1722 for (i = 0; i < MAX_LEVELS; i++)
1723 levelset.music[i] = -1;
1724 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1727 /* initialize gamemode/music mapping from static configuration */
1728 for (i = 0; gamemode_to_music[i].music > -1; i++)
1730 int gamemode = gamemode_to_music[i].gamemode;
1731 int music = gamemode_to_music[i].music;
1734 printf("::: gamemode == %d, music == %d\n", gamemode, music);
1738 gamemode = GAME_MODE_DEFAULT;
1740 menu.music[gamemode] = music;
1743 /* initialize gamemode/music mapping from dynamic configuration */
1744 for (i = 0; i < num_property_mappings; i++)
1746 int prefix = property_mapping[i].base_index;
1747 int gamemode = property_mapping[i].ext1_index;
1748 int level = property_mapping[i].ext2_index;
1749 int music = property_mapping[i].artwork_index;
1752 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
1753 prefix, gamemode, level, music);
1756 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1760 gamemode = GAME_MODE_DEFAULT;
1762 /* level specific music only allowed for in-game music */
1763 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1764 gamemode = GAME_MODE_PLAYING;
1769 default_levelset_music = music;
1772 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1773 levelset.music[level] = music;
1774 if (gamemode != GAME_MODE_PLAYING)
1775 menu.music[gamemode] = music;
1778 /* now set all '-1' values to menu specific default values */
1779 /* (undefined values of "levelset.music[]" might stay at "-1" to
1780 allow dynamic selection of music files from music directory!) */
1781 for (i = 0; i < MAX_LEVELS; i++)
1782 if (levelset.music[i] == -1)
1783 levelset.music[i] = default_levelset_music;
1784 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1785 if (menu.music[i] == -1)
1786 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1789 for (i = 0; i < MAX_LEVELS; i++)
1790 if (levelset.music[i] != -1)
1791 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
1792 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1793 if (menu.music[i] != -1)
1794 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
1798 static void set_music_parameters(int music, char **parameter_raw)
1800 int parameter[NUM_MUS_ARGS];
1803 /* get integer values from string parameters */
1804 for (i = 0; i < NUM_MUS_ARGS; i++)
1806 get_parameter_value(parameter_raw[i],
1807 music_config_suffix[i].token,
1808 music_config_suffix[i].type);
1810 /* explicit loop mode setting in configuration overrides default value */
1811 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1812 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1815 static void InitMusicInfo()
1817 int num_music = getMusicListSize();
1820 checked_free(music_info);
1822 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1824 for (i = 0; i < num_music; i++)
1826 struct FileInfo *music = getMusicListEntry(i);
1827 int len_music_text = strlen(music->token);
1829 music_info[i].loop = TRUE; /* default: play music in loop mode */
1831 /* determine all loop music */
1833 for (j = 0; music_prefix_info[j].prefix; j++)
1835 int len_prefix_text = strlen(music_prefix_info[j].prefix);
1837 if (len_prefix_text < len_music_text &&
1838 strncmp(music->token,
1839 music_prefix_info[j].prefix, len_prefix_text) == 0)
1841 music_info[i].loop = music_prefix_info[j].is_loop_music;
1847 set_music_parameters(i, music->parameter);
1851 static void ReinitializeGraphics()
1853 InitGraphicInfo(); /* graphic properties mapping */
1854 InitElementGraphicInfo(); /* element game graphic mapping */
1855 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
1857 InitElementSmallImages(); /* scale elements to all needed sizes */
1858 InitScaledImages(); /* scale all other images, if needed */
1859 InitFontGraphicInfo(); /* initialize text drawing functions */
1861 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
1863 SetMainBackgroundImage(IMG_BACKGROUND);
1864 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1870 static void ReinitializeSounds()
1872 InitSoundInfo(); /* sound properties mapping */
1873 InitElementSoundInfo(); /* element game sound mapping */
1874 InitGameModeSoundInfo(); /* game mode sound mapping */
1876 InitPlayLevelSound(); /* internal game sound settings */
1879 static void ReinitializeMusic()
1881 InitMusicInfo(); /* music properties mapping */
1882 InitGameModeMusicInfo(); /* game mode music mapping */
1885 static int get_special_property_bit(int element, int property_bit_nr)
1887 struct PropertyBitInfo
1893 static struct PropertyBitInfo pb_can_move_into_acid[] =
1895 /* the player may be able fall into acid when gravity is activated */
1900 { EL_SP_MURPHY, 0 },
1901 { EL_SOKOBAN_FIELD_PLAYER, 0 },
1903 /* all elements that can move may be able to also move into acid */
1906 { EL_BUG_RIGHT, 1 },
1909 { EL_SPACESHIP, 2 },
1910 { EL_SPACESHIP_LEFT, 2 },
1911 { EL_SPACESHIP_RIGHT, 2 },
1912 { EL_SPACESHIP_UP, 2 },
1913 { EL_SPACESHIP_DOWN, 2 },
1914 { EL_BD_BUTTERFLY, 3 },
1915 { EL_BD_BUTTERFLY_LEFT, 3 },
1916 { EL_BD_BUTTERFLY_RIGHT, 3 },
1917 { EL_BD_BUTTERFLY_UP, 3 },
1918 { EL_BD_BUTTERFLY_DOWN, 3 },
1919 { EL_BD_FIREFLY, 4 },
1920 { EL_BD_FIREFLY_LEFT, 4 },
1921 { EL_BD_FIREFLY_RIGHT, 4 },
1922 { EL_BD_FIREFLY_UP, 4 },
1923 { EL_BD_FIREFLY_DOWN, 4 },
1925 { EL_YAMYAM_LEFT, 5 },
1926 { EL_YAMYAM_RIGHT, 5 },
1927 { EL_YAMYAM_UP, 5 },
1928 { EL_YAMYAM_DOWN, 5 },
1929 { EL_DARK_YAMYAM, 6 },
1932 { EL_PACMAN_LEFT, 8 },
1933 { EL_PACMAN_RIGHT, 8 },
1934 { EL_PACMAN_UP, 8 },
1935 { EL_PACMAN_DOWN, 8 },
1937 { EL_MOLE_LEFT, 9 },
1938 { EL_MOLE_RIGHT, 9 },
1940 { EL_MOLE_DOWN, 9 },
1944 { EL_SATELLITE, 13 },
1945 { EL_SP_SNIKSNAK, 14 },
1946 { EL_SP_ELECTRON, 15 },
1949 { EL_EMC_ANDROID, 18 },
1954 static struct PropertyBitInfo pb_dont_collide_with[] =
1956 { EL_SP_SNIKSNAK, 0 },
1957 { EL_SP_ELECTRON, 1 },
1965 struct PropertyBitInfo *pb_info;
1968 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
1969 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
1974 struct PropertyBitInfo *pb_info = NULL;
1977 for (i = 0; pb_definition[i].bit_nr != -1; i++)
1978 if (pb_definition[i].bit_nr == property_bit_nr)
1979 pb_info = pb_definition[i].pb_info;
1981 if (pb_info == NULL)
1984 for (i = 0; pb_info[i].element != -1; i++)
1985 if (pb_info[i].element == element)
1986 return pb_info[i].bit_nr;
1991 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
1992 boolean property_value)
1994 int bit_nr = get_special_property_bit(element, property_bit_nr);
1999 *bitfield |= (1 << bit_nr);
2001 *bitfield &= ~(1 << bit_nr);
2005 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2007 int bit_nr = get_special_property_bit(element, property_bit_nr);
2010 return ((*bitfield & (1 << bit_nr)) != 0);
2015 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2017 static int group_nr;
2018 static struct ElementGroupInfo *group;
2019 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2022 if (actual_group == NULL) /* not yet initialized */
2025 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
2027 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2028 group_element - EL_GROUP_START + 1);
2030 /* replace element which caused too deep recursion by question mark */
2031 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2036 if (recursion_depth == 0) /* initialization */
2038 group = actual_group;
2039 group_nr = GROUP_NR(group_element);
2041 group->num_elements_resolved = 0;
2042 group->choice_pos = 0;
2044 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2045 element_info[i].in_group[group_nr] = FALSE;
2048 for (i = 0; i < actual_group->num_elements; i++)
2050 int element = actual_group->element[i];
2052 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2055 if (IS_GROUP_ELEMENT(element))
2056 ResolveGroupElementExt(element, recursion_depth + 1);
2059 group->element_resolved[group->num_elements_resolved++] = element;
2060 element_info[element].in_group[group_nr] = TRUE;
2065 void ResolveGroupElement(int group_element)
2067 ResolveGroupElementExt(group_element, 0);
2070 void InitElementPropertiesStatic()
2072 static int ep_diggable[] =
2077 EL_SP_BUGGY_BASE_ACTIVATING,
2080 EL_INVISIBLE_SAND_ACTIVE,
2083 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2084 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2089 EL_SP_BUGGY_BASE_ACTIVE,
2096 static int ep_collectible_only[] =
2118 EL_DYNABOMB_INCREASE_NUMBER,
2119 EL_DYNABOMB_INCREASE_SIZE,
2120 EL_DYNABOMB_INCREASE_POWER,
2138 /* !!! handle separately !!! */
2139 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2145 static int ep_dont_run_into[] =
2147 /* same elements as in 'ep_dont_touch' */
2153 /* same elements as in 'ep_dont_collide_with' */
2165 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2170 EL_SP_BUGGY_BASE_ACTIVE,
2177 static int ep_dont_collide_with[] =
2179 /* same elements as in 'ep_dont_touch' */
2196 static int ep_dont_touch[] =
2206 static int ep_indestructible[] =
2210 EL_ACID_POOL_TOPLEFT,
2211 EL_ACID_POOL_TOPRIGHT,
2212 EL_ACID_POOL_BOTTOMLEFT,
2213 EL_ACID_POOL_BOTTOM,
2214 EL_ACID_POOL_BOTTOMRIGHT,
2215 EL_SP_HARDWARE_GRAY,
2216 EL_SP_HARDWARE_GREEN,
2217 EL_SP_HARDWARE_BLUE,
2219 EL_SP_HARDWARE_YELLOW,
2220 EL_SP_HARDWARE_BASE_1,
2221 EL_SP_HARDWARE_BASE_2,
2222 EL_SP_HARDWARE_BASE_3,
2223 EL_SP_HARDWARE_BASE_4,
2224 EL_SP_HARDWARE_BASE_5,
2225 EL_SP_HARDWARE_BASE_6,
2226 EL_INVISIBLE_STEELWALL,
2227 EL_INVISIBLE_STEELWALL_ACTIVE,
2228 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2229 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2230 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2231 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2232 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2233 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2234 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2235 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2236 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2237 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2238 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2239 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2241 EL_LIGHT_SWITCH_ACTIVE,
2242 EL_SIGN_EXCLAMATION,
2243 EL_SIGN_RADIOACTIVITY,
2250 EL_SIGN_ENTRY_FORBIDDEN,
2251 EL_SIGN_EMERGENCY_EXIT,
2259 EL_STEEL_EXIT_CLOSED,
2261 EL_EM_STEEL_EXIT_CLOSED,
2262 EL_EM_STEEL_EXIT_OPEN,
2263 EL_DC_STEELWALL_1_LEFT,
2264 EL_DC_STEELWALL_1_RIGHT,
2265 EL_DC_STEELWALL_1_TOP,
2266 EL_DC_STEELWALL_1_BOTTOM,
2267 EL_DC_STEELWALL_1_HORIZONTAL,
2268 EL_DC_STEELWALL_1_VERTICAL,
2269 EL_DC_STEELWALL_1_TOPLEFT,
2270 EL_DC_STEELWALL_1_TOPRIGHT,
2271 EL_DC_STEELWALL_1_BOTTOMLEFT,
2272 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2273 EL_DC_STEELWALL_1_TOPLEFT_2,
2274 EL_DC_STEELWALL_1_TOPRIGHT_2,
2275 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2276 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2277 EL_DC_STEELWALL_2_LEFT,
2278 EL_DC_STEELWALL_2_RIGHT,
2279 EL_DC_STEELWALL_2_TOP,
2280 EL_DC_STEELWALL_2_BOTTOM,
2281 EL_DC_STEELWALL_2_HORIZONTAL,
2282 EL_DC_STEELWALL_2_VERTICAL,
2283 EL_DC_STEELWALL_2_MIDDLE,
2284 EL_DC_STEELWALL_2_SINGLE,
2285 EL_STEELWALL_SLIPPERY,
2299 EL_GATE_1_GRAY_ACTIVE,
2300 EL_GATE_2_GRAY_ACTIVE,
2301 EL_GATE_3_GRAY_ACTIVE,
2302 EL_GATE_4_GRAY_ACTIVE,
2311 EL_EM_GATE_1_GRAY_ACTIVE,
2312 EL_EM_GATE_2_GRAY_ACTIVE,
2313 EL_EM_GATE_3_GRAY_ACTIVE,
2314 EL_EM_GATE_4_GRAY_ACTIVE,
2323 EL_EMC_GATE_5_GRAY_ACTIVE,
2324 EL_EMC_GATE_6_GRAY_ACTIVE,
2325 EL_EMC_GATE_7_GRAY_ACTIVE,
2326 EL_EMC_GATE_8_GRAY_ACTIVE,
2328 EL_DC_GATE_WHITE_GRAY,
2329 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2330 EL_DC_GATE_FAKE_GRAY,
2332 EL_SWITCHGATE_OPENING,
2333 EL_SWITCHGATE_CLOSED,
2334 EL_SWITCHGATE_CLOSING,
2336 EL_DC_SWITCHGATE_SWITCH_UP,
2337 EL_DC_SWITCHGATE_SWITCH_DOWN,
2340 EL_TIMEGATE_OPENING,
2342 EL_TIMEGATE_CLOSING,
2344 EL_DC_TIMEGATE_SWITCH,
2345 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2350 EL_TUBE_VERTICAL_LEFT,
2351 EL_TUBE_VERTICAL_RIGHT,
2352 EL_TUBE_HORIZONTAL_UP,
2353 EL_TUBE_HORIZONTAL_DOWN,
2358 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2359 EL_EXPANDABLE_STEELWALL_VERTICAL,
2360 EL_EXPANDABLE_STEELWALL_ANY,
2365 static int ep_slippery[] =
2379 EL_ROBOT_WHEEL_ACTIVE,
2385 EL_ACID_POOL_TOPLEFT,
2386 EL_ACID_POOL_TOPRIGHT,
2396 EL_STEELWALL_SLIPPERY,
2399 EL_EMC_WALL_SLIPPERY_1,
2400 EL_EMC_WALL_SLIPPERY_2,
2401 EL_EMC_WALL_SLIPPERY_3,
2402 EL_EMC_WALL_SLIPPERY_4,
2404 EL_EMC_MAGIC_BALL_ACTIVE,
2409 static int ep_can_change[] =
2414 static int ep_can_move[] =
2416 /* same elements as in 'pb_can_move_into_acid' */
2439 static int ep_can_fall[] =
2453 EL_QUICKSAND_FAST_FULL,
2455 EL_BD_MAGIC_WALL_FULL,
2456 EL_DC_MAGIC_WALL_FULL,
2470 static int ep_can_smash_player[] =
2496 static int ep_can_smash_enemies[] =
2505 static int ep_can_smash_everything[] =
2514 static int ep_explodes_by_fire[] =
2516 /* same elements as in 'ep_explodes_impact' */
2521 /* same elements as in 'ep_explodes_smashed' */
2531 EL_EM_DYNAMITE_ACTIVE,
2532 EL_DYNABOMB_PLAYER_1_ACTIVE,
2533 EL_DYNABOMB_PLAYER_2_ACTIVE,
2534 EL_DYNABOMB_PLAYER_3_ACTIVE,
2535 EL_DYNABOMB_PLAYER_4_ACTIVE,
2536 EL_DYNABOMB_INCREASE_NUMBER,
2537 EL_DYNABOMB_INCREASE_SIZE,
2538 EL_DYNABOMB_INCREASE_POWER,
2539 EL_SP_DISK_RED_ACTIVE,
2553 static int ep_explodes_smashed[] =
2555 /* same elements as in 'ep_explodes_impact' */
2569 static int ep_explodes_impact[] =
2578 static int ep_walkable_over[] =
2582 EL_SOKOBAN_FIELD_EMPTY,
2588 EL_EM_STEEL_EXIT_OPEN,
2597 EL_GATE_1_GRAY_ACTIVE,
2598 EL_GATE_2_GRAY_ACTIVE,
2599 EL_GATE_3_GRAY_ACTIVE,
2600 EL_GATE_4_GRAY_ACTIVE,
2608 static int ep_walkable_inside[] =
2613 EL_TUBE_VERTICAL_LEFT,
2614 EL_TUBE_VERTICAL_RIGHT,
2615 EL_TUBE_HORIZONTAL_UP,
2616 EL_TUBE_HORIZONTAL_DOWN,
2625 static int ep_walkable_under[] =
2630 static int ep_passable_over[] =
2640 EL_EM_GATE_1_GRAY_ACTIVE,
2641 EL_EM_GATE_2_GRAY_ACTIVE,
2642 EL_EM_GATE_3_GRAY_ACTIVE,
2643 EL_EM_GATE_4_GRAY_ACTIVE,
2652 EL_EMC_GATE_5_GRAY_ACTIVE,
2653 EL_EMC_GATE_6_GRAY_ACTIVE,
2654 EL_EMC_GATE_7_GRAY_ACTIVE,
2655 EL_EMC_GATE_8_GRAY_ACTIVE,
2657 EL_DC_GATE_WHITE_GRAY,
2658 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2665 static int ep_passable_inside[] =
2671 EL_SP_PORT_HORIZONTAL,
2672 EL_SP_PORT_VERTICAL,
2674 EL_SP_GRAVITY_PORT_LEFT,
2675 EL_SP_GRAVITY_PORT_RIGHT,
2676 EL_SP_GRAVITY_PORT_UP,
2677 EL_SP_GRAVITY_PORT_DOWN,
2678 EL_SP_GRAVITY_ON_PORT_LEFT,
2679 EL_SP_GRAVITY_ON_PORT_RIGHT,
2680 EL_SP_GRAVITY_ON_PORT_UP,
2681 EL_SP_GRAVITY_ON_PORT_DOWN,
2682 EL_SP_GRAVITY_OFF_PORT_LEFT,
2683 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2684 EL_SP_GRAVITY_OFF_PORT_UP,
2685 EL_SP_GRAVITY_OFF_PORT_DOWN,
2690 static int ep_passable_under[] =
2695 static int ep_droppable[] =
2700 static int ep_explodes_1x1_old[] =
2705 static int ep_pushable[] =
2717 EL_SOKOBAN_FIELD_FULL,
2726 static int ep_explodes_cross_old[] =
2731 static int ep_protected[] =
2733 /* same elements as in 'ep_walkable_inside' */
2737 EL_TUBE_VERTICAL_LEFT,
2738 EL_TUBE_VERTICAL_RIGHT,
2739 EL_TUBE_HORIZONTAL_UP,
2740 EL_TUBE_HORIZONTAL_DOWN,
2746 /* same elements as in 'ep_passable_over' */
2755 EL_EM_GATE_1_GRAY_ACTIVE,
2756 EL_EM_GATE_2_GRAY_ACTIVE,
2757 EL_EM_GATE_3_GRAY_ACTIVE,
2758 EL_EM_GATE_4_GRAY_ACTIVE,
2767 EL_EMC_GATE_5_GRAY_ACTIVE,
2768 EL_EMC_GATE_6_GRAY_ACTIVE,
2769 EL_EMC_GATE_7_GRAY_ACTIVE,
2770 EL_EMC_GATE_8_GRAY_ACTIVE,
2772 EL_DC_GATE_WHITE_GRAY,
2773 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2777 /* same elements as in 'ep_passable_inside' */
2782 EL_SP_PORT_HORIZONTAL,
2783 EL_SP_PORT_VERTICAL,
2785 EL_SP_GRAVITY_PORT_LEFT,
2786 EL_SP_GRAVITY_PORT_RIGHT,
2787 EL_SP_GRAVITY_PORT_UP,
2788 EL_SP_GRAVITY_PORT_DOWN,
2789 EL_SP_GRAVITY_ON_PORT_LEFT,
2790 EL_SP_GRAVITY_ON_PORT_RIGHT,
2791 EL_SP_GRAVITY_ON_PORT_UP,
2792 EL_SP_GRAVITY_ON_PORT_DOWN,
2793 EL_SP_GRAVITY_OFF_PORT_LEFT,
2794 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2795 EL_SP_GRAVITY_OFF_PORT_UP,
2796 EL_SP_GRAVITY_OFF_PORT_DOWN,
2801 static int ep_throwable[] =
2806 static int ep_can_explode[] =
2808 /* same elements as in 'ep_explodes_impact' */
2813 /* same elements as in 'ep_explodes_smashed' */
2819 /* elements that can explode by explosion or by dragonfire */
2823 EL_EM_DYNAMITE_ACTIVE,
2824 EL_DYNABOMB_PLAYER_1_ACTIVE,
2825 EL_DYNABOMB_PLAYER_2_ACTIVE,
2826 EL_DYNABOMB_PLAYER_3_ACTIVE,
2827 EL_DYNABOMB_PLAYER_4_ACTIVE,
2828 EL_DYNABOMB_INCREASE_NUMBER,
2829 EL_DYNABOMB_INCREASE_SIZE,
2830 EL_DYNABOMB_INCREASE_POWER,
2831 EL_SP_DISK_RED_ACTIVE,
2839 /* elements that can explode only by explosion */
2845 static int ep_gravity_reachable[] =
2851 EL_INVISIBLE_SAND_ACTIVE,
2856 EL_SP_PORT_HORIZONTAL,
2857 EL_SP_PORT_VERTICAL,
2859 EL_SP_GRAVITY_PORT_LEFT,
2860 EL_SP_GRAVITY_PORT_RIGHT,
2861 EL_SP_GRAVITY_PORT_UP,
2862 EL_SP_GRAVITY_PORT_DOWN,
2863 EL_SP_GRAVITY_ON_PORT_LEFT,
2864 EL_SP_GRAVITY_ON_PORT_RIGHT,
2865 EL_SP_GRAVITY_ON_PORT_UP,
2866 EL_SP_GRAVITY_ON_PORT_DOWN,
2867 EL_SP_GRAVITY_OFF_PORT_LEFT,
2868 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2869 EL_SP_GRAVITY_OFF_PORT_UP,
2870 EL_SP_GRAVITY_OFF_PORT_DOWN,
2876 static int ep_player[] =
2883 EL_SOKOBAN_FIELD_PLAYER,
2889 static int ep_can_pass_magic_wall[] =
2903 static int ep_can_pass_dc_magic_wall[] =
2919 static int ep_switchable[] =
2923 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2924 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2925 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2926 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2927 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2928 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2929 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2930 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2931 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2932 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2933 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2934 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2935 EL_SWITCHGATE_SWITCH_UP,
2936 EL_SWITCHGATE_SWITCH_DOWN,
2937 EL_DC_SWITCHGATE_SWITCH_UP,
2938 EL_DC_SWITCHGATE_SWITCH_DOWN,
2940 EL_LIGHT_SWITCH_ACTIVE,
2942 EL_DC_TIMEGATE_SWITCH,
2943 EL_BALLOON_SWITCH_LEFT,
2944 EL_BALLOON_SWITCH_RIGHT,
2945 EL_BALLOON_SWITCH_UP,
2946 EL_BALLOON_SWITCH_DOWN,
2947 EL_BALLOON_SWITCH_ANY,
2948 EL_BALLOON_SWITCH_NONE,
2951 EL_EMC_MAGIC_BALL_SWITCH,
2952 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
2957 static int ep_bd_element[] =
2991 static int ep_sp_element[] =
2993 /* should always be valid */
2996 /* standard classic Supaplex elements */
3003 EL_SP_HARDWARE_GRAY,
3011 EL_SP_GRAVITY_PORT_RIGHT,
3012 EL_SP_GRAVITY_PORT_DOWN,
3013 EL_SP_GRAVITY_PORT_LEFT,
3014 EL_SP_GRAVITY_PORT_UP,
3019 EL_SP_PORT_VERTICAL,
3020 EL_SP_PORT_HORIZONTAL,
3026 EL_SP_HARDWARE_BASE_1,
3027 EL_SP_HARDWARE_GREEN,
3028 EL_SP_HARDWARE_BLUE,
3030 EL_SP_HARDWARE_YELLOW,
3031 EL_SP_HARDWARE_BASE_2,
3032 EL_SP_HARDWARE_BASE_3,
3033 EL_SP_HARDWARE_BASE_4,
3034 EL_SP_HARDWARE_BASE_5,
3035 EL_SP_HARDWARE_BASE_6,
3039 /* additional elements that appeared in newer Supaplex levels */
3042 /* additional gravity port elements (not switching, but setting gravity) */
3043 EL_SP_GRAVITY_ON_PORT_LEFT,
3044 EL_SP_GRAVITY_ON_PORT_RIGHT,
3045 EL_SP_GRAVITY_ON_PORT_UP,
3046 EL_SP_GRAVITY_ON_PORT_DOWN,
3047 EL_SP_GRAVITY_OFF_PORT_LEFT,
3048 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3049 EL_SP_GRAVITY_OFF_PORT_UP,
3050 EL_SP_GRAVITY_OFF_PORT_DOWN,
3052 /* more than one Murphy in a level results in an inactive clone */
3055 /* runtime Supaplex elements */
3056 EL_SP_DISK_RED_ACTIVE,
3057 EL_SP_TERMINAL_ACTIVE,
3058 EL_SP_BUGGY_BASE_ACTIVATING,
3059 EL_SP_BUGGY_BASE_ACTIVE,
3066 static int ep_sb_element[] =
3071 EL_SOKOBAN_FIELD_EMPTY,
3072 EL_SOKOBAN_FIELD_FULL,
3073 EL_SOKOBAN_FIELD_PLAYER,
3078 EL_INVISIBLE_STEELWALL,
3083 static int ep_gem[] =
3095 static int ep_food_dark_yamyam[] =
3123 static int ep_food_penguin[] =
3137 static int ep_food_pig[] =
3149 static int ep_historic_wall[] =
3160 EL_GATE_1_GRAY_ACTIVE,
3161 EL_GATE_2_GRAY_ACTIVE,
3162 EL_GATE_3_GRAY_ACTIVE,
3163 EL_GATE_4_GRAY_ACTIVE,
3172 EL_EM_GATE_1_GRAY_ACTIVE,
3173 EL_EM_GATE_2_GRAY_ACTIVE,
3174 EL_EM_GATE_3_GRAY_ACTIVE,
3175 EL_EM_GATE_4_GRAY_ACTIVE,
3182 EL_EXPANDABLE_WALL_HORIZONTAL,
3183 EL_EXPANDABLE_WALL_VERTICAL,
3184 EL_EXPANDABLE_WALL_ANY,
3185 EL_EXPANDABLE_WALL_GROWING,
3186 EL_BD_EXPANDABLE_WALL,
3193 EL_SP_HARDWARE_GRAY,
3194 EL_SP_HARDWARE_GREEN,
3195 EL_SP_HARDWARE_BLUE,
3197 EL_SP_HARDWARE_YELLOW,
3198 EL_SP_HARDWARE_BASE_1,
3199 EL_SP_HARDWARE_BASE_2,
3200 EL_SP_HARDWARE_BASE_3,
3201 EL_SP_HARDWARE_BASE_4,
3202 EL_SP_HARDWARE_BASE_5,
3203 EL_SP_HARDWARE_BASE_6,
3205 EL_SP_TERMINAL_ACTIVE,
3208 EL_INVISIBLE_STEELWALL,
3209 EL_INVISIBLE_STEELWALL_ACTIVE,
3211 EL_INVISIBLE_WALL_ACTIVE,
3212 EL_STEELWALL_SLIPPERY,
3229 static int ep_historic_solid[] =
3233 EL_EXPANDABLE_WALL_HORIZONTAL,
3234 EL_EXPANDABLE_WALL_VERTICAL,
3235 EL_EXPANDABLE_WALL_ANY,
3236 EL_BD_EXPANDABLE_WALL,
3249 EL_QUICKSAND_FILLING,
3250 EL_QUICKSAND_EMPTYING,
3252 EL_MAGIC_WALL_ACTIVE,
3253 EL_MAGIC_WALL_EMPTYING,
3254 EL_MAGIC_WALL_FILLING,
3258 EL_BD_MAGIC_WALL_ACTIVE,
3259 EL_BD_MAGIC_WALL_EMPTYING,
3260 EL_BD_MAGIC_WALL_FULL,
3261 EL_BD_MAGIC_WALL_FILLING,
3262 EL_BD_MAGIC_WALL_DEAD,
3271 EL_SP_TERMINAL_ACTIVE,
3275 EL_INVISIBLE_WALL_ACTIVE,
3276 EL_SWITCHGATE_SWITCH_UP,
3277 EL_SWITCHGATE_SWITCH_DOWN,
3278 EL_DC_SWITCHGATE_SWITCH_UP,
3279 EL_DC_SWITCHGATE_SWITCH_DOWN,
3281 EL_TIMEGATE_SWITCH_ACTIVE,
3282 EL_DC_TIMEGATE_SWITCH,
3283 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3295 /* the following elements are a direct copy of "indestructible" elements,
3296 except "EL_ACID", which is "indestructible", but not "solid"! */
3301 EL_ACID_POOL_TOPLEFT,
3302 EL_ACID_POOL_TOPRIGHT,
3303 EL_ACID_POOL_BOTTOMLEFT,
3304 EL_ACID_POOL_BOTTOM,
3305 EL_ACID_POOL_BOTTOMRIGHT,
3306 EL_SP_HARDWARE_GRAY,
3307 EL_SP_HARDWARE_GREEN,
3308 EL_SP_HARDWARE_BLUE,
3310 EL_SP_HARDWARE_YELLOW,
3311 EL_SP_HARDWARE_BASE_1,
3312 EL_SP_HARDWARE_BASE_2,
3313 EL_SP_HARDWARE_BASE_3,
3314 EL_SP_HARDWARE_BASE_4,
3315 EL_SP_HARDWARE_BASE_5,
3316 EL_SP_HARDWARE_BASE_6,
3317 EL_INVISIBLE_STEELWALL,
3318 EL_INVISIBLE_STEELWALL_ACTIVE,
3319 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3320 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3321 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3322 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3323 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3324 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3325 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3326 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3327 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3328 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3329 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3330 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3332 EL_LIGHT_SWITCH_ACTIVE,
3333 EL_SIGN_EXCLAMATION,
3334 EL_SIGN_RADIOACTIVITY,
3341 EL_SIGN_ENTRY_FORBIDDEN,
3342 EL_SIGN_EMERGENCY_EXIT,
3350 EL_STEEL_EXIT_CLOSED,
3352 EL_DC_STEELWALL_1_LEFT,
3353 EL_DC_STEELWALL_1_RIGHT,
3354 EL_DC_STEELWALL_1_TOP,
3355 EL_DC_STEELWALL_1_BOTTOM,
3356 EL_DC_STEELWALL_1_HORIZONTAL,
3357 EL_DC_STEELWALL_1_VERTICAL,
3358 EL_DC_STEELWALL_1_TOPLEFT,
3359 EL_DC_STEELWALL_1_TOPRIGHT,
3360 EL_DC_STEELWALL_1_BOTTOMLEFT,
3361 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3362 EL_DC_STEELWALL_1_TOPLEFT_2,
3363 EL_DC_STEELWALL_1_TOPRIGHT_2,
3364 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3365 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3366 EL_DC_STEELWALL_2_LEFT,
3367 EL_DC_STEELWALL_2_RIGHT,
3368 EL_DC_STEELWALL_2_TOP,
3369 EL_DC_STEELWALL_2_BOTTOM,
3370 EL_DC_STEELWALL_2_HORIZONTAL,
3371 EL_DC_STEELWALL_2_VERTICAL,
3372 EL_DC_STEELWALL_2_MIDDLE,
3373 EL_DC_STEELWALL_2_SINGLE,
3374 EL_STEELWALL_SLIPPERY,
3388 EL_GATE_1_GRAY_ACTIVE,
3389 EL_GATE_2_GRAY_ACTIVE,
3390 EL_GATE_3_GRAY_ACTIVE,
3391 EL_GATE_4_GRAY_ACTIVE,
3400 EL_EM_GATE_1_GRAY_ACTIVE,
3401 EL_EM_GATE_2_GRAY_ACTIVE,
3402 EL_EM_GATE_3_GRAY_ACTIVE,
3403 EL_EM_GATE_4_GRAY_ACTIVE,
3405 EL_SWITCHGATE_OPENING,
3406 EL_SWITCHGATE_CLOSED,
3407 EL_SWITCHGATE_CLOSING,
3409 EL_TIMEGATE_OPENING,
3411 EL_TIMEGATE_CLOSING,
3415 EL_TUBE_VERTICAL_LEFT,
3416 EL_TUBE_VERTICAL_RIGHT,
3417 EL_TUBE_HORIZONTAL_UP,
3418 EL_TUBE_HORIZONTAL_DOWN,
3427 static int ep_classic_enemy[] =
3444 static int ep_belt[] =
3446 EL_CONVEYOR_BELT_1_LEFT,
3447 EL_CONVEYOR_BELT_1_MIDDLE,
3448 EL_CONVEYOR_BELT_1_RIGHT,
3449 EL_CONVEYOR_BELT_2_LEFT,
3450 EL_CONVEYOR_BELT_2_MIDDLE,
3451 EL_CONVEYOR_BELT_2_RIGHT,
3452 EL_CONVEYOR_BELT_3_LEFT,
3453 EL_CONVEYOR_BELT_3_MIDDLE,
3454 EL_CONVEYOR_BELT_3_RIGHT,
3455 EL_CONVEYOR_BELT_4_LEFT,
3456 EL_CONVEYOR_BELT_4_MIDDLE,
3457 EL_CONVEYOR_BELT_4_RIGHT,
3462 static int ep_belt_active[] =
3464 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3465 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3466 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3467 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3468 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3469 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3470 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3471 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3472 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3473 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3474 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3475 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3480 static int ep_belt_switch[] =
3482 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3483 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3484 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3485 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3486 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3487 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3488 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3489 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3490 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3491 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3492 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3493 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3498 static int ep_tube[] =
3505 EL_TUBE_HORIZONTAL_UP,
3506 EL_TUBE_HORIZONTAL_DOWN,
3508 EL_TUBE_VERTICAL_LEFT,
3509 EL_TUBE_VERTICAL_RIGHT,
3515 static int ep_acid_pool[] =
3517 EL_ACID_POOL_TOPLEFT,
3518 EL_ACID_POOL_TOPRIGHT,
3519 EL_ACID_POOL_BOTTOMLEFT,
3520 EL_ACID_POOL_BOTTOM,
3521 EL_ACID_POOL_BOTTOMRIGHT,
3526 static int ep_keygate[] =
3536 EL_GATE_1_GRAY_ACTIVE,
3537 EL_GATE_2_GRAY_ACTIVE,
3538 EL_GATE_3_GRAY_ACTIVE,
3539 EL_GATE_4_GRAY_ACTIVE,
3548 EL_EM_GATE_1_GRAY_ACTIVE,
3549 EL_EM_GATE_2_GRAY_ACTIVE,
3550 EL_EM_GATE_3_GRAY_ACTIVE,
3551 EL_EM_GATE_4_GRAY_ACTIVE,
3560 EL_EMC_GATE_5_GRAY_ACTIVE,
3561 EL_EMC_GATE_6_GRAY_ACTIVE,
3562 EL_EMC_GATE_7_GRAY_ACTIVE,
3563 EL_EMC_GATE_8_GRAY_ACTIVE,
3565 EL_DC_GATE_WHITE_GRAY,
3566 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3571 static int ep_amoeboid[] =
3583 static int ep_amoebalive[] =
3594 static int ep_has_editor_content[] =
3616 static int ep_can_turn_each_move[] =
3618 /* !!! do something with this one !!! */
3622 static int ep_can_grow[] =
3636 static int ep_active_bomb[] =
3639 EL_EM_DYNAMITE_ACTIVE,
3640 EL_DYNABOMB_PLAYER_1_ACTIVE,
3641 EL_DYNABOMB_PLAYER_2_ACTIVE,
3642 EL_DYNABOMB_PLAYER_3_ACTIVE,
3643 EL_DYNABOMB_PLAYER_4_ACTIVE,
3644 EL_SP_DISK_RED_ACTIVE,
3649 static int ep_inactive[] =
3659 EL_QUICKSAND_FAST_EMPTY,
3682 EL_GATE_1_GRAY_ACTIVE,
3683 EL_GATE_2_GRAY_ACTIVE,
3684 EL_GATE_3_GRAY_ACTIVE,
3685 EL_GATE_4_GRAY_ACTIVE,
3694 EL_EM_GATE_1_GRAY_ACTIVE,
3695 EL_EM_GATE_2_GRAY_ACTIVE,
3696 EL_EM_GATE_3_GRAY_ACTIVE,
3697 EL_EM_GATE_4_GRAY_ACTIVE,
3706 EL_EMC_GATE_5_GRAY_ACTIVE,
3707 EL_EMC_GATE_6_GRAY_ACTIVE,
3708 EL_EMC_GATE_7_GRAY_ACTIVE,
3709 EL_EMC_GATE_8_GRAY_ACTIVE,
3711 EL_DC_GATE_WHITE_GRAY,
3712 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3713 EL_DC_GATE_FAKE_GRAY,
3716 EL_INVISIBLE_STEELWALL,
3724 EL_WALL_EMERALD_YELLOW,
3725 EL_DYNABOMB_INCREASE_NUMBER,
3726 EL_DYNABOMB_INCREASE_SIZE,
3727 EL_DYNABOMB_INCREASE_POWER,
3731 EL_SOKOBAN_FIELD_EMPTY,
3732 EL_SOKOBAN_FIELD_FULL,
3733 EL_WALL_EMERALD_RED,
3734 EL_WALL_EMERALD_PURPLE,
3735 EL_ACID_POOL_TOPLEFT,
3736 EL_ACID_POOL_TOPRIGHT,
3737 EL_ACID_POOL_BOTTOMLEFT,
3738 EL_ACID_POOL_BOTTOM,
3739 EL_ACID_POOL_BOTTOMRIGHT,
3743 EL_BD_MAGIC_WALL_DEAD,
3745 EL_DC_MAGIC_WALL_DEAD,
3746 EL_AMOEBA_TO_DIAMOND,
3754 EL_SP_GRAVITY_PORT_RIGHT,
3755 EL_SP_GRAVITY_PORT_DOWN,
3756 EL_SP_GRAVITY_PORT_LEFT,
3757 EL_SP_GRAVITY_PORT_UP,
3758 EL_SP_PORT_HORIZONTAL,
3759 EL_SP_PORT_VERTICAL,
3770 EL_SP_HARDWARE_GRAY,
3771 EL_SP_HARDWARE_GREEN,
3772 EL_SP_HARDWARE_BLUE,
3774 EL_SP_HARDWARE_YELLOW,
3775 EL_SP_HARDWARE_BASE_1,
3776 EL_SP_HARDWARE_BASE_2,
3777 EL_SP_HARDWARE_BASE_3,
3778 EL_SP_HARDWARE_BASE_4,
3779 EL_SP_HARDWARE_BASE_5,
3780 EL_SP_HARDWARE_BASE_6,
3781 EL_SP_GRAVITY_ON_PORT_LEFT,
3782 EL_SP_GRAVITY_ON_PORT_RIGHT,
3783 EL_SP_GRAVITY_ON_PORT_UP,
3784 EL_SP_GRAVITY_ON_PORT_DOWN,
3785 EL_SP_GRAVITY_OFF_PORT_LEFT,
3786 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3787 EL_SP_GRAVITY_OFF_PORT_UP,
3788 EL_SP_GRAVITY_OFF_PORT_DOWN,
3789 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3790 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3791 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3792 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3793 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3794 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3795 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3796 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3797 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3798 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3799 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3800 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3801 EL_SIGN_EXCLAMATION,
3802 EL_SIGN_RADIOACTIVITY,
3809 EL_SIGN_ENTRY_FORBIDDEN,
3810 EL_SIGN_EMERGENCY_EXIT,
3818 EL_DC_STEELWALL_1_LEFT,
3819 EL_DC_STEELWALL_1_RIGHT,
3820 EL_DC_STEELWALL_1_TOP,
3821 EL_DC_STEELWALL_1_BOTTOM,
3822 EL_DC_STEELWALL_1_HORIZONTAL,
3823 EL_DC_STEELWALL_1_VERTICAL,
3824 EL_DC_STEELWALL_1_TOPLEFT,
3825 EL_DC_STEELWALL_1_TOPRIGHT,
3826 EL_DC_STEELWALL_1_BOTTOMLEFT,
3827 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3828 EL_DC_STEELWALL_1_TOPLEFT_2,
3829 EL_DC_STEELWALL_1_TOPRIGHT_2,
3830 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3831 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3832 EL_DC_STEELWALL_2_LEFT,
3833 EL_DC_STEELWALL_2_RIGHT,
3834 EL_DC_STEELWALL_2_TOP,
3835 EL_DC_STEELWALL_2_BOTTOM,
3836 EL_DC_STEELWALL_2_HORIZONTAL,
3837 EL_DC_STEELWALL_2_VERTICAL,
3838 EL_DC_STEELWALL_2_MIDDLE,
3839 EL_DC_STEELWALL_2_SINGLE,
3840 EL_STEELWALL_SLIPPERY,
3845 EL_EMC_WALL_SLIPPERY_1,
3846 EL_EMC_WALL_SLIPPERY_2,
3847 EL_EMC_WALL_SLIPPERY_3,
3848 EL_EMC_WALL_SLIPPERY_4,
3869 static int ep_em_slippery_wall[] =
3874 static int ep_gfx_crumbled[] =
3885 static int ep_editor_cascade_active[] =
3887 EL_INTERNAL_CASCADE_BD_ACTIVE,
3888 EL_INTERNAL_CASCADE_EM_ACTIVE,
3889 EL_INTERNAL_CASCADE_EMC_ACTIVE,
3890 EL_INTERNAL_CASCADE_RND_ACTIVE,
3891 EL_INTERNAL_CASCADE_SB_ACTIVE,
3892 EL_INTERNAL_CASCADE_SP_ACTIVE,
3893 EL_INTERNAL_CASCADE_DC_ACTIVE,
3894 EL_INTERNAL_CASCADE_DX_ACTIVE,
3895 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
3896 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
3897 EL_INTERNAL_CASCADE_CE_ACTIVE,
3898 EL_INTERNAL_CASCADE_GE_ACTIVE,
3899 EL_INTERNAL_CASCADE_REF_ACTIVE,
3900 EL_INTERNAL_CASCADE_USER_ACTIVE,
3901 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
3906 static int ep_editor_cascade_inactive[] =
3908 EL_INTERNAL_CASCADE_BD,
3909 EL_INTERNAL_CASCADE_EM,
3910 EL_INTERNAL_CASCADE_EMC,
3911 EL_INTERNAL_CASCADE_RND,
3912 EL_INTERNAL_CASCADE_SB,
3913 EL_INTERNAL_CASCADE_SP,
3914 EL_INTERNAL_CASCADE_DC,
3915 EL_INTERNAL_CASCADE_DX,
3916 EL_INTERNAL_CASCADE_CHARS,
3917 EL_INTERNAL_CASCADE_STEEL_CHARS,
3918 EL_INTERNAL_CASCADE_CE,
3919 EL_INTERNAL_CASCADE_GE,
3920 EL_INTERNAL_CASCADE_REF,
3921 EL_INTERNAL_CASCADE_USER,
3922 EL_INTERNAL_CASCADE_DYNAMIC,
3927 static int ep_obsolete[] =
3931 EL_EM_KEY_1_FILE_OBSOLETE,
3932 EL_EM_KEY_2_FILE_OBSOLETE,
3933 EL_EM_KEY_3_FILE_OBSOLETE,
3934 EL_EM_KEY_4_FILE_OBSOLETE,
3935 EL_ENVELOPE_OBSOLETE,
3944 } element_properties[] =
3946 { ep_diggable, EP_DIGGABLE },
3947 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
3948 { ep_dont_run_into, EP_DONT_RUN_INTO },
3949 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
3950 { ep_dont_touch, EP_DONT_TOUCH },
3951 { ep_indestructible, EP_INDESTRUCTIBLE },
3952 { ep_slippery, EP_SLIPPERY },
3953 { ep_can_change, EP_CAN_CHANGE },
3954 { ep_can_move, EP_CAN_MOVE },
3955 { ep_can_fall, EP_CAN_FALL },
3956 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
3957 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
3958 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
3959 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
3960 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
3961 { ep_explodes_impact, EP_EXPLODES_IMPACT },
3962 { ep_walkable_over, EP_WALKABLE_OVER },
3963 { ep_walkable_inside, EP_WALKABLE_INSIDE },
3964 { ep_walkable_under, EP_WALKABLE_UNDER },
3965 { ep_passable_over, EP_PASSABLE_OVER },
3966 { ep_passable_inside, EP_PASSABLE_INSIDE },
3967 { ep_passable_under, EP_PASSABLE_UNDER },
3968 { ep_droppable, EP_DROPPABLE },
3969 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
3970 { ep_pushable, EP_PUSHABLE },
3971 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
3972 { ep_protected, EP_PROTECTED },
3973 { ep_throwable, EP_THROWABLE },
3974 { ep_can_explode, EP_CAN_EXPLODE },
3975 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
3977 { ep_player, EP_PLAYER },
3978 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
3979 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
3980 { ep_switchable, EP_SWITCHABLE },
3981 { ep_bd_element, EP_BD_ELEMENT },
3982 { ep_sp_element, EP_SP_ELEMENT },
3983 { ep_sb_element, EP_SB_ELEMENT },
3985 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
3986 { ep_food_penguin, EP_FOOD_PENGUIN },
3987 { ep_food_pig, EP_FOOD_PIG },
3988 { ep_historic_wall, EP_HISTORIC_WALL },
3989 { ep_historic_solid, EP_HISTORIC_SOLID },
3990 { ep_classic_enemy, EP_CLASSIC_ENEMY },
3991 { ep_belt, EP_BELT },
3992 { ep_belt_active, EP_BELT_ACTIVE },
3993 { ep_belt_switch, EP_BELT_SWITCH },
3994 { ep_tube, EP_TUBE },
3995 { ep_acid_pool, EP_ACID_POOL },
3996 { ep_keygate, EP_KEYGATE },
3997 { ep_amoeboid, EP_AMOEBOID },
3998 { ep_amoebalive, EP_AMOEBALIVE },
3999 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4000 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4001 { ep_can_grow, EP_CAN_GROW },
4002 { ep_active_bomb, EP_ACTIVE_BOMB },
4003 { ep_inactive, EP_INACTIVE },
4005 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4007 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4009 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4010 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4012 { ep_obsolete, EP_OBSOLETE },
4019 /* always start with reliable default values (element has no properties) */
4020 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4021 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4022 SET_PROPERTY(i, j, FALSE);
4024 /* set all base element properties from above array definitions */
4025 for (i = 0; element_properties[i].elements != NULL; i++)
4026 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4027 SET_PROPERTY((element_properties[i].elements)[j],
4028 element_properties[i].property, TRUE);
4030 /* copy properties to some elements that are only stored in level file */
4031 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4032 for (j = 0; copy_properties[j][0] != -1; j++)
4033 if (HAS_PROPERTY(copy_properties[j][0], i))
4034 for (k = 1; k <= 4; k++)
4035 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4037 /* set static element properties that are not listed in array definitions */
4038 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4039 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4042 void InitElementPropertiesEngine(int engine_version)
4044 static int no_wall_properties[] =
4047 EP_COLLECTIBLE_ONLY,
4049 EP_DONT_COLLIDE_WITH,
4052 EP_CAN_SMASH_PLAYER,
4053 EP_CAN_SMASH_ENEMIES,
4054 EP_CAN_SMASH_EVERYTHING,
4059 EP_FOOD_DARK_YAMYAM,
4075 /* important: after initialization in InitElementPropertiesStatic(), the
4076 elements are not again initialized to a default value; therefore all
4077 changes have to make sure that they leave the element with a defined
4078 property (which means that conditional property changes must be set to
4079 a reliable default value before) */
4081 /* resolve group elements */
4082 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4083 ResolveGroupElement(EL_GROUP_START + i);
4085 /* set all special, combined or engine dependent element properties */
4086 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4088 /* ---------- INACTIVE ------------------------------------------------- */
4089 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4090 i <= EL_CHAR_END) ||
4091 (i >= EL_STEEL_CHAR_START &&
4092 i <= EL_STEEL_CHAR_END)));
4094 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4095 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4096 IS_WALKABLE_INSIDE(i) ||
4097 IS_WALKABLE_UNDER(i)));
4099 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4100 IS_PASSABLE_INSIDE(i) ||
4101 IS_PASSABLE_UNDER(i)));
4103 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4104 IS_PASSABLE_OVER(i)));
4106 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4107 IS_PASSABLE_INSIDE(i)));
4109 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4110 IS_PASSABLE_UNDER(i)));
4112 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4115 /* ---------- COLLECTIBLE ---------------------------------------------- */
4116 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4120 /* ---------- SNAPPABLE ------------------------------------------------ */
4121 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4122 IS_COLLECTIBLE(i) ||
4126 /* ---------- WALL ----------------------------------------------------- */
4127 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4129 for (j = 0; no_wall_properties[j] != -1; j++)
4130 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4131 i >= EL_FIRST_RUNTIME_UNREAL)
4132 SET_PROPERTY(i, EP_WALL, FALSE);
4134 if (IS_HISTORIC_WALL(i))
4135 SET_PROPERTY(i, EP_WALL, TRUE);
4137 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4138 if (engine_version < VERSION_IDENT(2,2,0,0))
4139 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4141 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4143 !IS_COLLECTIBLE(i)));
4145 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4146 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4147 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4149 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4150 IS_INDESTRUCTIBLE(i)));
4152 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4154 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4155 else if (engine_version < VERSION_IDENT(2,2,0,0))
4156 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4158 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4162 if (IS_CUSTOM_ELEMENT(i))
4164 /* these are additional properties which are initially false when set */
4166 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4168 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4169 if (DONT_COLLIDE_WITH(i))
4170 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4172 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4173 if (CAN_SMASH_EVERYTHING(i))
4174 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4175 if (CAN_SMASH_ENEMIES(i))
4176 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4179 /* ---------- CAN_SMASH ------------------------------------------------ */
4180 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4181 CAN_SMASH_ENEMIES(i) ||
4182 CAN_SMASH_EVERYTHING(i)));
4184 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4185 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4186 EXPLODES_BY_FIRE(i)));
4188 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4189 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4190 EXPLODES_SMASHED(i)));
4192 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4193 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4194 EXPLODES_IMPACT(i)));
4196 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4197 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4199 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4200 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4201 i == EL_BLACK_ORB));
4203 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4204 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4206 IS_CUSTOM_ELEMENT(i)));
4208 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4209 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4210 i == EL_SP_ELECTRON));
4212 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4213 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4214 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4215 getMoveIntoAcidProperty(&level, i));
4217 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4218 if (MAYBE_DONT_COLLIDE_WITH(i))
4219 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4220 getDontCollideWithProperty(&level, i));
4222 /* ---------- SP_PORT -------------------------------------------------- */
4223 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4224 IS_PASSABLE_INSIDE(i)));
4226 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4227 for (j = 0; j < level.num_android_clone_elements; j++)
4228 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4230 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4232 /* ---------- CAN_CHANGE ----------------------------------------------- */
4233 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4234 for (j = 0; j < element_info[i].num_change_pages; j++)
4235 if (element_info[i].change_page[j].can_change)
4236 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4238 /* ---------- HAS_ACTION ----------------------------------------------- */
4239 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4240 for (j = 0; j < element_info[i].num_change_pages; j++)
4241 if (element_info[i].change_page[j].has_action)
4242 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4244 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4245 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4248 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4250 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4251 element_info[i].crumbled[ACTION_DEFAULT] !=
4252 element_info[i].graphic[ACTION_DEFAULT]);
4254 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
4255 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4256 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
4259 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4260 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4261 IS_EDITOR_CASCADE_INACTIVE(i)));
4264 /* dynamically adjust element properties according to game engine version */
4266 static int ep_em_slippery_wall[] =
4271 EL_EXPANDABLE_WALL_HORIZONTAL,
4272 EL_EXPANDABLE_WALL_VERTICAL,
4273 EL_EXPANDABLE_WALL_ANY,
4274 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4275 EL_EXPANDABLE_STEELWALL_VERTICAL,
4276 EL_EXPANDABLE_STEELWALL_ANY,
4277 EL_EXPANDABLE_STEELWALL_GROWING,
4281 /* special EM style gems behaviour */
4282 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4283 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4284 level.em_slippery_gems);
4286 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4287 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4288 (level.em_slippery_gems &&
4289 engine_version > VERSION_IDENT(2,0,1,0)));
4292 /* this is needed because some graphics depend on element properties */
4293 if (game_status == GAME_MODE_PLAYING)
4294 InitElementGraphicInfo();
4297 void InitElementPropertiesAfterLoading(int engine_version)
4301 /* set some other uninitialized values of custom elements in older levels */
4302 if (engine_version < VERSION_IDENT(3,1,0,0))
4304 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4306 int element = EL_CUSTOM_START + i;
4308 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4310 element_info[element].explosion_delay = 17;
4311 element_info[element].ignition_delay = 8;
4316 static void InitGlobal()
4320 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4322 /* check if element_name_info entry defined for each element in "main.h" */
4323 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4324 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4326 element_info[i].token_name = element_name_info[i].token_name;
4327 element_info[i].class_name = element_name_info[i].class_name;
4328 element_info[i].editor_description=element_name_info[i].editor_description;
4331 printf("%04d: %s\n", i, element_name_info[i].token_name);
4335 global.autoplay_leveldir = NULL;
4336 global.convert_leveldir = NULL;
4338 global.frames_per_second = 0;
4339 global.fps_slowdown = FALSE;
4340 global.fps_slowdown_factor = 1;
4343 void Execute_Command(char *command)
4347 if (strEqual(command, "print graphicsinfo.conf"))
4349 printf("# You can configure additional/alternative image files here.\n");
4350 printf("# (The entries below are default and therefore commented out.)\n");
4352 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4354 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4357 for (i = 0; image_config[i].token != NULL; i++)
4358 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
4359 image_config[i].value));
4363 else if (strEqual(command, "print soundsinfo.conf"))
4365 printf("# You can configure additional/alternative sound files here.\n");
4366 printf("# (The entries below are default and therefore commented out.)\n");
4368 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4370 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4373 for (i = 0; sound_config[i].token != NULL; i++)
4374 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4375 sound_config[i].value));
4379 else if (strEqual(command, "print musicinfo.conf"))
4381 printf("# You can configure additional/alternative music files here.\n");
4382 printf("# (The entries below are default and therefore commented out.)\n");
4384 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4386 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4389 for (i = 0; music_config[i].token != NULL; i++)
4390 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
4391 music_config[i].value));
4395 else if (strEqual(command, "print editorsetup.conf"))
4397 printf("# You can configure your personal editor element list here.\n");
4398 printf("# (The entries below are default and therefore commented out.)\n");
4401 /* this is needed to be able to check element list for cascade elements */
4402 InitElementPropertiesStatic();
4403 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4405 PrintEditorElementList();
4409 else if (strEqual(command, "print helpanim.conf"))
4411 printf("# You can configure different element help animations here.\n");
4412 printf("# (The entries below are default and therefore commented out.)\n");
4415 for (i = 0; helpanim_config[i].token != NULL; i++)
4417 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4418 helpanim_config[i].value));
4420 if (strEqual(helpanim_config[i].token, "end"))
4426 else if (strEqual(command, "print helptext.conf"))
4428 printf("# You can configure different element help text here.\n");
4429 printf("# (The entries below are default and therefore commented out.)\n");
4432 for (i = 0; helptext_config[i].token != NULL; i++)
4433 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4434 helptext_config[i].value));
4438 else if (strncmp(command, "dump level ", 11) == 0)
4440 char *filename = &command[11];
4442 if (!fileExists(filename))
4443 Error(ERR_EXIT, "cannot open file '%s'", filename);
4445 LoadLevelFromFilename(&level, filename);
4450 else if (strncmp(command, "dump tape ", 10) == 0)
4452 char *filename = &command[10];
4454 if (!fileExists(filename))
4455 Error(ERR_EXIT, "cannot open file '%s'", filename);
4457 LoadTapeFromFilename(filename);
4462 else if (strncmp(command, "autoplay ", 9) == 0)
4464 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
4466 while (*str_ptr != '\0') /* continue parsing string */
4468 /* cut leading whitespace from string, replace it by string terminator */
4469 while (*str_ptr == ' ' || *str_ptr == '\t')
4472 if (*str_ptr == '\0') /* end of string reached */
4475 if (global.autoplay_leveldir == NULL) /* read level set string */
4477 global.autoplay_leveldir = str_ptr;
4478 global.autoplay_all = TRUE; /* default: play all tapes */
4480 for (i = 0; i < MAX_TAPES_PER_SET; i++)
4481 global.autoplay_level[i] = FALSE;
4483 else /* read level number string */
4485 int level_nr = atoi(str_ptr); /* get level_nr value */
4487 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
4488 global.autoplay_level[level_nr] = TRUE;
4490 global.autoplay_all = FALSE;
4493 /* advance string pointer to the next whitespace (or end of string) */
4494 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
4498 else if (strncmp(command, "convert ", 8) == 0)
4500 char *str_copy = getStringCopy(&command[8]);
4501 char *str_ptr = strchr(str_copy, ' ');
4503 global.convert_leveldir = str_copy;
4504 global.convert_level_nr = -1;
4506 if (str_ptr != NULL) /* level number follows */
4508 *str_ptr++ = '\0'; /* terminate leveldir string */
4509 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
4514 #if defined(TARGET_SDL)
4515 else if (strEqual(command, "SDL_ListModes"))
4520 SDL_Init(SDL_INIT_VIDEO);
4522 /* get available fullscreen/hardware modes */
4523 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
4525 /* check if there are any modes available */
4528 printf("No modes available!\n");
4533 /* check if our resolution is restricted */
4534 if (modes == (SDL_Rect **)-1)
4536 printf("All resolutions available.\n");
4540 printf("Available Modes:\n");
4542 for(i = 0; modes[i]; i++)
4543 printf(" %d x %d\n", modes[i]->w, modes[i]->h);
4553 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4557 static void InitSetup()
4559 LoadSetup(); /* global setup info */
4561 /* set some options from setup file */
4563 if (setup.options.verbose)
4564 options.verbose = TRUE;
4567 static void InitGameInfo()
4569 game.restart_level = FALSE;
4572 static void InitPlayerInfo()
4576 /* choose default local player */
4577 local_player = &stored_player[0];
4579 for (i = 0; i < MAX_PLAYERS; i++)
4580 stored_player[i].connected = FALSE;
4582 local_player->connected = TRUE;
4585 static void InitArtworkInfo()
4590 static char *get_string_in_brackets(char *string)
4592 char *string_in_brackets = checked_malloc(strlen(string) + 3);
4594 sprintf(string_in_brackets, "[%s]", string);
4596 return string_in_brackets;
4599 static char *get_level_id_suffix(int id_nr)
4601 char *id_suffix = checked_malloc(1 + 3 + 1);
4603 if (id_nr < 0 || id_nr > 999)
4606 sprintf(id_suffix, ".%03d", id_nr);
4612 static char *get_element_class_token(int element)
4614 char *element_class_name = element_info[element].class_name;
4615 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
4617 sprintf(element_class_token, "[%s]", element_class_name);
4619 return element_class_token;
4622 static char *get_action_class_token(int action)
4624 char *action_class_name = &element_action_info[action].suffix[1];
4625 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
4627 sprintf(action_class_token, "[%s]", action_class_name);
4629 return action_class_token;
4633 static void InitArtworkConfig()
4635 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
4636 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
4637 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
4638 static char *action_id_suffix[NUM_ACTIONS + 1];
4639 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
4640 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
4641 static char *level_id_suffix[MAX_LEVELS + 1];
4642 static char *dummy[1] = { NULL };
4643 static char *ignore_generic_tokens[] =
4649 static char **ignore_image_tokens;
4650 static char **ignore_sound_tokens;
4651 static char **ignore_music_tokens;
4652 int num_ignore_generic_tokens;
4653 int num_ignore_image_tokens;
4654 int num_ignore_sound_tokens;
4655 int num_ignore_music_tokens;
4658 /* dynamically determine list of generic tokens to be ignored */
4659 num_ignore_generic_tokens = 0;
4660 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
4661 num_ignore_generic_tokens++;
4663 /* dynamically determine list of image tokens to be ignored */
4664 num_ignore_image_tokens = num_ignore_generic_tokens;
4665 for (i = 0; image_config_vars[i].token != NULL; i++)
4666 num_ignore_image_tokens++;
4667 ignore_image_tokens =
4668 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
4669 for (i = 0; i < num_ignore_generic_tokens; i++)
4670 ignore_image_tokens[i] = ignore_generic_tokens[i];
4671 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
4672 ignore_image_tokens[num_ignore_generic_tokens + i] =
4673 image_config_vars[i].token;
4674 ignore_image_tokens[num_ignore_image_tokens] = NULL;
4676 /* dynamically determine list of sound tokens to be ignored */
4677 num_ignore_sound_tokens = num_ignore_generic_tokens;
4678 ignore_sound_tokens =
4679 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
4680 for (i = 0; i < num_ignore_generic_tokens; i++)
4681 ignore_sound_tokens[i] = ignore_generic_tokens[i];
4682 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
4684 /* dynamically determine list of music tokens to be ignored */
4685 num_ignore_music_tokens = num_ignore_generic_tokens;
4686 ignore_music_tokens =
4687 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
4688 for (i = 0; i < num_ignore_generic_tokens; i++)
4689 ignore_music_tokens[i] = ignore_generic_tokens[i];
4690 ignore_music_tokens[num_ignore_music_tokens] = NULL;
4692 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4693 image_id_prefix[i] = element_info[i].token_name;
4694 for (i = 0; i < NUM_FONTS; i++)
4695 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
4696 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
4698 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4699 sound_id_prefix[i] = element_info[i].token_name;
4700 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4701 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
4702 get_string_in_brackets(element_info[i].class_name);
4703 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
4705 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
4706 music_id_prefix[i] = music_prefix_info[i].prefix;
4707 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
4709 for (i = 0; i < NUM_ACTIONS; i++)
4710 action_id_suffix[i] = element_action_info[i].suffix;
4711 action_id_suffix[NUM_ACTIONS] = NULL;
4713 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
4714 direction_id_suffix[i] = element_direction_info[i].suffix;
4715 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
4717 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
4718 special_id_suffix[i] = special_suffix_info[i].suffix;
4719 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
4721 for (i = 0; i < MAX_LEVELS; i++)
4722 level_id_suffix[i] = get_level_id_suffix(i);
4723 level_id_suffix[MAX_LEVELS] = NULL;
4725 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
4726 image_id_prefix, action_id_suffix, direction_id_suffix,
4727 special_id_suffix, ignore_image_tokens);
4728 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
4729 sound_id_prefix, action_id_suffix, dummy,
4730 special_id_suffix, ignore_sound_tokens);
4731 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
4732 music_id_prefix, special_id_suffix, level_id_suffix,
4733 dummy, ignore_music_tokens);
4736 static void InitMixer()
4744 char *filename_font_initial = NULL;
4745 Bitmap *bitmap_font_initial = NULL;
4749 /* determine settings for initial font (for displaying startup messages) */
4750 for (i = 0; image_config[i].token != NULL; i++)
4752 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4754 char font_token[128];
4757 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
4758 len_font_token = strlen(font_token);
4760 if (strEqual(image_config[i].token, font_token))
4761 filename_font_initial = image_config[i].value;
4762 else if (strlen(image_config[i].token) > len_font_token &&
4763 strncmp(image_config[i].token, font_token, len_font_token) == 0)
4765 if (strEqual(&image_config[i].token[len_font_token], ".x"))
4766 font_initial[j].src_x = atoi(image_config[i].value);
4767 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
4768 font_initial[j].src_y = atoi(image_config[i].value);
4769 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
4770 font_initial[j].width = atoi(image_config[i].value);
4771 else if (strEqual(&image_config[i].token[len_font_token],".height"))
4772 font_initial[j].height = atoi(image_config[i].value);
4777 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4779 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
4780 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
4783 if (filename_font_initial == NULL) /* should not happen */
4784 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
4786 /* create additional image buffers for double-buffering and cross-fading */
4787 bitmap_db_cross = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
4788 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
4789 bitmap_db_panel = CreateBitmap(DXSIZE, DYSIZE, DEFAULT_DEPTH);
4790 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
4792 /* initialize screen properties */
4793 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
4794 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
4796 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
4797 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
4798 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
4800 bitmap_font_initial = LoadCustomImage(filename_font_initial);
4802 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4803 font_initial[j].bitmap = bitmap_font_initial;
4805 InitFontGraphicInfo();
4807 font_height = getFontHeight(FC_RED);
4810 DrawInitText(getWindowTitleString(), 20, FC_YELLOW);
4812 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
4814 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
4815 DrawInitText(PROGRAM_WEBSITE_STRING, WIN_YSIZE - 20 - font_height, FC_RED);
4817 DrawInitText("Loading graphics", 120, FC_GREEN);
4820 void RedrawBackground()
4822 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
4823 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
4825 redraw_mask = REDRAW_ALL;
4828 void InitGfxBackground()
4832 fieldbuffer = bitmap_db_field;
4833 SetDrawtoField(DRAW_BACKBUFFER);
4837 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
4838 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
4840 for (x = 0; x < MAX_BUF_XSIZE; x++)
4841 for (y = 0; y < MAX_BUF_YSIZE; y++)
4844 redraw_mask = REDRAW_ALL;
4847 static void InitLevelInfo()
4849 LoadLevelInfo(); /* global level info */
4850 LoadLevelSetup_LastSeries(); /* last played series info */
4851 LoadLevelSetup_SeriesInfo(); /* last played level info */
4854 void InitLevelArtworkInfo()
4856 LoadLevelArtworkInfo();
4859 static void InitImages()
4861 setLevelArtworkDir(artwork.gfx_first);
4864 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
4865 leveldir_current->identifier,
4866 artwork.gfx_current_identifier,
4867 artwork.gfx_current->identifier,
4868 leveldir_current->graphics_set,
4869 leveldir_current->graphics_path);
4872 ReloadCustomImages();
4874 LoadCustomElementDescriptions();
4875 LoadSpecialMenuDesignSettings();
4877 ReinitializeGraphics();
4880 static void InitSound(char *identifier)
4882 if (identifier == NULL)
4883 identifier = artwork.snd_current->identifier;
4885 /* set artwork path to send it to the sound server process */
4886 setLevelArtworkDir(artwork.snd_first);
4888 InitReloadCustomSounds(identifier);
4889 ReinitializeSounds();
4892 static void InitMusic(char *identifier)
4894 if (identifier == NULL)
4895 identifier = artwork.mus_current->identifier;
4897 /* set artwork path to send it to the sound server process */
4898 setLevelArtworkDir(artwork.mus_first);
4900 InitReloadCustomMusic(identifier);
4901 ReinitializeMusic();
4904 void InitNetworkServer()
4906 #if defined(NETWORK_AVALIABLE)
4910 if (!options.network)
4913 #if defined(NETWORK_AVALIABLE)
4914 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
4916 if (!ConnectToServer(options.server_host, options.server_port))
4917 Error(ERR_EXIT, "cannot connect to network game server");
4919 SendToServer_PlayerName(setup.player_name);
4920 SendToServer_ProtocolVersion();
4923 SendToServer_NrWanted(nr_wanted);
4927 static char *getNewArtworkIdentifier(int type)
4929 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
4930 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
4931 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
4932 static boolean initialized[3] = { FALSE, FALSE, FALSE };
4933 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
4934 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
4935 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
4936 char *leveldir_identifier = leveldir_current->identifier;
4938 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
4939 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
4941 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
4943 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
4944 char *artwork_current_identifier;
4945 char *artwork_new_identifier = NULL; /* default: nothing has changed */
4947 /* leveldir_current may be invalid (level group, parent link) */
4948 if (!validLevelSeries(leveldir_current))
4951 /* 1st step: determine artwork set to be activated in descending order:
4952 --------------------------------------------------------------------
4953 1. setup artwork (when configured to override everything else)
4954 2. artwork set configured in "levelinfo.conf" of current level set
4955 (artwork in level directory will have priority when loading later)
4956 3. artwork in level directory (stored in artwork sub-directory)
4957 4. setup artwork (currently configured in setup menu) */
4959 if (setup_override_artwork)
4960 artwork_current_identifier = setup_artwork_set;
4961 else if (leveldir_artwork_set != NULL)
4962 artwork_current_identifier = leveldir_artwork_set;
4963 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
4964 artwork_current_identifier = leveldir_identifier;
4966 artwork_current_identifier = setup_artwork_set;
4969 /* 2nd step: check if it is really needed to reload artwork set
4970 ------------------------------------------------------------ */
4973 if (type == ARTWORK_TYPE_GRAPHICS)
4974 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
4975 artwork_new_identifier,
4976 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4977 artwork_current_identifier,
4978 leveldir_current->graphics_set,
4979 leveldir_current->identifier);
4982 /* ---------- reload if level set and also artwork set has changed ------- */
4983 if (leveldir_current_identifier[type] != leveldir_identifier &&
4984 (last_has_level_artwork_set[type] || has_level_artwork_set))
4985 artwork_new_identifier = artwork_current_identifier;
4987 leveldir_current_identifier[type] = leveldir_identifier;
4988 last_has_level_artwork_set[type] = has_level_artwork_set;
4991 if (type == ARTWORK_TYPE_GRAPHICS)
4992 printf("::: 1: '%s'\n", artwork_new_identifier);
4995 /* ---------- reload if "override artwork" setting has changed ----------- */
4996 if (last_override_level_artwork[type] != setup_override_artwork)
4997 artwork_new_identifier = artwork_current_identifier;
4999 last_override_level_artwork[type] = setup_override_artwork;
5002 if (type == ARTWORK_TYPE_GRAPHICS)
5003 printf("::: 2: '%s'\n", artwork_new_identifier);
5006 /* ---------- reload if current artwork identifier has changed ----------- */
5007 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5008 artwork_current_identifier))
5009 artwork_new_identifier = artwork_current_identifier;
5011 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5014 if (type == ARTWORK_TYPE_GRAPHICS)
5015 printf("::: 3: '%s'\n", artwork_new_identifier);
5018 /* ---------- do not reload directly after starting ---------------------- */
5019 if (!initialized[type])
5020 artwork_new_identifier = NULL;
5022 initialized[type] = TRUE;
5025 if (type == ARTWORK_TYPE_GRAPHICS)
5026 printf("::: 4: '%s'\n", artwork_new_identifier);
5030 if (type == ARTWORK_TYPE_GRAPHICS)
5031 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
5032 artwork.gfx_current_identifier, artwork_current_identifier,
5033 artwork.gfx_current->identifier, leveldir_current->graphics_set,
5034 artwork_new_identifier);
5037 return artwork_new_identifier;
5040 void ReloadCustomArtwork(int force_reload)
5042 char *gfx_new_identifier;
5043 char *snd_new_identifier;
5044 char *mus_new_identifier;
5045 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5046 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5047 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5048 boolean redraw_screen = FALSE;
5050 force_reload_gfx |= AdjustGraphicsForEMC();
5052 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5053 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5054 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5056 if (gfx_new_identifier != NULL || force_reload_gfx)
5059 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5060 artwork.gfx_current_identifier,
5062 artwork.gfx_current->identifier,
5063 leveldir_current->graphics_set);
5066 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
5070 redraw_screen = TRUE;
5073 if (snd_new_identifier != NULL || force_reload_snd)
5075 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
5077 InitSound(snd_new_identifier);
5079 redraw_screen = TRUE;
5082 if (mus_new_identifier != NULL || force_reload_mus)
5084 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
5086 InitMusic(mus_new_identifier);
5088 redraw_screen = TRUE;
5095 /* force redraw of (open or closed) door graphics */
5096 SetDoorState(DOOR_OPEN_ALL);
5097 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5101 void KeyboardAutoRepeatOffUnlessAutoplay()
5103 if (global.autoplay_leveldir == NULL)
5104 KeyboardAutoRepeatOff();
5108 /* ========================================================================= */
5110 /* ========================================================================= */
5114 InitGlobal(); /* initialize some global variables */
5116 if (options.execute_command)
5117 Execute_Command(options.execute_command);
5119 if (options.serveronly)
5121 #if defined(PLATFORM_UNIX)
5122 NetworkServer(options.server_port, options.serveronly);
5124 Error(ERR_WARN, "networking only supported in Unix version");
5127 exit(0); /* never reached, server loops forever */
5134 InitArtworkInfo(); /* needed before loading gfx, sound & music */
5135 InitArtworkConfig(); /* needed before forking sound child process */
5140 InitRND(NEW_RANDOMIZE);
5141 InitSimpleRandom(NEW_RANDOMIZE);
5146 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
5148 InitEventFilter(FilterMouseMotionEvents);
5150 InitElementPropertiesStatic();
5151 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5155 // debug_print_timestamp(0, "INIT");
5157 // debug_print_timestamp(0, "TIME InitLevelInfo: ");
5158 InitLevelArtworkInfo();
5159 // debug_print_timestamp(0, "TIME InitLevelArtworkInfo: ");
5161 InitImages(); /* needs to know current level directory */
5162 InitSound(NULL); /* needs to know current level directory */
5163 InitMusic(NULL); /* needs to know current level directory */
5165 InitGfxBackground();
5171 if (global.autoplay_leveldir)
5176 else if (global.convert_leveldir)
5182 game_status = GAME_MODE_MAIN;
5186 InitNetworkServer();
5189 void CloseAllAndExit(int exit_value)
5194 CloseAudio(); /* called after freeing sounds (needed for SDL) */
5202 #if defined(TARGET_SDL)
5203 if (network_server) /* terminate network server */
5204 SDL_KillThread(server_thread);
5207 CloseVideoDisplay();
5208 ClosePlatformDependentStuff();
5210 if (exit_value != 0)
5211 NotifyUserAboutErrorFile();