1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2006 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
14 #include "libgame/libgame.h"
29 #include "conf_e2g.c" /* include auto-generated data structure definitions */
30 #include "conf_esg.c" /* include auto-generated data structure definitions */
31 #include "conf_e2s.c" /* include auto-generated data structure definitions */
32 #include "conf_fnt.c" /* include auto-generated data structure definitions */
33 #include "conf_g2s.c" /* include auto-generated data structure definitions */
34 #include "conf_g2m.c" /* include auto-generated data structure definitions */
37 #define CONFIG_TOKEN_FONT_INITIAL "font.initial"
40 static struct FontBitmapInfo font_initial[NUM_INITIAL_FONTS];
42 static int copy_properties[][5] =
46 EL_BUG_LEFT, EL_BUG_RIGHT,
47 EL_BUG_UP, EL_BUG_DOWN
51 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
52 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
56 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
57 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
61 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
62 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
66 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
67 EL_PACMAN_UP, EL_PACMAN_DOWN
71 EL_YAMYAM_LEFT, EL_YAMYAM_RIGHT,
72 EL_YAMYAM_UP, EL_YAMYAM_DOWN
76 EL_MOLE_LEFT, EL_MOLE_RIGHT,
77 EL_MOLE_UP, EL_MOLE_DOWN
87 FreeLevelEditorGadgets();
96 static boolean gadgets_initialized = FALSE;
98 if (gadgets_initialized)
101 CreateLevelEditorGadgets();
105 CreateScreenGadgets();
107 InitGadgetsSoundCallback(PlaySoundActivating, PlaySoundSelecting);
109 gadgets_initialized = TRUE;
112 inline void InitElementSmallImagesScaledUp(int graphic)
114 CreateImageWithSmallImages(graphic, graphic_info[graphic].scale_up_factor);
117 void InitElementSmallImages()
119 static int special_graphics[] =
121 IMG_EDITOR_ELEMENT_BORDER,
122 IMG_EDITOR_ELEMENT_BORDER_INPUT,
123 IMG_EDITOR_CASCADE_LIST,
124 IMG_EDITOR_CASCADE_LIST_ACTIVE,
127 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
128 int num_property_mappings = getImageListPropertyMappingSize();
131 /* initialize normal images from static configuration */
132 for (i = 0; element_to_graphic[i].element > -1; i++)
133 InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
135 /* initialize special images from static configuration */
136 for (i = 0; element_to_special_graphic[i].element > -1; i++)
137 InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
139 /* initialize images from dynamic configuration (may be elements or other) */
140 for (i = 0; i < num_property_mappings; i++)
141 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
143 /* initialize special images from above list (non-element images) */
144 for (i = 0; special_graphics[i] > -1; i++)
145 InitElementSmallImagesScaledUp(special_graphics[i]);
148 void InitScaledImages()
152 /* scale normal images from static configuration, if not already scaled */
153 for (i = 0; i < NUM_IMAGE_FILES; i++)
154 ScaleImage(i, graphic_info[i].scale_up_factor);
158 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
159 void SetBitmaps_EM(Bitmap **em_bitmap)
161 em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
162 em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].bitmap;
166 static int getFontBitmapID(int font_nr)
170 if (game_status >= GAME_MODE_TITLE_INITIAL &&
171 game_status <= GAME_MODE_PSEUDO_PREVIEW)
172 special = game_status;
173 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
174 special = GFX_SPECIAL_ARG_MAIN;
176 else if (game_status == GAME_MODE_PLAYING)
177 special = GFX_SPECIAL_ARG_DOOR;
181 return font_info[font_nr].special_bitmap_id[special];
186 static int getFontFromToken(char *token)
190 /* !!! OPTIMIZE THIS BY USING HASH !!! */
191 for (i = 0; i < NUM_FONTS; i++)
192 if (strEqual(token, font_info[i].token_name))
195 /* if font not found, use reliable default value */
196 return FONT_INITIAL_1;
199 void InitFontGraphicInfo()
201 static struct FontBitmapInfo *font_bitmap_info = NULL;
202 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
203 int num_property_mappings = getImageListPropertyMappingSize();
204 int num_font_bitmaps = NUM_FONTS;
207 if (graphic_info == NULL) /* still at startup phase */
209 InitFontInfo(font_initial, NUM_INITIAL_FONTS,
210 getFontBitmapID, getFontFromToken);
215 /* ---------- initialize font graphic definitions ---------- */
217 /* always start with reliable default values (normal font graphics) */
218 for (i = 0; i < NUM_FONTS; i++)
219 font_info[i].graphic = IMG_FONT_INITIAL_1;
221 /* initialize normal font/graphic mapping from static configuration */
222 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
224 int font_nr = font_to_graphic[i].font_nr;
225 int special = font_to_graphic[i].special;
226 int graphic = font_to_graphic[i].graphic;
231 font_info[font_nr].graphic = graphic;
234 /* always start with reliable default values (special font graphics) */
235 for (i = 0; i < NUM_FONTS; i++)
237 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
239 font_info[i].special_graphic[j] = font_info[i].graphic;
240 font_info[i].special_bitmap_id[j] = i;
244 /* initialize special font/graphic mapping from static configuration */
245 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
247 int font_nr = font_to_graphic[i].font_nr;
248 int special = font_to_graphic[i].special;
249 int graphic = font_to_graphic[i].graphic;
250 int base_graphic = font2baseimg(font_nr);
252 if (IS_SPECIAL_GFX_ARG(special))
254 boolean base_redefined =
255 getImageListEntryFromImageID(base_graphic)->redefined;
256 boolean special_redefined =
257 getImageListEntryFromImageID(graphic)->redefined;
258 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
260 /* if the base font ("font.title_1", for example) has been redefined,
261 but not the special font ("font.title_1.LEVELS", for example), do not
262 use an existing (in this case considered obsolete) special font
263 anymore, but use the automatically determined default font */
264 /* special case: cloned special fonts must be explicitly redefined,
265 but are not automatically redefined by redefining base font */
266 if (base_redefined && !special_redefined && !special_cloned)
269 font_info[font_nr].special_graphic[special] = graphic;
270 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
275 /* initialize special font/graphic mapping from dynamic configuration */
276 for (i = 0; i < num_property_mappings; i++)
278 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
279 int special = property_mapping[i].ext3_index;
280 int graphic = property_mapping[i].artwork_index;
285 if (IS_SPECIAL_GFX_ARG(special))
287 font_info[font_nr].special_graphic[special] = graphic;
288 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
293 /* correct special font/graphic mapping for cloned fonts for downwards
294 compatibility of PREVIEW fonts -- this is only needed for implicit
295 redefinition of special font by redefined base font, and only if other
296 fonts are cloned from this special font (like in the "Zelda" level set) */
297 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
299 int font_nr = font_to_graphic[i].font_nr;
300 int special = font_to_graphic[i].special;
301 int graphic = font_to_graphic[i].graphic;
303 if (IS_SPECIAL_GFX_ARG(special))
305 boolean special_redefined =
306 getImageListEntryFromImageID(graphic)->redefined;
307 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
309 if (special_cloned && !special_redefined)
313 for (j = 0; font_to_graphic[j].font_nr > -1; j++)
315 int font_nr2 = font_to_graphic[j].font_nr;
316 int special2 = font_to_graphic[j].special;
317 int graphic2 = font_to_graphic[j].graphic;
319 if (IS_SPECIAL_GFX_ARG(special2) &&
320 graphic2 == graphic_info[graphic].clone_from)
322 font_info[font_nr].special_graphic[special] =
323 font_info[font_nr2].special_graphic[special2];
324 font_info[font_nr].special_bitmap_id[special] =
325 font_info[font_nr2].special_bitmap_id[special2];
332 /* reset non-redefined ".active" font graphics if normal font is redefined */
333 /* (this different treatment is needed because normal and active fonts are
334 independently defined ("active" is not a property of font definitions!) */
335 for (i = 0; i < NUM_FONTS; i++)
337 int font_nr_base = i;
338 int font_nr_active = FONT_ACTIVE(font_nr_base);
340 /* check only those fonts with exist as normal and ".active" variant */
341 if (font_nr_base != font_nr_active)
343 int base_graphic = font_info[font_nr_base].graphic;
344 int active_graphic = font_info[font_nr_active].graphic;
345 boolean base_redefined =
346 getImageListEntryFromImageID(base_graphic)->redefined;
347 boolean active_redefined =
348 getImageListEntryFromImageID(active_graphic)->redefined;
350 /* if the base font ("font.menu_1", for example) has been redefined,
351 but not the active font ("font.menu_1.active", for example), do not
352 use an existing (in this case considered obsolete) active font
353 anymore, but use the automatically determined default font */
354 if (base_redefined && !active_redefined)
355 font_info[font_nr_active].graphic = base_graphic;
357 /* now also check each "special" font (which may be the same as above) */
358 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
360 int base_graphic = font_info[font_nr_base].special_graphic[j];
361 int active_graphic = font_info[font_nr_active].special_graphic[j];
362 boolean base_redefined =
363 getImageListEntryFromImageID(base_graphic)->redefined;
364 boolean active_redefined =
365 getImageListEntryFromImageID(active_graphic)->redefined;
367 /* same as above, but check special graphic definitions, for example:
368 redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN" */
369 if (base_redefined && !active_redefined)
371 font_info[font_nr_active].special_graphic[j] =
372 font_info[font_nr_base].special_graphic[j];
373 font_info[font_nr_active].special_bitmap_id[j] =
374 font_info[font_nr_base].special_bitmap_id[j];
380 /* ---------- initialize font bitmap array ---------- */
382 if (font_bitmap_info != NULL)
383 FreeFontInfo(font_bitmap_info);
386 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
388 /* ---------- initialize font bitmap definitions ---------- */
390 for (i = 0; i < NUM_FONTS; i++)
392 if (i < NUM_INITIAL_FONTS)
394 font_bitmap_info[i] = font_initial[i];
398 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
400 int font_bitmap_id = font_info[i].special_bitmap_id[j];
401 int graphic = font_info[i].special_graphic[j];
403 /* set 'graphic_info' for font entries, if uninitialized (guessed) */
404 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
406 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
407 graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
410 /* copy font relevant information from graphics information */
411 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
412 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
413 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
414 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
415 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
417 font_bitmap_info[font_bitmap_id].draw_xoffset =
418 graphic_info[graphic].draw_xoffset;
419 font_bitmap_info[font_bitmap_id].draw_yoffset =
420 graphic_info[graphic].draw_yoffset;
422 font_bitmap_info[font_bitmap_id].num_chars =
423 graphic_info[graphic].anim_frames;
424 font_bitmap_info[font_bitmap_id].num_chars_per_line =
425 graphic_info[graphic].anim_frames_per_line;
429 InitFontInfo(font_bitmap_info, num_font_bitmaps,
430 getFontBitmapID, getFontFromToken);
433 void InitElementGraphicInfo()
435 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
436 int num_property_mappings = getImageListPropertyMappingSize();
439 if (graphic_info == NULL) /* still at startup phase */
442 /* set values to -1 to identify later as "uninitialized" values */
443 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
445 for (act = 0; act < NUM_ACTIONS; act++)
447 element_info[i].graphic[act] = -1;
448 element_info[i].crumbled[act] = -1;
450 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
452 element_info[i].direction_graphic[act][dir] = -1;
453 element_info[i].direction_crumbled[act][dir] = -1;
458 /* initialize normal element/graphic mapping from static configuration */
459 for (i = 0; element_to_graphic[i].element > -1; i++)
461 int element = element_to_graphic[i].element;
462 int action = element_to_graphic[i].action;
463 int direction = element_to_graphic[i].direction;
464 boolean crumbled = element_to_graphic[i].crumbled;
465 int graphic = element_to_graphic[i].graphic;
466 int base_graphic = el2baseimg(element);
468 if (graphic_info[graphic].bitmap == NULL)
471 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
474 boolean base_redefined =
475 getImageListEntryFromImageID(base_graphic)->redefined;
476 boolean act_dir_redefined =
477 getImageListEntryFromImageID(graphic)->redefined;
479 /* if the base graphic ("emerald", for example) has been redefined,
480 but not the action graphic ("emerald.falling", for example), do not
481 use an existing (in this case considered obsolete) action graphic
482 anymore, but use the automatically determined default graphic */
483 if (base_redefined && !act_dir_redefined)
488 action = ACTION_DEFAULT;
493 element_info[element].direction_crumbled[action][direction] = graphic;
495 element_info[element].crumbled[action] = graphic;
500 element_info[element].direction_graphic[action][direction] = graphic;
502 element_info[element].graphic[action] = graphic;
506 /* initialize normal element/graphic mapping from dynamic configuration */
507 for (i = 0; i < num_property_mappings; i++)
509 int element = property_mapping[i].base_index;
510 int action = property_mapping[i].ext1_index;
511 int direction = property_mapping[i].ext2_index;
512 int special = property_mapping[i].ext3_index;
513 int graphic = property_mapping[i].artwork_index;
514 boolean crumbled = FALSE;
516 if (special == GFX_SPECIAL_ARG_CRUMBLED)
522 if (graphic_info[graphic].bitmap == NULL)
525 if (element >= MAX_NUM_ELEMENTS || special != -1)
529 action = ACTION_DEFAULT;
534 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
535 element_info[element].direction_crumbled[action][dir] = -1;
538 element_info[element].direction_crumbled[action][direction] = graphic;
540 element_info[element].crumbled[action] = graphic;
545 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
546 element_info[element].direction_graphic[action][dir] = -1;
549 element_info[element].direction_graphic[action][direction] = graphic;
551 element_info[element].graphic[action] = graphic;
555 /* now copy all graphics that are defined to be cloned from other graphics */
556 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
558 int graphic = element_info[i].graphic[ACTION_DEFAULT];
559 int crumbled_like, diggable_like;
564 crumbled_like = graphic_info[graphic].crumbled_like;
565 diggable_like = graphic_info[graphic].diggable_like;
567 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
569 for (act = 0; act < NUM_ACTIONS; act++)
570 element_info[i].crumbled[act] =
571 element_info[crumbled_like].crumbled[act];
572 for (act = 0; act < NUM_ACTIONS; act++)
573 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
574 element_info[i].direction_crumbled[act][dir] =
575 element_info[crumbled_like].direction_crumbled[act][dir];
578 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
580 element_info[i].graphic[ACTION_DIGGING] =
581 element_info[diggable_like].graphic[ACTION_DIGGING];
582 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
583 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
584 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
589 /* set hardcoded definitions for some runtime elements without graphic */
590 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
594 /* set hardcoded definitions for some internal elements without graphic */
595 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
597 if (IS_EDITOR_CASCADE_INACTIVE(i))
598 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
599 else if (IS_EDITOR_CASCADE_ACTIVE(i))
600 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
604 /* now set all undefined/invalid graphics to -1 to set to default after it */
605 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
607 for (act = 0; act < NUM_ACTIONS; act++)
611 graphic = element_info[i].graphic[act];
612 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
613 element_info[i].graphic[act] = -1;
615 graphic = element_info[i].crumbled[act];
616 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
617 element_info[i].crumbled[act] = -1;
619 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
621 graphic = element_info[i].direction_graphic[act][dir];
622 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
623 element_info[i].direction_graphic[act][dir] = -1;
625 graphic = element_info[i].direction_crumbled[act][dir];
626 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
627 element_info[i].direction_crumbled[act][dir] = -1;
632 /* adjust graphics with 2nd tile for movement according to direction
633 (do this before correcting '-1' values to minimize calculations) */
634 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
636 for (act = 0; act < NUM_ACTIONS; act++)
638 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
640 int graphic = element_info[i].direction_graphic[act][dir];
641 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
643 if (act == ACTION_FALLING) /* special case */
644 graphic = element_info[i].graphic[act];
647 graphic_info[graphic].double_movement &&
648 graphic_info[graphic].swap_double_tiles != 0)
650 struct GraphicInfo *g = &graphic_info[graphic];
651 int src_x_front = g->src_x;
652 int src_y_front = g->src_y;
653 int src_x_back = g->src_x + g->offset2_x;
654 int src_y_back = g->src_y + g->offset2_y;
655 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
657 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
658 src_y_front < src_y_back);
659 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
660 boolean swap_movement_tiles_autodetected =
661 (!frames_are_ordered_diagonally &&
662 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
663 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
664 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
665 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
668 /* swap frontside and backside graphic tile coordinates, if needed */
669 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
671 /* get current (wrong) backside tile coordinates */
672 getGraphicSourceExt(graphic, 0, &dummy, &src_x_back, &src_y_back,
675 /* set frontside tile coordinates to backside tile coordinates */
676 g->src_x = src_x_back;
677 g->src_y = src_y_back;
679 /* invert tile offset to point to new backside tile coordinates */
683 /* do not swap front and backside tiles again after correction */
684 g->swap_double_tiles = 0;
691 /* now set all '-1' values to element specific default values */
692 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
694 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
695 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
696 int default_direction_graphic[NUM_DIRECTIONS_FULL];
697 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
699 if (default_graphic == -1)
700 default_graphic = IMG_UNKNOWN;
702 if (default_crumbled == -1)
703 default_crumbled = default_graphic;
705 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
706 if (default_crumbled == -1)
707 default_crumbled = IMG_EMPTY;
710 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
712 default_direction_graphic[dir] =
713 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
714 default_direction_crumbled[dir] =
715 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
717 if (default_direction_graphic[dir] == -1)
718 default_direction_graphic[dir] = default_graphic;
720 if (default_direction_crumbled[dir] == -1)
721 default_direction_crumbled[dir] = default_direction_graphic[dir];
723 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
724 if (default_direction_crumbled[dir] == -1)
725 default_direction_crumbled[dir] = default_crumbled;
729 for (act = 0; act < NUM_ACTIONS; act++)
731 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
732 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
733 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
734 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
735 act == ACTION_TURNING_FROM_RIGHT ||
736 act == ACTION_TURNING_FROM_UP ||
737 act == ACTION_TURNING_FROM_DOWN);
739 /* generic default action graphic (defined by "[default]" directive) */
740 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
741 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
742 int default_remove_graphic = IMG_EMPTY;
744 if (act_remove && default_action_graphic != -1)
745 default_remove_graphic = default_action_graphic;
747 /* look for special default action graphic (classic game specific) */
748 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
749 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
750 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
751 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
752 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
753 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
755 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
756 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
757 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
758 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
759 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
760 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
763 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
764 /* !!! make this better !!! */
765 if (i == EL_EMPTY_SPACE)
767 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
768 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
772 if (default_action_graphic == -1)
773 default_action_graphic = default_graphic;
775 if (default_action_crumbled == -1)
776 default_action_crumbled = default_action_graphic;
778 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
779 if (default_action_crumbled == -1)
780 default_action_crumbled = default_crumbled;
783 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
785 /* use action graphic as the default direction graphic, if undefined */
786 int default_action_direction_graphic = element_info[i].graphic[act];
787 int default_action_direction_crumbled = element_info[i].crumbled[act];
789 /* no graphic for current action -- use default direction graphic */
790 if (default_action_direction_graphic == -1)
791 default_action_direction_graphic =
792 (act_remove ? default_remove_graphic :
794 element_info[i].direction_graphic[ACTION_TURNING][dir] :
795 default_action_graphic != default_graphic ?
796 default_action_graphic :
797 default_direction_graphic[dir]);
799 if (element_info[i].direction_graphic[act][dir] == -1)
800 element_info[i].direction_graphic[act][dir] =
801 default_action_direction_graphic;
804 if (default_action_direction_crumbled == -1)
805 default_action_direction_crumbled =
806 element_info[i].direction_graphic[act][dir];
808 if (default_action_direction_crumbled == -1)
809 default_action_direction_crumbled =
810 (act_remove ? default_remove_graphic :
812 element_info[i].direction_crumbled[ACTION_TURNING][dir] :
813 default_action_crumbled != default_crumbled ?
814 default_action_crumbled :
815 default_direction_crumbled[dir]);
818 if (element_info[i].direction_crumbled[act][dir] == -1)
819 element_info[i].direction_crumbled[act][dir] =
820 default_action_direction_crumbled;
823 /* no graphic for this specific action -- use default action graphic */
824 if (element_info[i].graphic[act] == -1)
825 element_info[i].graphic[act] =
826 (act_remove ? default_remove_graphic :
827 act_turning ? element_info[i].graphic[ACTION_TURNING] :
828 default_action_graphic);
830 if (element_info[i].crumbled[act] == -1)
831 element_info[i].crumbled[act] = element_info[i].graphic[act];
833 if (element_info[i].crumbled[act] == -1)
834 element_info[i].crumbled[act] =
835 (act_remove ? default_remove_graphic :
836 act_turning ? element_info[i].crumbled[ACTION_TURNING] :
837 default_action_crumbled);
843 /* !!! THIS ALSO CLEARS SPECIAL FLAGS (AND IS NOT NEEDED ANYWAY) !!! */
844 /* set animation mode to "none" for each graphic with only 1 frame */
845 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
847 for (act = 0; act < NUM_ACTIONS; act++)
849 int graphic = element_info[i].graphic[act];
850 int crumbled = element_info[i].crumbled[act];
852 if (graphic_info[graphic].anim_frames == 1)
853 graphic_info[graphic].anim_mode = ANIM_NONE;
854 if (graphic_info[crumbled].anim_frames == 1)
855 graphic_info[crumbled].anim_mode = ANIM_NONE;
857 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
859 graphic = element_info[i].direction_graphic[act][dir];
860 crumbled = element_info[i].direction_crumbled[act][dir];
862 if (graphic_info[graphic].anim_frames == 1)
863 graphic_info[graphic].anim_mode = ANIM_NONE;
864 if (graphic_info[crumbled].anim_frames == 1)
865 graphic_info[crumbled].anim_mode = ANIM_NONE;
875 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
876 if (element_info[i].graphic[ACTION_DEFAULT] == IMG_UNKNOWN &&
878 Error(ERR_INFO, "warning: no graphic for element '%s' (%d)",
879 element_info[i].token_name, i);
885 void InitElementSpecialGraphicInfo()
887 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
888 int num_property_mappings = getImageListPropertyMappingSize();
891 /* always start with reliable default values */
892 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
893 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
894 element_info[i].special_graphic[j] =
895 element_info[i].graphic[ACTION_DEFAULT];
897 /* initialize special element/graphic mapping from static configuration */
898 for (i = 0; element_to_special_graphic[i].element > -1; i++)
900 int element = element_to_special_graphic[i].element;
901 int special = element_to_special_graphic[i].special;
902 int graphic = element_to_special_graphic[i].graphic;
903 int base_graphic = el2baseimg(element);
904 boolean base_redefined =
905 getImageListEntryFromImageID(base_graphic)->redefined;
906 boolean special_redefined =
907 getImageListEntryFromImageID(graphic)->redefined;
909 /* if the base graphic ("emerald", for example) has been redefined,
910 but not the special graphic ("emerald.EDITOR", for example), do not
911 use an existing (in this case considered obsolete) special graphic
912 anymore, but use the automatically created (down-scaled) graphic */
913 if (base_redefined && !special_redefined)
916 element_info[element].special_graphic[special] = graphic;
919 /* initialize special element/graphic mapping from dynamic configuration */
920 for (i = 0; i < num_property_mappings; i++)
922 int element = property_mapping[i].base_index;
923 int special = property_mapping[i].ext3_index;
924 int graphic = property_mapping[i].artwork_index;
926 if (element >= MAX_NUM_ELEMENTS)
929 if (IS_SPECIAL_GFX_ARG(special))
930 element_info[element].special_graphic[special] = graphic;
933 /* now set all undefined/invalid graphics to default */
934 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
935 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
936 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
937 element_info[i].special_graphic[j] =
938 element_info[i].graphic[ACTION_DEFAULT];
941 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
946 if (type != TYPE_TOKEN)
947 return get_parameter_value(value_raw, suffix, type);
949 if (strEqual(value_raw, ARG_UNDEFINED))
950 return ARG_UNDEFINED_VALUE;
952 /* !!! OPTIMIZE THIS BY USING HASH !!! */
953 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
954 if (strEqual(element_info[i].token_name, value_raw))
957 /* !!! OPTIMIZE THIS BY USING HASH !!! */
958 for (i = 0; image_config[i].token != NULL; i++)
960 int len_config_value = strlen(image_config[i].value);
962 if (!strEqual(&image_config[i].value[len_config_value - 4], ".pcx") &&
963 !strEqual(&image_config[i].value[len_config_value - 4], ".wav") &&
964 !strEqual(image_config[i].value, UNDEFINED_FILENAME))
967 if (strEqual(image_config[i].token, value_raw))
976 static int get_scaled_graphic_width(int graphic)
978 int original_width = getOriginalImageWidthFromImageID(graphic);
979 int scale_up_factor = graphic_info[graphic].scale_up_factor;
981 return original_width * scale_up_factor;
984 static int get_scaled_graphic_height(int graphic)
986 int original_height = getOriginalImageHeightFromImageID(graphic);
987 int scale_up_factor = graphic_info[graphic].scale_up_factor;
989 return original_height * scale_up_factor;
992 static void set_graphic_parameters(int graphic)
994 struct FileInfo *image = getImageListEntryFromImageID(graphic);
995 char **parameter_raw = image->parameter;
996 Bitmap *src_bitmap = getBitmapFromImageID(graphic);
997 int parameter[NUM_GFX_ARGS];
998 int anim_frames_per_row = 1, anim_frames_per_col = 1;
999 int anim_frames_per_line = 1;
1002 /* if fallback to default artwork is done, also use the default parameters */
1003 if (image->fallback_to_default)
1004 parameter_raw = image->default_parameter;
1006 /* get integer values from string parameters */
1007 for (i = 0; i < NUM_GFX_ARGS; i++)
1008 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1009 image_config_suffix[i].token,
1010 image_config_suffix[i].type);
1012 graphic_info[graphic].bitmap = src_bitmap;
1014 /* always start with reliable default values */
1015 graphic_info[graphic].src_image_width = 0;
1016 graphic_info[graphic].src_image_height = 0;
1017 graphic_info[graphic].src_x = 0;
1018 graphic_info[graphic].src_y = 0;
1019 graphic_info[graphic].width = TILEX; /* default for element graphics */
1020 graphic_info[graphic].height = TILEY; /* default for element graphics */
1021 graphic_info[graphic].offset_x = 0; /* one or both of these values ... */
1022 graphic_info[graphic].offset_y = 0; /* ... will be corrected later */
1023 graphic_info[graphic].offset2_x = 0; /* one or both of these values ... */
1024 graphic_info[graphic].offset2_y = 0; /* ... will be corrected later */
1025 graphic_info[graphic].swap_double_tiles = -1; /* auto-detect tile swapping */
1026 graphic_info[graphic].crumbled_like = -1; /* do not use clone element */
1027 graphic_info[graphic].diggable_like = -1; /* do not use clone element */
1028 graphic_info[graphic].border_size = TILEX / 8; /* "CRUMBLED" border size */
1029 graphic_info[graphic].scale_up_factor = 1; /* default: no scaling up */
1030 graphic_info[graphic].clone_from = -1; /* do not use clone graphic */
1031 graphic_info[graphic].anim_delay_fixed = 0;
1032 graphic_info[graphic].anim_delay_random = 0;
1033 graphic_info[graphic].post_delay_fixed = 0;
1034 graphic_info[graphic].post_delay_random = 0;
1035 graphic_info[graphic].fade_delay = -1;
1036 graphic_info[graphic].post_delay = -1;
1037 graphic_info[graphic].auto_delay = -1;
1038 graphic_info[graphic].align = ALIGN_CENTER; /* default for title screens */
1039 graphic_info[graphic].valign = VALIGN_MIDDLE; /* default for title screens */
1040 graphic_info[graphic].sort_priority = 0; /* default for title screens */
1043 /* optional zoom factor for scaling up the image to a larger size */
1044 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1045 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1046 if (graphic_info[graphic].scale_up_factor < 1)
1047 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
1051 if (graphic_info[graphic].use_image_size)
1053 /* set new default bitmap size (with scaling, but without small images) */
1054 graphic_info[graphic].width = get_scaled_graphic_width(graphic);
1055 graphic_info[graphic].height = get_scaled_graphic_height(graphic);
1059 /* optional x and y tile position of animation frame sequence */
1060 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1061 graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
1062 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1063 graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
1065 /* optional x and y pixel position of animation frame sequence */
1066 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1067 graphic_info[graphic].src_x = parameter[GFX_ARG_X];
1068 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1069 graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
1071 /* optional width and height of each animation frame */
1072 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1073 graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
1074 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1075 graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
1078 /* optional zoom factor for scaling up the image to a larger size */
1079 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1080 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1081 if (graphic_info[graphic].scale_up_factor < 1)
1082 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
1087 /* get final bitmap size (with scaling, but without small images) */
1088 int src_image_width = get_scaled_graphic_width(graphic);
1089 int src_image_height = get_scaled_graphic_height(graphic);
1091 anim_frames_per_row = src_image_width / graphic_info[graphic].width;
1092 anim_frames_per_col = src_image_height / graphic_info[graphic].height;
1094 graphic_info[graphic].src_image_width = src_image_width;
1095 graphic_info[graphic].src_image_height = src_image_height;
1098 /* correct x or y offset dependent of vertical or horizontal frame order */
1099 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1101 graphic_info[graphic].offset_y =
1102 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1103 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
1104 anim_frames_per_line = anim_frames_per_col;
1106 else /* frames are ordered horizontally */
1108 graphic_info[graphic].offset_x =
1109 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1110 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
1111 anim_frames_per_line = anim_frames_per_row;
1114 /* optionally, the x and y offset of frames can be specified directly */
1115 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1116 graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
1117 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1118 graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
1120 /* optionally, moving animations may have separate start and end graphics */
1121 graphic_info[graphic].double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1123 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1124 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1126 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1127 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1128 graphic_info[graphic].offset2_y =
1129 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1130 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].height);
1131 else /* frames are ordered horizontally */
1132 graphic_info[graphic].offset2_x =
1133 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1134 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].width);
1136 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1137 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1138 graphic_info[graphic].offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1139 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1140 graphic_info[graphic].offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1142 /* optionally, the second movement tile can be specified as start tile */
1143 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1144 graphic_info[graphic].swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1146 /* automatically determine correct number of frames, if not defined */
1147 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1148 graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
1149 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1150 graphic_info[graphic].anim_frames = anim_frames_per_row;
1151 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1152 graphic_info[graphic].anim_frames = anim_frames_per_col;
1154 graphic_info[graphic].anim_frames = 1;
1156 if (graphic_info[graphic].anim_frames == 0) /* frames must be at least 1 */
1157 graphic_info[graphic].anim_frames = 1;
1159 graphic_info[graphic].anim_frames_per_line =
1160 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1161 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1163 graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
1164 if (graphic_info[graphic].anim_delay == 0) /* delay must be at least 1 */
1165 graphic_info[graphic].anim_delay = 1;
1167 graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
1169 if (graphic_info[graphic].anim_frames == 1)
1170 graphic_info[graphic].anim_mode = ANIM_NONE;
1173 /* automatically determine correct start frame, if not defined */
1174 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1175 graphic_info[graphic].anim_start_frame = 0;
1176 else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
1177 graphic_info[graphic].anim_start_frame =
1178 graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1180 graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
1182 /* animation synchronized with global frame counter, not move position */
1183 graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1185 /* optional element for cloning crumble graphics */
1186 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1187 graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1189 /* optional element for cloning digging graphics */
1190 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1191 graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1193 /* optional border size for "crumbling" diggable graphics */
1194 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1195 graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
1197 /* this is only used for player "boring" and "sleeping" actions */
1198 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1199 graphic_info[graphic].anim_delay_fixed =
1200 parameter[GFX_ARG_ANIM_DELAY_FIXED];
1201 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1202 graphic_info[graphic].anim_delay_random =
1203 parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1204 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1205 graphic_info[graphic].post_delay_fixed =
1206 parameter[GFX_ARG_POST_DELAY_FIXED];
1207 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1208 graphic_info[graphic].post_delay_random =
1209 parameter[GFX_ARG_POST_DELAY_RANDOM];
1211 /* this is only used for toon animations */
1212 graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
1213 graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY];
1215 /* this is only used for drawing font characters */
1216 graphic_info[graphic].draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1217 graphic_info[graphic].draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1219 /* this is only used for drawing envelope graphics */
1220 graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1222 /* optional graphic for cloning all graphics settings */
1223 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1224 graphic_info[graphic].clone_from = parameter[GFX_ARG_CLONE_FROM];
1226 /* optional settings for drawing title screens */
1227 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1228 graphic_info[graphic].fade_delay = parameter[GFX_ARG_FADE_DELAY];
1229 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1230 graphic_info[graphic].post_delay = parameter[GFX_ARG_POST_DELAY];
1231 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1232 graphic_info[graphic].auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1233 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1234 graphic_info[graphic].align = parameter[GFX_ARG_ALIGN];
1235 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1236 graphic_info[graphic].valign = parameter[GFX_ARG_VALIGN];
1237 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1238 graphic_info[graphic].sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1241 static void set_cloned_graphic_parameters(int graphic)
1243 int fallback_graphic = IMG_CHAR_EXCLAM;
1244 int max_num_images = getImageListSize();
1245 int clone_graphic = graphic_info[graphic].clone_from;
1246 int num_references_followed = 1;
1248 while (graphic_info[clone_graphic].clone_from != -1 &&
1249 num_references_followed < max_num_images)
1251 clone_graphic = graphic_info[clone_graphic].clone_from;
1253 num_references_followed++;
1256 if (num_references_followed >= max_num_images)
1258 Error(ERR_INFO_LINE, "-");
1259 Error(ERR_INFO, "warning: error found in config file:");
1260 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1261 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1262 Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1263 Error(ERR_INFO, "custom graphic rejected for this element/action");
1265 if (graphic == fallback_graphic)
1266 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1268 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1269 Error(ERR_INFO_LINE, "-");
1271 graphic_info[graphic] = graphic_info[fallback_graphic];
1275 graphic_info[graphic] = graphic_info[clone_graphic];
1276 graphic_info[graphic].clone_from = clone_graphic;
1280 static void InitGraphicInfo()
1282 int fallback_graphic = IMG_CHAR_EXCLAM;
1283 int num_images = getImageListSize();
1286 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1287 static boolean clipmasks_initialized = FALSE;
1289 XGCValues clip_gc_values;
1290 unsigned long clip_gc_valuemask;
1291 GC copy_clipmask_gc = None;
1294 /* use image size as default values for width and height for these images */
1295 static int full_size_graphics[] =
1300 IMG_BACKGROUND_ENVELOPE_1,
1301 IMG_BACKGROUND_ENVELOPE_2,
1302 IMG_BACKGROUND_ENVELOPE_3,
1303 IMG_BACKGROUND_ENVELOPE_4,
1306 IMG_BACKGROUND_TITLE_INITIAL,
1307 IMG_BACKGROUND_TITLE,
1308 IMG_BACKGROUND_MAIN,
1309 IMG_BACKGROUND_LEVELS,
1310 IMG_BACKGROUND_SCORES,
1311 IMG_BACKGROUND_EDITOR,
1312 IMG_BACKGROUND_INFO,
1313 IMG_BACKGROUND_INFO_ELEMENTS,
1314 IMG_BACKGROUND_INFO_MUSIC,
1315 IMG_BACKGROUND_INFO_CREDITS,
1316 IMG_BACKGROUND_INFO_PROGRAM,
1317 IMG_BACKGROUND_INFO_LEVELSET,
1318 IMG_BACKGROUND_SETUP,
1319 IMG_BACKGROUND_DOOR,
1321 IMG_TITLESCREEN_INITIAL_1,
1322 IMG_TITLESCREEN_INITIAL_2,
1323 IMG_TITLESCREEN_INITIAL_3,
1324 IMG_TITLESCREEN_INITIAL_4,
1325 IMG_TITLESCREEN_INITIAL_5,
1335 checked_free(graphic_info);
1337 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1340 /* initialize "use_image_size" flag with default value */
1341 for (i = 0; i < num_images; i++)
1342 graphic_info[i].use_image_size = FALSE;
1344 /* initialize "use_image_size" flag from static configuration above */
1345 for (i = 0; full_size_graphics[i] != -1; i++)
1346 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1349 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1350 if (clipmasks_initialized)
1352 for (i = 0; i < num_images; i++)
1354 if (graphic_info[i].clip_mask)
1355 XFreePixmap(display, graphic_info[i].clip_mask);
1356 if (graphic_info[i].clip_gc)
1357 XFreeGC(display, graphic_info[i].clip_gc);
1359 graphic_info[i].clip_mask = None;
1360 graphic_info[i].clip_gc = None;
1365 /* first set all graphic paramaters ... */
1366 for (i = 0; i < num_images; i++)
1367 set_graphic_parameters(i);
1369 /* ... then copy these parameters for cloned graphics */
1370 for (i = 0; i < num_images; i++)
1371 if (graphic_info[i].clone_from != -1)
1372 set_cloned_graphic_parameters(i);
1374 for (i = 0; i < num_images; i++)
1379 int first_frame, last_frame;
1380 int src_bitmap_width, src_bitmap_height;
1382 /* now check if no animation frames are outside of the loaded image */
1384 if (graphic_info[i].bitmap == NULL)
1385 continue; /* skip check for optional images that are undefined */
1387 /* get image size (this can differ from the standard element tile size!) */
1388 width = graphic_info[i].width;
1389 height = graphic_info[i].height;
1391 /* get final bitmap size (with scaling, but without small images) */
1392 src_bitmap_width = graphic_info[i].src_image_width;
1393 src_bitmap_height = graphic_info[i].src_image_height;
1395 /* check if first animation frame is inside specified bitmap */
1398 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1401 /* this avoids calculating wrong start position for out-of-bounds frame */
1402 src_x = graphic_info[i].src_x;
1403 src_y = graphic_info[i].src_y;
1406 if (src_x < 0 || src_y < 0 ||
1407 src_x + width > src_bitmap_width ||
1408 src_y + height > src_bitmap_height)
1410 Error(ERR_INFO_LINE, "-");
1411 Error(ERR_INFO, "warning: error found in config file:");
1412 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1413 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1414 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1416 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1417 src_x, src_y, src_bitmap_width, src_bitmap_height);
1418 Error(ERR_INFO, "custom graphic rejected for this element/action");
1420 if (i == fallback_graphic)
1421 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1423 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1424 Error(ERR_INFO_LINE, "-");
1426 graphic_info[i] = graphic_info[fallback_graphic];
1429 /* check if last animation frame is inside specified bitmap */
1431 last_frame = graphic_info[i].anim_frames - 1;
1432 getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1434 if (src_x < 0 || src_y < 0 ||
1435 src_x + width > src_bitmap_width ||
1436 src_y + height > src_bitmap_height)
1438 Error(ERR_INFO_LINE, "-");
1439 Error(ERR_INFO, "warning: error found in config file:");
1440 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1441 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1442 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1444 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1445 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1446 Error(ERR_INFO, "custom graphic rejected for this element/action");
1448 if (i == fallback_graphic)
1449 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1451 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1452 Error(ERR_INFO_LINE, "-");
1454 graphic_info[i] = graphic_info[fallback_graphic];
1457 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1458 /* currently we only need a tile clip mask from the first frame */
1459 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1461 if (copy_clipmask_gc == None)
1463 clip_gc_values.graphics_exposures = False;
1464 clip_gc_valuemask = GCGraphicsExposures;
1465 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
1466 clip_gc_valuemask, &clip_gc_values);
1469 graphic_info[i].clip_mask =
1470 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
1472 src_pixmap = src_bitmap->clip_mask;
1473 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
1474 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
1476 clip_gc_values.graphics_exposures = False;
1477 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
1478 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
1480 graphic_info[i].clip_gc =
1481 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
1485 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1486 if (copy_clipmask_gc)
1487 XFreeGC(display, copy_clipmask_gc);
1489 clipmasks_initialized = TRUE;
1493 static void InitElementSoundInfo()
1495 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1496 int num_property_mappings = getSoundListPropertyMappingSize();
1499 /* set values to -1 to identify later as "uninitialized" values */
1500 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1501 for (act = 0; act < NUM_ACTIONS; act++)
1502 element_info[i].sound[act] = -1;
1504 /* initialize element/sound mapping from static configuration */
1505 for (i = 0; element_to_sound[i].element > -1; i++)
1507 int element = element_to_sound[i].element;
1508 int action = element_to_sound[i].action;
1509 int sound = element_to_sound[i].sound;
1510 boolean is_class = element_to_sound[i].is_class;
1513 action = ACTION_DEFAULT;
1516 element_info[element].sound[action] = sound;
1518 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1519 if (strEqual(element_info[j].class_name,
1520 element_info[element].class_name))
1521 element_info[j].sound[action] = sound;
1524 /* initialize element class/sound mapping from dynamic configuration */
1525 for (i = 0; i < num_property_mappings; i++)
1527 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1528 int action = property_mapping[i].ext1_index;
1529 int sound = property_mapping[i].artwork_index;
1531 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1535 action = ACTION_DEFAULT;
1537 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1538 if (strEqual(element_info[j].class_name,
1539 element_info[element_class].class_name))
1540 element_info[j].sound[action] = sound;
1543 /* initialize element/sound mapping from dynamic configuration */
1544 for (i = 0; i < num_property_mappings; i++)
1546 int element = property_mapping[i].base_index;
1547 int action = property_mapping[i].ext1_index;
1548 int sound = property_mapping[i].artwork_index;
1550 if (element >= MAX_NUM_ELEMENTS)
1554 action = ACTION_DEFAULT;
1556 element_info[element].sound[action] = sound;
1559 /* now set all '-1' values to element specific default values */
1560 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1562 for (act = 0; act < NUM_ACTIONS; act++)
1564 /* generic default action sound (defined by "[default]" directive) */
1565 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1567 /* look for special default action sound (classic game specific) */
1568 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1569 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1570 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1571 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1572 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1573 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1575 /* !!! there's no such thing as a "default action sound" !!! */
1577 /* look for element specific default sound (independent from action) */
1578 if (element_info[i].sound[ACTION_DEFAULT] != -1)
1579 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
1583 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1584 /* !!! make this better !!! */
1585 if (i == EL_EMPTY_SPACE)
1586 default_action_sound = element_info[EL_DEFAULT].sound[act];
1589 /* no sound for this specific action -- use default action sound */
1590 if (element_info[i].sound[act] == -1)
1591 element_info[i].sound[act] = default_action_sound;
1595 /* copy sound settings to some elements that are only stored in level file
1596 in native R'n'D levels, but are used by game engine in native EM levels */
1597 for (i = 0; copy_properties[i][0] != -1; i++)
1598 for (j = 1; j <= 4; j++)
1599 for (act = 0; act < NUM_ACTIONS; act++)
1600 element_info[copy_properties[i][j]].sound[act] =
1601 element_info[copy_properties[i][0]].sound[act];
1604 static void InitGameModeSoundInfo()
1608 /* set values to -1 to identify later as "uninitialized" values */
1609 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1612 /* initialize gamemode/sound mapping from static configuration */
1613 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1615 int gamemode = gamemode_to_sound[i].gamemode;
1616 int sound = gamemode_to_sound[i].sound;
1619 gamemode = GAME_MODE_DEFAULT;
1621 menu.sound[gamemode] = sound;
1624 /* now set all '-1' values to levelset specific default values */
1625 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1626 if (menu.sound[i] == -1)
1627 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1630 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1631 if (menu.sound[i] != -1)
1632 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
1636 static void set_sound_parameters(int sound, char **parameter_raw)
1638 int parameter[NUM_SND_ARGS];
1641 /* get integer values from string parameters */
1642 for (i = 0; i < NUM_SND_ARGS; i++)
1644 get_parameter_value(parameter_raw[i],
1645 sound_config_suffix[i].token,
1646 sound_config_suffix[i].type);
1648 /* explicit loop mode setting in configuration overrides default value */
1649 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1650 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1652 /* sound volume to change the original volume when loading the sound file */
1653 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1655 /* sound priority to give certain sounds a higher or lower priority */
1656 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
1659 static void InitSoundInfo()
1661 int *sound_effect_properties;
1662 int num_sounds = getSoundListSize();
1665 checked_free(sound_info);
1667 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1668 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1670 /* initialize sound effect for all elements to "no sound" */
1671 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1672 for (j = 0; j < NUM_ACTIONS; j++)
1673 element_info[i].sound[j] = SND_UNDEFINED;
1675 for (i = 0; i < num_sounds; i++)
1677 struct FileInfo *sound = getSoundListEntry(i);
1678 int len_effect_text = strlen(sound->token);
1680 sound_effect_properties[i] = ACTION_OTHER;
1681 sound_info[i].loop = FALSE; /* default: play sound only once */
1684 printf("::: sound %d: '%s'\n", i, sound->token);
1687 /* determine all loop sounds and identify certain sound classes */
1689 for (j = 0; element_action_info[j].suffix; j++)
1691 int len_action_text = strlen(element_action_info[j].suffix);
1693 if (len_action_text < len_effect_text &&
1694 strEqual(&sound->token[len_effect_text - len_action_text],
1695 element_action_info[j].suffix))
1697 sound_effect_properties[i] = element_action_info[j].value;
1698 sound_info[i].loop = element_action_info[j].is_loop_sound;
1704 /* associate elements and some selected sound actions */
1706 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1708 if (element_info[j].class_name)
1710 int len_class_text = strlen(element_info[j].class_name);
1712 if (len_class_text + 1 < len_effect_text &&
1713 strncmp(sound->token,
1714 element_info[j].class_name, len_class_text) == 0 &&
1715 sound->token[len_class_text] == '.')
1717 int sound_action_value = sound_effect_properties[i];
1719 element_info[j].sound[sound_action_value] = i;
1724 set_sound_parameters(i, sound->parameter);
1727 free(sound_effect_properties);
1730 static void InitGameModeMusicInfo()
1732 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1733 int num_property_mappings = getMusicListPropertyMappingSize();
1734 int default_levelset_music = -1;
1737 /* set values to -1 to identify later as "uninitialized" values */
1738 for (i = 0; i < MAX_LEVELS; i++)
1739 levelset.music[i] = -1;
1740 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1743 /* initialize gamemode/music mapping from static configuration */
1744 for (i = 0; gamemode_to_music[i].music > -1; i++)
1746 int gamemode = gamemode_to_music[i].gamemode;
1747 int music = gamemode_to_music[i].music;
1750 printf("::: gamemode == %d, music == %d\n", gamemode, music);
1754 gamemode = GAME_MODE_DEFAULT;
1756 menu.music[gamemode] = music;
1759 /* initialize gamemode/music mapping from dynamic configuration */
1760 for (i = 0; i < num_property_mappings; i++)
1762 int prefix = property_mapping[i].base_index;
1763 int gamemode = property_mapping[i].ext1_index;
1764 int level = property_mapping[i].ext2_index;
1765 int music = property_mapping[i].artwork_index;
1768 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
1769 prefix, gamemode, level, music);
1772 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1776 gamemode = GAME_MODE_DEFAULT;
1778 /* level specific music only allowed for in-game music */
1779 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1780 gamemode = GAME_MODE_PLAYING;
1785 default_levelset_music = music;
1788 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1789 levelset.music[level] = music;
1790 if (gamemode != GAME_MODE_PLAYING)
1791 menu.music[gamemode] = music;
1794 /* now set all '-1' values to menu specific default values */
1795 /* (undefined values of "levelset.music[]" might stay at "-1" to
1796 allow dynamic selection of music files from music directory!) */
1797 for (i = 0; i < MAX_LEVELS; i++)
1798 if (levelset.music[i] == -1)
1799 levelset.music[i] = default_levelset_music;
1800 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1801 if (menu.music[i] == -1)
1802 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1805 for (i = 0; i < MAX_LEVELS; i++)
1806 if (levelset.music[i] != -1)
1807 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
1808 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1809 if (menu.music[i] != -1)
1810 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
1814 static void set_music_parameters(int music, char **parameter_raw)
1816 int parameter[NUM_MUS_ARGS];
1819 /* get integer values from string parameters */
1820 for (i = 0; i < NUM_MUS_ARGS; i++)
1822 get_parameter_value(parameter_raw[i],
1823 music_config_suffix[i].token,
1824 music_config_suffix[i].type);
1826 /* explicit loop mode setting in configuration overrides default value */
1827 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1828 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1831 static void InitMusicInfo()
1833 int num_music = getMusicListSize();
1836 checked_free(music_info);
1838 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1840 for (i = 0; i < num_music; i++)
1842 struct FileInfo *music = getMusicListEntry(i);
1843 int len_music_text = strlen(music->token);
1845 music_info[i].loop = TRUE; /* default: play music in loop mode */
1847 /* determine all loop music */
1849 for (j = 0; music_prefix_info[j].prefix; j++)
1851 int len_prefix_text = strlen(music_prefix_info[j].prefix);
1853 if (len_prefix_text < len_music_text &&
1854 strncmp(music->token,
1855 music_prefix_info[j].prefix, len_prefix_text) == 0)
1857 music_info[i].loop = music_prefix_info[j].is_loop_music;
1863 set_music_parameters(i, music->parameter);
1867 static void ReinitializeGraphics()
1869 InitGraphicInfo(); /* graphic properties mapping */
1870 InitElementGraphicInfo(); /* element game graphic mapping */
1871 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
1873 InitElementSmallImages(); /* scale elements to all needed sizes */
1874 InitScaledImages(); /* scale all other images, if needed */
1875 InitFontGraphicInfo(); /* initialize text drawing functions */
1877 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
1879 SetMainBackgroundImage(IMG_BACKGROUND);
1880 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1886 static void ReinitializeSounds()
1888 InitSoundInfo(); /* sound properties mapping */
1889 InitElementSoundInfo(); /* element game sound mapping */
1890 InitGameModeSoundInfo(); /* game mode sound mapping */
1892 InitPlayLevelSound(); /* internal game sound settings */
1895 static void ReinitializeMusic()
1897 InitMusicInfo(); /* music properties mapping */
1898 InitGameModeMusicInfo(); /* game mode music mapping */
1901 static int get_special_property_bit(int element, int property_bit_nr)
1903 struct PropertyBitInfo
1909 static struct PropertyBitInfo pb_can_move_into_acid[] =
1911 /* the player may be able fall into acid when gravity is activated */
1916 { EL_SP_MURPHY, 0 },
1917 { EL_SOKOBAN_FIELD_PLAYER, 0 },
1919 /* all elements that can move may be able to also move into acid */
1922 { EL_BUG_RIGHT, 1 },
1925 { EL_SPACESHIP, 2 },
1926 { EL_SPACESHIP_LEFT, 2 },
1927 { EL_SPACESHIP_RIGHT, 2 },
1928 { EL_SPACESHIP_UP, 2 },
1929 { EL_SPACESHIP_DOWN, 2 },
1930 { EL_BD_BUTTERFLY, 3 },
1931 { EL_BD_BUTTERFLY_LEFT, 3 },
1932 { EL_BD_BUTTERFLY_RIGHT, 3 },
1933 { EL_BD_BUTTERFLY_UP, 3 },
1934 { EL_BD_BUTTERFLY_DOWN, 3 },
1935 { EL_BD_FIREFLY, 4 },
1936 { EL_BD_FIREFLY_LEFT, 4 },
1937 { EL_BD_FIREFLY_RIGHT, 4 },
1938 { EL_BD_FIREFLY_UP, 4 },
1939 { EL_BD_FIREFLY_DOWN, 4 },
1941 { EL_YAMYAM_LEFT, 5 },
1942 { EL_YAMYAM_RIGHT, 5 },
1943 { EL_YAMYAM_UP, 5 },
1944 { EL_YAMYAM_DOWN, 5 },
1945 { EL_DARK_YAMYAM, 6 },
1948 { EL_PACMAN_LEFT, 8 },
1949 { EL_PACMAN_RIGHT, 8 },
1950 { EL_PACMAN_UP, 8 },
1951 { EL_PACMAN_DOWN, 8 },
1953 { EL_MOLE_LEFT, 9 },
1954 { EL_MOLE_RIGHT, 9 },
1956 { EL_MOLE_DOWN, 9 },
1960 { EL_SATELLITE, 13 },
1961 { EL_SP_SNIKSNAK, 14 },
1962 { EL_SP_ELECTRON, 15 },
1965 { EL_EMC_ANDROID, 18 },
1970 static struct PropertyBitInfo pb_dont_collide_with[] =
1972 { EL_SP_SNIKSNAK, 0 },
1973 { EL_SP_ELECTRON, 1 },
1981 struct PropertyBitInfo *pb_info;
1984 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
1985 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
1990 struct PropertyBitInfo *pb_info = NULL;
1993 for (i = 0; pb_definition[i].bit_nr != -1; i++)
1994 if (pb_definition[i].bit_nr == property_bit_nr)
1995 pb_info = pb_definition[i].pb_info;
1997 if (pb_info == NULL)
2000 for (i = 0; pb_info[i].element != -1; i++)
2001 if (pb_info[i].element == element)
2002 return pb_info[i].bit_nr;
2007 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2008 boolean property_value)
2010 int bit_nr = get_special_property_bit(element, property_bit_nr);
2015 *bitfield |= (1 << bit_nr);
2017 *bitfield &= ~(1 << bit_nr);
2021 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2023 int bit_nr = get_special_property_bit(element, property_bit_nr);
2026 return ((*bitfield & (1 << bit_nr)) != 0);
2031 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2033 static int group_nr;
2034 static struct ElementGroupInfo *group;
2035 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2038 if (actual_group == NULL) /* not yet initialized */
2041 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
2043 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2044 group_element - EL_GROUP_START + 1);
2046 /* replace element which caused too deep recursion by question mark */
2047 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2052 if (recursion_depth == 0) /* initialization */
2054 group = actual_group;
2055 group_nr = GROUP_NR(group_element);
2057 group->num_elements_resolved = 0;
2058 group->choice_pos = 0;
2060 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2061 element_info[i].in_group[group_nr] = FALSE;
2064 for (i = 0; i < actual_group->num_elements; i++)
2066 int element = actual_group->element[i];
2068 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2071 if (IS_GROUP_ELEMENT(element))
2072 ResolveGroupElementExt(element, recursion_depth + 1);
2075 group->element_resolved[group->num_elements_resolved++] = element;
2076 element_info[element].in_group[group_nr] = TRUE;
2081 void ResolveGroupElement(int group_element)
2083 ResolveGroupElementExt(group_element, 0);
2086 void InitElementPropertiesStatic()
2088 static int ep_diggable[] =
2093 EL_SP_BUGGY_BASE_ACTIVATING,
2096 EL_INVISIBLE_SAND_ACTIVE,
2099 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2100 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2105 EL_SP_BUGGY_BASE_ACTIVE,
2112 static int ep_collectible_only[] =
2134 EL_DYNABOMB_INCREASE_NUMBER,
2135 EL_DYNABOMB_INCREASE_SIZE,
2136 EL_DYNABOMB_INCREASE_POWER,
2154 /* !!! handle separately !!! */
2155 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2161 static int ep_dont_run_into[] =
2163 /* same elements as in 'ep_dont_touch' */
2169 /* same elements as in 'ep_dont_collide_with' */
2181 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2186 EL_SP_BUGGY_BASE_ACTIVE,
2193 static int ep_dont_collide_with[] =
2195 /* same elements as in 'ep_dont_touch' */
2212 static int ep_dont_touch[] =
2222 static int ep_indestructible[] =
2226 EL_ACID_POOL_TOPLEFT,
2227 EL_ACID_POOL_TOPRIGHT,
2228 EL_ACID_POOL_BOTTOMLEFT,
2229 EL_ACID_POOL_BOTTOM,
2230 EL_ACID_POOL_BOTTOMRIGHT,
2231 EL_SP_HARDWARE_GRAY,
2232 EL_SP_HARDWARE_GREEN,
2233 EL_SP_HARDWARE_BLUE,
2235 EL_SP_HARDWARE_YELLOW,
2236 EL_SP_HARDWARE_BASE_1,
2237 EL_SP_HARDWARE_BASE_2,
2238 EL_SP_HARDWARE_BASE_3,
2239 EL_SP_HARDWARE_BASE_4,
2240 EL_SP_HARDWARE_BASE_5,
2241 EL_SP_HARDWARE_BASE_6,
2242 EL_INVISIBLE_STEELWALL,
2243 EL_INVISIBLE_STEELWALL_ACTIVE,
2244 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2245 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2246 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2247 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2248 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2249 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2250 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2251 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2252 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2253 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2254 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2255 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2257 EL_LIGHT_SWITCH_ACTIVE,
2258 EL_SIGN_EXCLAMATION,
2259 EL_SIGN_RADIOACTIVITY,
2266 EL_SIGN_ENTRY_FORBIDDEN,
2267 EL_SIGN_EMERGENCY_EXIT,
2275 EL_STEEL_EXIT_CLOSED,
2277 EL_EM_STEEL_EXIT_CLOSED,
2278 EL_EM_STEEL_EXIT_OPEN,
2279 EL_DC_STEELWALL_1_LEFT,
2280 EL_DC_STEELWALL_1_RIGHT,
2281 EL_DC_STEELWALL_1_TOP,
2282 EL_DC_STEELWALL_1_BOTTOM,
2283 EL_DC_STEELWALL_1_HORIZONTAL,
2284 EL_DC_STEELWALL_1_VERTICAL,
2285 EL_DC_STEELWALL_1_TOPLEFT,
2286 EL_DC_STEELWALL_1_TOPRIGHT,
2287 EL_DC_STEELWALL_1_BOTTOMLEFT,
2288 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2289 EL_DC_STEELWALL_1_TOPLEFT_2,
2290 EL_DC_STEELWALL_1_TOPRIGHT_2,
2291 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2292 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2293 EL_DC_STEELWALL_2_LEFT,
2294 EL_DC_STEELWALL_2_RIGHT,
2295 EL_DC_STEELWALL_2_TOP,
2296 EL_DC_STEELWALL_2_BOTTOM,
2297 EL_DC_STEELWALL_2_HORIZONTAL,
2298 EL_DC_STEELWALL_2_VERTICAL,
2299 EL_DC_STEELWALL_2_MIDDLE,
2300 EL_DC_STEELWALL_2_SINGLE,
2301 EL_STEELWALL_SLIPPERY,
2315 EL_GATE_1_GRAY_ACTIVE,
2316 EL_GATE_2_GRAY_ACTIVE,
2317 EL_GATE_3_GRAY_ACTIVE,
2318 EL_GATE_4_GRAY_ACTIVE,
2327 EL_EM_GATE_1_GRAY_ACTIVE,
2328 EL_EM_GATE_2_GRAY_ACTIVE,
2329 EL_EM_GATE_3_GRAY_ACTIVE,
2330 EL_EM_GATE_4_GRAY_ACTIVE,
2339 EL_EMC_GATE_5_GRAY_ACTIVE,
2340 EL_EMC_GATE_6_GRAY_ACTIVE,
2341 EL_EMC_GATE_7_GRAY_ACTIVE,
2342 EL_EMC_GATE_8_GRAY_ACTIVE,
2344 EL_DC_GATE_WHITE_GRAY,
2345 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2346 EL_DC_GATE_FAKE_GRAY,
2348 EL_SWITCHGATE_OPENING,
2349 EL_SWITCHGATE_CLOSED,
2350 EL_SWITCHGATE_CLOSING,
2352 EL_DC_SWITCHGATE_SWITCH_UP,
2353 EL_DC_SWITCHGATE_SWITCH_DOWN,
2356 EL_TIMEGATE_OPENING,
2358 EL_TIMEGATE_CLOSING,
2360 EL_DC_TIMEGATE_SWITCH,
2361 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2366 EL_TUBE_VERTICAL_LEFT,
2367 EL_TUBE_VERTICAL_RIGHT,
2368 EL_TUBE_HORIZONTAL_UP,
2369 EL_TUBE_HORIZONTAL_DOWN,
2374 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2375 EL_EXPANDABLE_STEELWALL_VERTICAL,
2376 EL_EXPANDABLE_STEELWALL_ANY,
2381 static int ep_slippery[] =
2395 EL_ROBOT_WHEEL_ACTIVE,
2401 EL_ACID_POOL_TOPLEFT,
2402 EL_ACID_POOL_TOPRIGHT,
2412 EL_STEELWALL_SLIPPERY,
2415 EL_EMC_WALL_SLIPPERY_1,
2416 EL_EMC_WALL_SLIPPERY_2,
2417 EL_EMC_WALL_SLIPPERY_3,
2418 EL_EMC_WALL_SLIPPERY_4,
2420 EL_EMC_MAGIC_BALL_ACTIVE,
2425 static int ep_can_change[] =
2430 static int ep_can_move[] =
2432 /* same elements as in 'pb_can_move_into_acid' */
2455 static int ep_can_fall[] =
2469 EL_QUICKSAND_FAST_FULL,
2471 EL_BD_MAGIC_WALL_FULL,
2472 EL_DC_MAGIC_WALL_FULL,
2486 static int ep_can_smash_player[] =
2512 static int ep_can_smash_enemies[] =
2521 static int ep_can_smash_everything[] =
2530 static int ep_explodes_by_fire[] =
2532 /* same elements as in 'ep_explodes_impact' */
2537 /* same elements as in 'ep_explodes_smashed' */
2547 EL_EM_DYNAMITE_ACTIVE,
2548 EL_DYNABOMB_PLAYER_1_ACTIVE,
2549 EL_DYNABOMB_PLAYER_2_ACTIVE,
2550 EL_DYNABOMB_PLAYER_3_ACTIVE,
2551 EL_DYNABOMB_PLAYER_4_ACTIVE,
2552 EL_DYNABOMB_INCREASE_NUMBER,
2553 EL_DYNABOMB_INCREASE_SIZE,
2554 EL_DYNABOMB_INCREASE_POWER,
2555 EL_SP_DISK_RED_ACTIVE,
2569 static int ep_explodes_smashed[] =
2571 /* same elements as in 'ep_explodes_impact' */
2585 static int ep_explodes_impact[] =
2594 static int ep_walkable_over[] =
2598 EL_SOKOBAN_FIELD_EMPTY,
2604 EL_EM_STEEL_EXIT_OPEN,
2613 EL_GATE_1_GRAY_ACTIVE,
2614 EL_GATE_2_GRAY_ACTIVE,
2615 EL_GATE_3_GRAY_ACTIVE,
2616 EL_GATE_4_GRAY_ACTIVE,
2624 static int ep_walkable_inside[] =
2629 EL_TUBE_VERTICAL_LEFT,
2630 EL_TUBE_VERTICAL_RIGHT,
2631 EL_TUBE_HORIZONTAL_UP,
2632 EL_TUBE_HORIZONTAL_DOWN,
2641 static int ep_walkable_under[] =
2646 static int ep_passable_over[] =
2656 EL_EM_GATE_1_GRAY_ACTIVE,
2657 EL_EM_GATE_2_GRAY_ACTIVE,
2658 EL_EM_GATE_3_GRAY_ACTIVE,
2659 EL_EM_GATE_4_GRAY_ACTIVE,
2668 EL_EMC_GATE_5_GRAY_ACTIVE,
2669 EL_EMC_GATE_6_GRAY_ACTIVE,
2670 EL_EMC_GATE_7_GRAY_ACTIVE,
2671 EL_EMC_GATE_8_GRAY_ACTIVE,
2673 EL_DC_GATE_WHITE_GRAY,
2674 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2681 static int ep_passable_inside[] =
2687 EL_SP_PORT_HORIZONTAL,
2688 EL_SP_PORT_VERTICAL,
2690 EL_SP_GRAVITY_PORT_LEFT,
2691 EL_SP_GRAVITY_PORT_RIGHT,
2692 EL_SP_GRAVITY_PORT_UP,
2693 EL_SP_GRAVITY_PORT_DOWN,
2694 EL_SP_GRAVITY_ON_PORT_LEFT,
2695 EL_SP_GRAVITY_ON_PORT_RIGHT,
2696 EL_SP_GRAVITY_ON_PORT_UP,
2697 EL_SP_GRAVITY_ON_PORT_DOWN,
2698 EL_SP_GRAVITY_OFF_PORT_LEFT,
2699 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2700 EL_SP_GRAVITY_OFF_PORT_UP,
2701 EL_SP_GRAVITY_OFF_PORT_DOWN,
2706 static int ep_passable_under[] =
2711 static int ep_droppable[] =
2716 static int ep_explodes_1x1_old[] =
2721 static int ep_pushable[] =
2733 EL_SOKOBAN_FIELD_FULL,
2742 static int ep_explodes_cross_old[] =
2747 static int ep_protected[] =
2749 /* same elements as in 'ep_walkable_inside' */
2753 EL_TUBE_VERTICAL_LEFT,
2754 EL_TUBE_VERTICAL_RIGHT,
2755 EL_TUBE_HORIZONTAL_UP,
2756 EL_TUBE_HORIZONTAL_DOWN,
2762 /* same elements as in 'ep_passable_over' */
2771 EL_EM_GATE_1_GRAY_ACTIVE,
2772 EL_EM_GATE_2_GRAY_ACTIVE,
2773 EL_EM_GATE_3_GRAY_ACTIVE,
2774 EL_EM_GATE_4_GRAY_ACTIVE,
2783 EL_EMC_GATE_5_GRAY_ACTIVE,
2784 EL_EMC_GATE_6_GRAY_ACTIVE,
2785 EL_EMC_GATE_7_GRAY_ACTIVE,
2786 EL_EMC_GATE_8_GRAY_ACTIVE,
2788 EL_DC_GATE_WHITE_GRAY,
2789 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2793 /* same elements as in 'ep_passable_inside' */
2798 EL_SP_PORT_HORIZONTAL,
2799 EL_SP_PORT_VERTICAL,
2801 EL_SP_GRAVITY_PORT_LEFT,
2802 EL_SP_GRAVITY_PORT_RIGHT,
2803 EL_SP_GRAVITY_PORT_UP,
2804 EL_SP_GRAVITY_PORT_DOWN,
2805 EL_SP_GRAVITY_ON_PORT_LEFT,
2806 EL_SP_GRAVITY_ON_PORT_RIGHT,
2807 EL_SP_GRAVITY_ON_PORT_UP,
2808 EL_SP_GRAVITY_ON_PORT_DOWN,
2809 EL_SP_GRAVITY_OFF_PORT_LEFT,
2810 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2811 EL_SP_GRAVITY_OFF_PORT_UP,
2812 EL_SP_GRAVITY_OFF_PORT_DOWN,
2817 static int ep_throwable[] =
2822 static int ep_can_explode[] =
2824 /* same elements as in 'ep_explodes_impact' */
2829 /* same elements as in 'ep_explodes_smashed' */
2835 /* elements that can explode by explosion or by dragonfire */
2839 EL_EM_DYNAMITE_ACTIVE,
2840 EL_DYNABOMB_PLAYER_1_ACTIVE,
2841 EL_DYNABOMB_PLAYER_2_ACTIVE,
2842 EL_DYNABOMB_PLAYER_3_ACTIVE,
2843 EL_DYNABOMB_PLAYER_4_ACTIVE,
2844 EL_DYNABOMB_INCREASE_NUMBER,
2845 EL_DYNABOMB_INCREASE_SIZE,
2846 EL_DYNABOMB_INCREASE_POWER,
2847 EL_SP_DISK_RED_ACTIVE,
2855 /* elements that can explode only by explosion */
2861 static int ep_gravity_reachable[] =
2867 EL_INVISIBLE_SAND_ACTIVE,
2872 EL_SP_PORT_HORIZONTAL,
2873 EL_SP_PORT_VERTICAL,
2875 EL_SP_GRAVITY_PORT_LEFT,
2876 EL_SP_GRAVITY_PORT_RIGHT,
2877 EL_SP_GRAVITY_PORT_UP,
2878 EL_SP_GRAVITY_PORT_DOWN,
2879 EL_SP_GRAVITY_ON_PORT_LEFT,
2880 EL_SP_GRAVITY_ON_PORT_RIGHT,
2881 EL_SP_GRAVITY_ON_PORT_UP,
2882 EL_SP_GRAVITY_ON_PORT_DOWN,
2883 EL_SP_GRAVITY_OFF_PORT_LEFT,
2884 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2885 EL_SP_GRAVITY_OFF_PORT_UP,
2886 EL_SP_GRAVITY_OFF_PORT_DOWN,
2892 static int ep_player[] =
2899 EL_SOKOBAN_FIELD_PLAYER,
2905 static int ep_can_pass_magic_wall[] =
2919 static int ep_can_pass_dc_magic_wall[] =
2935 static int ep_switchable[] =
2939 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2940 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2941 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2942 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2943 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2944 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2945 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2946 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2947 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2948 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2949 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2950 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2951 EL_SWITCHGATE_SWITCH_UP,
2952 EL_SWITCHGATE_SWITCH_DOWN,
2953 EL_DC_SWITCHGATE_SWITCH_UP,
2954 EL_DC_SWITCHGATE_SWITCH_DOWN,
2956 EL_LIGHT_SWITCH_ACTIVE,
2958 EL_DC_TIMEGATE_SWITCH,
2959 EL_BALLOON_SWITCH_LEFT,
2960 EL_BALLOON_SWITCH_RIGHT,
2961 EL_BALLOON_SWITCH_UP,
2962 EL_BALLOON_SWITCH_DOWN,
2963 EL_BALLOON_SWITCH_ANY,
2964 EL_BALLOON_SWITCH_NONE,
2967 EL_EMC_MAGIC_BALL_SWITCH,
2968 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
2973 static int ep_bd_element[] =
3007 static int ep_sp_element[] =
3009 /* should always be valid */
3012 /* standard classic Supaplex elements */
3019 EL_SP_HARDWARE_GRAY,
3027 EL_SP_GRAVITY_PORT_RIGHT,
3028 EL_SP_GRAVITY_PORT_DOWN,
3029 EL_SP_GRAVITY_PORT_LEFT,
3030 EL_SP_GRAVITY_PORT_UP,
3035 EL_SP_PORT_VERTICAL,
3036 EL_SP_PORT_HORIZONTAL,
3042 EL_SP_HARDWARE_BASE_1,
3043 EL_SP_HARDWARE_GREEN,
3044 EL_SP_HARDWARE_BLUE,
3046 EL_SP_HARDWARE_YELLOW,
3047 EL_SP_HARDWARE_BASE_2,
3048 EL_SP_HARDWARE_BASE_3,
3049 EL_SP_HARDWARE_BASE_4,
3050 EL_SP_HARDWARE_BASE_5,
3051 EL_SP_HARDWARE_BASE_6,
3055 /* additional elements that appeared in newer Supaplex levels */
3058 /* additional gravity port elements (not switching, but setting gravity) */
3059 EL_SP_GRAVITY_ON_PORT_LEFT,
3060 EL_SP_GRAVITY_ON_PORT_RIGHT,
3061 EL_SP_GRAVITY_ON_PORT_UP,
3062 EL_SP_GRAVITY_ON_PORT_DOWN,
3063 EL_SP_GRAVITY_OFF_PORT_LEFT,
3064 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3065 EL_SP_GRAVITY_OFF_PORT_UP,
3066 EL_SP_GRAVITY_OFF_PORT_DOWN,
3068 /* more than one Murphy in a level results in an inactive clone */
3071 /* runtime Supaplex elements */
3072 EL_SP_DISK_RED_ACTIVE,
3073 EL_SP_TERMINAL_ACTIVE,
3074 EL_SP_BUGGY_BASE_ACTIVATING,
3075 EL_SP_BUGGY_BASE_ACTIVE,
3082 static int ep_sb_element[] =
3087 EL_SOKOBAN_FIELD_EMPTY,
3088 EL_SOKOBAN_FIELD_FULL,
3089 EL_SOKOBAN_FIELD_PLAYER,
3094 EL_INVISIBLE_STEELWALL,
3099 static int ep_gem[] =
3111 static int ep_food_dark_yamyam[] =
3139 static int ep_food_penguin[] =
3153 static int ep_food_pig[] =
3165 static int ep_historic_wall[] =
3176 EL_GATE_1_GRAY_ACTIVE,
3177 EL_GATE_2_GRAY_ACTIVE,
3178 EL_GATE_3_GRAY_ACTIVE,
3179 EL_GATE_4_GRAY_ACTIVE,
3188 EL_EM_GATE_1_GRAY_ACTIVE,
3189 EL_EM_GATE_2_GRAY_ACTIVE,
3190 EL_EM_GATE_3_GRAY_ACTIVE,
3191 EL_EM_GATE_4_GRAY_ACTIVE,
3198 EL_EXPANDABLE_WALL_HORIZONTAL,
3199 EL_EXPANDABLE_WALL_VERTICAL,
3200 EL_EXPANDABLE_WALL_ANY,
3201 EL_EXPANDABLE_WALL_GROWING,
3202 EL_BD_EXPANDABLE_WALL,
3209 EL_SP_HARDWARE_GRAY,
3210 EL_SP_HARDWARE_GREEN,
3211 EL_SP_HARDWARE_BLUE,
3213 EL_SP_HARDWARE_YELLOW,
3214 EL_SP_HARDWARE_BASE_1,
3215 EL_SP_HARDWARE_BASE_2,
3216 EL_SP_HARDWARE_BASE_3,
3217 EL_SP_HARDWARE_BASE_4,
3218 EL_SP_HARDWARE_BASE_5,
3219 EL_SP_HARDWARE_BASE_6,
3221 EL_SP_TERMINAL_ACTIVE,
3224 EL_INVISIBLE_STEELWALL,
3225 EL_INVISIBLE_STEELWALL_ACTIVE,
3227 EL_INVISIBLE_WALL_ACTIVE,
3228 EL_STEELWALL_SLIPPERY,
3245 static int ep_historic_solid[] =
3249 EL_EXPANDABLE_WALL_HORIZONTAL,
3250 EL_EXPANDABLE_WALL_VERTICAL,
3251 EL_EXPANDABLE_WALL_ANY,
3252 EL_BD_EXPANDABLE_WALL,
3265 EL_QUICKSAND_FILLING,
3266 EL_QUICKSAND_EMPTYING,
3268 EL_MAGIC_WALL_ACTIVE,
3269 EL_MAGIC_WALL_EMPTYING,
3270 EL_MAGIC_WALL_FILLING,
3274 EL_BD_MAGIC_WALL_ACTIVE,
3275 EL_BD_MAGIC_WALL_EMPTYING,
3276 EL_BD_MAGIC_WALL_FULL,
3277 EL_BD_MAGIC_WALL_FILLING,
3278 EL_BD_MAGIC_WALL_DEAD,
3287 EL_SP_TERMINAL_ACTIVE,
3291 EL_INVISIBLE_WALL_ACTIVE,
3292 EL_SWITCHGATE_SWITCH_UP,
3293 EL_SWITCHGATE_SWITCH_DOWN,
3294 EL_DC_SWITCHGATE_SWITCH_UP,
3295 EL_DC_SWITCHGATE_SWITCH_DOWN,
3297 EL_TIMEGATE_SWITCH_ACTIVE,
3298 EL_DC_TIMEGATE_SWITCH,
3299 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3311 /* the following elements are a direct copy of "indestructible" elements,
3312 except "EL_ACID", which is "indestructible", but not "solid"! */
3317 EL_ACID_POOL_TOPLEFT,
3318 EL_ACID_POOL_TOPRIGHT,
3319 EL_ACID_POOL_BOTTOMLEFT,
3320 EL_ACID_POOL_BOTTOM,
3321 EL_ACID_POOL_BOTTOMRIGHT,
3322 EL_SP_HARDWARE_GRAY,
3323 EL_SP_HARDWARE_GREEN,
3324 EL_SP_HARDWARE_BLUE,
3326 EL_SP_HARDWARE_YELLOW,
3327 EL_SP_HARDWARE_BASE_1,
3328 EL_SP_HARDWARE_BASE_2,
3329 EL_SP_HARDWARE_BASE_3,
3330 EL_SP_HARDWARE_BASE_4,
3331 EL_SP_HARDWARE_BASE_5,
3332 EL_SP_HARDWARE_BASE_6,
3333 EL_INVISIBLE_STEELWALL,
3334 EL_INVISIBLE_STEELWALL_ACTIVE,
3335 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3336 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3337 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3338 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3339 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3340 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3341 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3342 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3343 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3344 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3345 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3346 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3348 EL_LIGHT_SWITCH_ACTIVE,
3349 EL_SIGN_EXCLAMATION,
3350 EL_SIGN_RADIOACTIVITY,
3357 EL_SIGN_ENTRY_FORBIDDEN,
3358 EL_SIGN_EMERGENCY_EXIT,
3366 EL_STEEL_EXIT_CLOSED,
3368 EL_DC_STEELWALL_1_LEFT,
3369 EL_DC_STEELWALL_1_RIGHT,
3370 EL_DC_STEELWALL_1_TOP,
3371 EL_DC_STEELWALL_1_BOTTOM,
3372 EL_DC_STEELWALL_1_HORIZONTAL,
3373 EL_DC_STEELWALL_1_VERTICAL,
3374 EL_DC_STEELWALL_1_TOPLEFT,
3375 EL_DC_STEELWALL_1_TOPRIGHT,
3376 EL_DC_STEELWALL_1_BOTTOMLEFT,
3377 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3378 EL_DC_STEELWALL_1_TOPLEFT_2,
3379 EL_DC_STEELWALL_1_TOPRIGHT_2,
3380 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3381 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3382 EL_DC_STEELWALL_2_LEFT,
3383 EL_DC_STEELWALL_2_RIGHT,
3384 EL_DC_STEELWALL_2_TOP,
3385 EL_DC_STEELWALL_2_BOTTOM,
3386 EL_DC_STEELWALL_2_HORIZONTAL,
3387 EL_DC_STEELWALL_2_VERTICAL,
3388 EL_DC_STEELWALL_2_MIDDLE,
3389 EL_DC_STEELWALL_2_SINGLE,
3390 EL_STEELWALL_SLIPPERY,
3404 EL_GATE_1_GRAY_ACTIVE,
3405 EL_GATE_2_GRAY_ACTIVE,
3406 EL_GATE_3_GRAY_ACTIVE,
3407 EL_GATE_4_GRAY_ACTIVE,
3416 EL_EM_GATE_1_GRAY_ACTIVE,
3417 EL_EM_GATE_2_GRAY_ACTIVE,
3418 EL_EM_GATE_3_GRAY_ACTIVE,
3419 EL_EM_GATE_4_GRAY_ACTIVE,
3421 EL_SWITCHGATE_OPENING,
3422 EL_SWITCHGATE_CLOSED,
3423 EL_SWITCHGATE_CLOSING,
3425 EL_TIMEGATE_OPENING,
3427 EL_TIMEGATE_CLOSING,
3431 EL_TUBE_VERTICAL_LEFT,
3432 EL_TUBE_VERTICAL_RIGHT,
3433 EL_TUBE_HORIZONTAL_UP,
3434 EL_TUBE_HORIZONTAL_DOWN,
3443 static int ep_classic_enemy[] =
3460 static int ep_belt[] =
3462 EL_CONVEYOR_BELT_1_LEFT,
3463 EL_CONVEYOR_BELT_1_MIDDLE,
3464 EL_CONVEYOR_BELT_1_RIGHT,
3465 EL_CONVEYOR_BELT_2_LEFT,
3466 EL_CONVEYOR_BELT_2_MIDDLE,
3467 EL_CONVEYOR_BELT_2_RIGHT,
3468 EL_CONVEYOR_BELT_3_LEFT,
3469 EL_CONVEYOR_BELT_3_MIDDLE,
3470 EL_CONVEYOR_BELT_3_RIGHT,
3471 EL_CONVEYOR_BELT_4_LEFT,
3472 EL_CONVEYOR_BELT_4_MIDDLE,
3473 EL_CONVEYOR_BELT_4_RIGHT,
3478 static int ep_belt_active[] =
3480 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3481 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3482 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3483 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3484 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3485 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3486 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3487 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3488 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3489 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3490 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3491 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3496 static int ep_belt_switch[] =
3498 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3499 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3500 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3501 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3502 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3503 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3504 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3505 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3506 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3507 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3508 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3509 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3514 static int ep_tube[] =
3521 EL_TUBE_HORIZONTAL_UP,
3522 EL_TUBE_HORIZONTAL_DOWN,
3524 EL_TUBE_VERTICAL_LEFT,
3525 EL_TUBE_VERTICAL_RIGHT,
3531 static int ep_acid_pool[] =
3533 EL_ACID_POOL_TOPLEFT,
3534 EL_ACID_POOL_TOPRIGHT,
3535 EL_ACID_POOL_BOTTOMLEFT,
3536 EL_ACID_POOL_BOTTOM,
3537 EL_ACID_POOL_BOTTOMRIGHT,
3542 static int ep_keygate[] =
3552 EL_GATE_1_GRAY_ACTIVE,
3553 EL_GATE_2_GRAY_ACTIVE,
3554 EL_GATE_3_GRAY_ACTIVE,
3555 EL_GATE_4_GRAY_ACTIVE,
3564 EL_EM_GATE_1_GRAY_ACTIVE,
3565 EL_EM_GATE_2_GRAY_ACTIVE,
3566 EL_EM_GATE_3_GRAY_ACTIVE,
3567 EL_EM_GATE_4_GRAY_ACTIVE,
3576 EL_EMC_GATE_5_GRAY_ACTIVE,
3577 EL_EMC_GATE_6_GRAY_ACTIVE,
3578 EL_EMC_GATE_7_GRAY_ACTIVE,
3579 EL_EMC_GATE_8_GRAY_ACTIVE,
3581 EL_DC_GATE_WHITE_GRAY,
3582 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3587 static int ep_amoeboid[] =
3599 static int ep_amoebalive[] =
3610 static int ep_has_editor_content[] =
3632 static int ep_can_turn_each_move[] =
3634 /* !!! do something with this one !!! */
3638 static int ep_can_grow[] =
3652 static int ep_active_bomb[] =
3655 EL_EM_DYNAMITE_ACTIVE,
3656 EL_DYNABOMB_PLAYER_1_ACTIVE,
3657 EL_DYNABOMB_PLAYER_2_ACTIVE,
3658 EL_DYNABOMB_PLAYER_3_ACTIVE,
3659 EL_DYNABOMB_PLAYER_4_ACTIVE,
3660 EL_SP_DISK_RED_ACTIVE,
3665 static int ep_inactive[] =
3675 EL_QUICKSAND_FAST_EMPTY,
3698 EL_GATE_1_GRAY_ACTIVE,
3699 EL_GATE_2_GRAY_ACTIVE,
3700 EL_GATE_3_GRAY_ACTIVE,
3701 EL_GATE_4_GRAY_ACTIVE,
3710 EL_EM_GATE_1_GRAY_ACTIVE,
3711 EL_EM_GATE_2_GRAY_ACTIVE,
3712 EL_EM_GATE_3_GRAY_ACTIVE,
3713 EL_EM_GATE_4_GRAY_ACTIVE,
3722 EL_EMC_GATE_5_GRAY_ACTIVE,
3723 EL_EMC_GATE_6_GRAY_ACTIVE,
3724 EL_EMC_GATE_7_GRAY_ACTIVE,
3725 EL_EMC_GATE_8_GRAY_ACTIVE,
3727 EL_DC_GATE_WHITE_GRAY,
3728 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3729 EL_DC_GATE_FAKE_GRAY,
3732 EL_INVISIBLE_STEELWALL,
3740 EL_WALL_EMERALD_YELLOW,
3741 EL_DYNABOMB_INCREASE_NUMBER,
3742 EL_DYNABOMB_INCREASE_SIZE,
3743 EL_DYNABOMB_INCREASE_POWER,
3747 EL_SOKOBAN_FIELD_EMPTY,
3748 EL_SOKOBAN_FIELD_FULL,
3749 EL_WALL_EMERALD_RED,
3750 EL_WALL_EMERALD_PURPLE,
3751 EL_ACID_POOL_TOPLEFT,
3752 EL_ACID_POOL_TOPRIGHT,
3753 EL_ACID_POOL_BOTTOMLEFT,
3754 EL_ACID_POOL_BOTTOM,
3755 EL_ACID_POOL_BOTTOMRIGHT,
3759 EL_BD_MAGIC_WALL_DEAD,
3761 EL_DC_MAGIC_WALL_DEAD,
3762 EL_AMOEBA_TO_DIAMOND,
3770 EL_SP_GRAVITY_PORT_RIGHT,
3771 EL_SP_GRAVITY_PORT_DOWN,
3772 EL_SP_GRAVITY_PORT_LEFT,
3773 EL_SP_GRAVITY_PORT_UP,
3774 EL_SP_PORT_HORIZONTAL,
3775 EL_SP_PORT_VERTICAL,
3786 EL_SP_HARDWARE_GRAY,
3787 EL_SP_HARDWARE_GREEN,
3788 EL_SP_HARDWARE_BLUE,
3790 EL_SP_HARDWARE_YELLOW,
3791 EL_SP_HARDWARE_BASE_1,
3792 EL_SP_HARDWARE_BASE_2,
3793 EL_SP_HARDWARE_BASE_3,
3794 EL_SP_HARDWARE_BASE_4,
3795 EL_SP_HARDWARE_BASE_5,
3796 EL_SP_HARDWARE_BASE_6,
3797 EL_SP_GRAVITY_ON_PORT_LEFT,
3798 EL_SP_GRAVITY_ON_PORT_RIGHT,
3799 EL_SP_GRAVITY_ON_PORT_UP,
3800 EL_SP_GRAVITY_ON_PORT_DOWN,
3801 EL_SP_GRAVITY_OFF_PORT_LEFT,
3802 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3803 EL_SP_GRAVITY_OFF_PORT_UP,
3804 EL_SP_GRAVITY_OFF_PORT_DOWN,
3805 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3806 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3807 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3808 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3809 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3810 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3811 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3812 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3813 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3814 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3815 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3816 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3817 EL_SIGN_EXCLAMATION,
3818 EL_SIGN_RADIOACTIVITY,
3825 EL_SIGN_ENTRY_FORBIDDEN,
3826 EL_SIGN_EMERGENCY_EXIT,
3834 EL_DC_STEELWALL_1_LEFT,
3835 EL_DC_STEELWALL_1_RIGHT,
3836 EL_DC_STEELWALL_1_TOP,
3837 EL_DC_STEELWALL_1_BOTTOM,
3838 EL_DC_STEELWALL_1_HORIZONTAL,
3839 EL_DC_STEELWALL_1_VERTICAL,
3840 EL_DC_STEELWALL_1_TOPLEFT,
3841 EL_DC_STEELWALL_1_TOPRIGHT,
3842 EL_DC_STEELWALL_1_BOTTOMLEFT,
3843 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3844 EL_DC_STEELWALL_1_TOPLEFT_2,
3845 EL_DC_STEELWALL_1_TOPRIGHT_2,
3846 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3847 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3848 EL_DC_STEELWALL_2_LEFT,
3849 EL_DC_STEELWALL_2_RIGHT,
3850 EL_DC_STEELWALL_2_TOP,
3851 EL_DC_STEELWALL_2_BOTTOM,
3852 EL_DC_STEELWALL_2_HORIZONTAL,
3853 EL_DC_STEELWALL_2_VERTICAL,
3854 EL_DC_STEELWALL_2_MIDDLE,
3855 EL_DC_STEELWALL_2_SINGLE,
3856 EL_STEELWALL_SLIPPERY,
3861 EL_EMC_WALL_SLIPPERY_1,
3862 EL_EMC_WALL_SLIPPERY_2,
3863 EL_EMC_WALL_SLIPPERY_3,
3864 EL_EMC_WALL_SLIPPERY_4,
3885 static int ep_em_slippery_wall[] =
3890 static int ep_gfx_crumbled[] =
3901 static int ep_editor_cascade_active[] =
3903 EL_INTERNAL_CASCADE_BD_ACTIVE,
3904 EL_INTERNAL_CASCADE_EM_ACTIVE,
3905 EL_INTERNAL_CASCADE_EMC_ACTIVE,
3906 EL_INTERNAL_CASCADE_RND_ACTIVE,
3907 EL_INTERNAL_CASCADE_SB_ACTIVE,
3908 EL_INTERNAL_CASCADE_SP_ACTIVE,
3909 EL_INTERNAL_CASCADE_DC_ACTIVE,
3910 EL_INTERNAL_CASCADE_DX_ACTIVE,
3911 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
3912 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
3913 EL_INTERNAL_CASCADE_CE_ACTIVE,
3914 EL_INTERNAL_CASCADE_GE_ACTIVE,
3915 EL_INTERNAL_CASCADE_REF_ACTIVE,
3916 EL_INTERNAL_CASCADE_USER_ACTIVE,
3917 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
3922 static int ep_editor_cascade_inactive[] =
3924 EL_INTERNAL_CASCADE_BD,
3925 EL_INTERNAL_CASCADE_EM,
3926 EL_INTERNAL_CASCADE_EMC,
3927 EL_INTERNAL_CASCADE_RND,
3928 EL_INTERNAL_CASCADE_SB,
3929 EL_INTERNAL_CASCADE_SP,
3930 EL_INTERNAL_CASCADE_DC,
3931 EL_INTERNAL_CASCADE_DX,
3932 EL_INTERNAL_CASCADE_CHARS,
3933 EL_INTERNAL_CASCADE_STEEL_CHARS,
3934 EL_INTERNAL_CASCADE_CE,
3935 EL_INTERNAL_CASCADE_GE,
3936 EL_INTERNAL_CASCADE_REF,
3937 EL_INTERNAL_CASCADE_USER,
3938 EL_INTERNAL_CASCADE_DYNAMIC,
3943 static int ep_obsolete[] =
3947 EL_EM_KEY_1_FILE_OBSOLETE,
3948 EL_EM_KEY_2_FILE_OBSOLETE,
3949 EL_EM_KEY_3_FILE_OBSOLETE,
3950 EL_EM_KEY_4_FILE_OBSOLETE,
3951 EL_ENVELOPE_OBSOLETE,
3960 } element_properties[] =
3962 { ep_diggable, EP_DIGGABLE },
3963 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
3964 { ep_dont_run_into, EP_DONT_RUN_INTO },
3965 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
3966 { ep_dont_touch, EP_DONT_TOUCH },
3967 { ep_indestructible, EP_INDESTRUCTIBLE },
3968 { ep_slippery, EP_SLIPPERY },
3969 { ep_can_change, EP_CAN_CHANGE },
3970 { ep_can_move, EP_CAN_MOVE },
3971 { ep_can_fall, EP_CAN_FALL },
3972 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
3973 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
3974 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
3975 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
3976 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
3977 { ep_explodes_impact, EP_EXPLODES_IMPACT },
3978 { ep_walkable_over, EP_WALKABLE_OVER },
3979 { ep_walkable_inside, EP_WALKABLE_INSIDE },
3980 { ep_walkable_under, EP_WALKABLE_UNDER },
3981 { ep_passable_over, EP_PASSABLE_OVER },
3982 { ep_passable_inside, EP_PASSABLE_INSIDE },
3983 { ep_passable_under, EP_PASSABLE_UNDER },
3984 { ep_droppable, EP_DROPPABLE },
3985 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
3986 { ep_pushable, EP_PUSHABLE },
3987 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
3988 { ep_protected, EP_PROTECTED },
3989 { ep_throwable, EP_THROWABLE },
3990 { ep_can_explode, EP_CAN_EXPLODE },
3991 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
3993 { ep_player, EP_PLAYER },
3994 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
3995 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
3996 { ep_switchable, EP_SWITCHABLE },
3997 { ep_bd_element, EP_BD_ELEMENT },
3998 { ep_sp_element, EP_SP_ELEMENT },
3999 { ep_sb_element, EP_SB_ELEMENT },
4001 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4002 { ep_food_penguin, EP_FOOD_PENGUIN },
4003 { ep_food_pig, EP_FOOD_PIG },
4004 { ep_historic_wall, EP_HISTORIC_WALL },
4005 { ep_historic_solid, EP_HISTORIC_SOLID },
4006 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4007 { ep_belt, EP_BELT },
4008 { ep_belt_active, EP_BELT_ACTIVE },
4009 { ep_belt_switch, EP_BELT_SWITCH },
4010 { ep_tube, EP_TUBE },
4011 { ep_acid_pool, EP_ACID_POOL },
4012 { ep_keygate, EP_KEYGATE },
4013 { ep_amoeboid, EP_AMOEBOID },
4014 { ep_amoebalive, EP_AMOEBALIVE },
4015 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4016 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4017 { ep_can_grow, EP_CAN_GROW },
4018 { ep_active_bomb, EP_ACTIVE_BOMB },
4019 { ep_inactive, EP_INACTIVE },
4021 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4023 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4025 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4026 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4028 { ep_obsolete, EP_OBSOLETE },
4035 /* always start with reliable default values (element has no properties) */
4036 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4037 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4038 SET_PROPERTY(i, j, FALSE);
4040 /* set all base element properties from above array definitions */
4041 for (i = 0; element_properties[i].elements != NULL; i++)
4042 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4043 SET_PROPERTY((element_properties[i].elements)[j],
4044 element_properties[i].property, TRUE);
4046 /* copy properties to some elements that are only stored in level file */
4047 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4048 for (j = 0; copy_properties[j][0] != -1; j++)
4049 if (HAS_PROPERTY(copy_properties[j][0], i))
4050 for (k = 1; k <= 4; k++)
4051 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4053 /* set static element properties that are not listed in array definitions */
4054 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4055 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4058 void InitElementPropertiesEngine(int engine_version)
4060 static int no_wall_properties[] =
4063 EP_COLLECTIBLE_ONLY,
4065 EP_DONT_COLLIDE_WITH,
4068 EP_CAN_SMASH_PLAYER,
4069 EP_CAN_SMASH_ENEMIES,
4070 EP_CAN_SMASH_EVERYTHING,
4075 EP_FOOD_DARK_YAMYAM,
4091 /* important: after initialization in InitElementPropertiesStatic(), the
4092 elements are not again initialized to a default value; therefore all
4093 changes have to make sure that they leave the element with a defined
4094 property (which means that conditional property changes must be set to
4095 a reliable default value before) */
4097 /* resolve group elements */
4098 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4099 ResolveGroupElement(EL_GROUP_START + i);
4101 /* set all special, combined or engine dependent element properties */
4102 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4104 /* ---------- INACTIVE ------------------------------------------------- */
4105 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4106 i <= EL_CHAR_END) ||
4107 (i >= EL_STEEL_CHAR_START &&
4108 i <= EL_STEEL_CHAR_END)));
4110 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4111 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4112 IS_WALKABLE_INSIDE(i) ||
4113 IS_WALKABLE_UNDER(i)));
4115 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4116 IS_PASSABLE_INSIDE(i) ||
4117 IS_PASSABLE_UNDER(i)));
4119 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4120 IS_PASSABLE_OVER(i)));
4122 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4123 IS_PASSABLE_INSIDE(i)));
4125 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4126 IS_PASSABLE_UNDER(i)));
4128 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4131 /* ---------- COLLECTIBLE ---------------------------------------------- */
4132 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4136 /* ---------- SNAPPABLE ------------------------------------------------ */
4137 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4138 IS_COLLECTIBLE(i) ||
4142 /* ---------- WALL ----------------------------------------------------- */
4143 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4145 for (j = 0; no_wall_properties[j] != -1; j++)
4146 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4147 i >= EL_FIRST_RUNTIME_UNREAL)
4148 SET_PROPERTY(i, EP_WALL, FALSE);
4150 if (IS_HISTORIC_WALL(i))
4151 SET_PROPERTY(i, EP_WALL, TRUE);
4153 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4154 if (engine_version < VERSION_IDENT(2,2,0,0))
4155 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4157 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4159 !IS_COLLECTIBLE(i)));
4161 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4162 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4163 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4165 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4166 IS_INDESTRUCTIBLE(i)));
4168 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4170 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4171 else if (engine_version < VERSION_IDENT(2,2,0,0))
4172 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4174 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4178 if (IS_CUSTOM_ELEMENT(i))
4180 /* these are additional properties which are initially false when set */
4182 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4184 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4185 if (DONT_COLLIDE_WITH(i))
4186 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4188 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4189 if (CAN_SMASH_EVERYTHING(i))
4190 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4191 if (CAN_SMASH_ENEMIES(i))
4192 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4195 /* ---------- CAN_SMASH ------------------------------------------------ */
4196 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4197 CAN_SMASH_ENEMIES(i) ||
4198 CAN_SMASH_EVERYTHING(i)));
4200 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4201 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4202 EXPLODES_BY_FIRE(i)));
4204 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4205 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4206 EXPLODES_SMASHED(i)));
4208 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4209 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4210 EXPLODES_IMPACT(i)));
4212 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4213 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4215 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4216 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4217 i == EL_BLACK_ORB));
4219 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4220 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4222 IS_CUSTOM_ELEMENT(i)));
4224 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4225 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4226 i == EL_SP_ELECTRON));
4228 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4229 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4230 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4231 getMoveIntoAcidProperty(&level, i));
4233 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4234 if (MAYBE_DONT_COLLIDE_WITH(i))
4235 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4236 getDontCollideWithProperty(&level, i));
4238 /* ---------- SP_PORT -------------------------------------------------- */
4239 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4240 IS_PASSABLE_INSIDE(i)));
4242 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4243 for (j = 0; j < level.num_android_clone_elements; j++)
4244 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4246 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4248 /* ---------- CAN_CHANGE ----------------------------------------------- */
4249 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4250 for (j = 0; j < element_info[i].num_change_pages; j++)
4251 if (element_info[i].change_page[j].can_change)
4252 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4254 /* ---------- HAS_ACTION ----------------------------------------------- */
4255 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4256 for (j = 0; j < element_info[i].num_change_pages; j++)
4257 if (element_info[i].change_page[j].has_action)
4258 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4260 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4261 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4264 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4266 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4267 element_info[i].crumbled[ACTION_DEFAULT] !=
4268 element_info[i].graphic[ACTION_DEFAULT]);
4270 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
4271 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4272 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
4275 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4276 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4277 IS_EDITOR_CASCADE_INACTIVE(i)));
4280 /* dynamically adjust element properties according to game engine version */
4282 static int ep_em_slippery_wall[] =
4287 EL_EXPANDABLE_WALL_HORIZONTAL,
4288 EL_EXPANDABLE_WALL_VERTICAL,
4289 EL_EXPANDABLE_WALL_ANY,
4290 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4291 EL_EXPANDABLE_STEELWALL_VERTICAL,
4292 EL_EXPANDABLE_STEELWALL_ANY,
4293 EL_EXPANDABLE_STEELWALL_GROWING,
4297 /* special EM style gems behaviour */
4298 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4299 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4300 level.em_slippery_gems);
4302 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4303 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4304 (level.em_slippery_gems &&
4305 engine_version > VERSION_IDENT(2,0,1,0)));
4308 /* this is needed because some graphics depend on element properties */
4309 if (game_status == GAME_MODE_PLAYING)
4310 InitElementGraphicInfo();
4313 void InitElementPropertiesAfterLoading(int engine_version)
4317 /* set some other uninitialized values of custom elements in older levels */
4318 if (engine_version < VERSION_IDENT(3,1,0,0))
4320 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4322 int element = EL_CUSTOM_START + i;
4324 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4326 element_info[element].explosion_delay = 17;
4327 element_info[element].ignition_delay = 8;
4332 static void InitGlobal()
4336 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4338 /* check if element_name_info entry defined for each element in "main.h" */
4339 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4340 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4342 element_info[i].token_name = element_name_info[i].token_name;
4343 element_info[i].class_name = element_name_info[i].class_name;
4344 element_info[i].editor_description=element_name_info[i].editor_description;
4347 printf("%04d: %s\n", i, element_name_info[i].token_name);
4351 global.autoplay_leveldir = NULL;
4352 global.convert_leveldir = NULL;
4354 global.frames_per_second = 0;
4355 global.fps_slowdown = FALSE;
4356 global.fps_slowdown_factor = 1;
4359 void Execute_Command(char *command)
4363 if (strEqual(command, "print graphicsinfo.conf"))
4365 printf("# You can configure additional/alternative image files here.\n");
4366 printf("# (The entries below are default and therefore commented out.)\n");
4368 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4370 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4373 for (i = 0; image_config[i].token != NULL; i++)
4374 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
4375 image_config[i].value));
4379 else if (strEqual(command, "print soundsinfo.conf"))
4381 printf("# You can configure additional/alternative sound files here.\n");
4382 printf("# (The entries below are default and therefore commented out.)\n");
4384 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4386 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4389 for (i = 0; sound_config[i].token != NULL; i++)
4390 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4391 sound_config[i].value));
4395 else if (strEqual(command, "print musicinfo.conf"))
4397 printf("# You can configure additional/alternative music files here.\n");
4398 printf("# (The entries below are default and therefore commented out.)\n");
4400 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4402 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4405 for (i = 0; music_config[i].token != NULL; i++)
4406 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
4407 music_config[i].value));
4411 else if (strEqual(command, "print editorsetup.conf"))
4413 printf("# You can configure your personal editor element list here.\n");
4414 printf("# (The entries below are default and therefore commented out.)\n");
4417 /* this is needed to be able to check element list for cascade elements */
4418 InitElementPropertiesStatic();
4419 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4421 PrintEditorElementList();
4425 else if (strEqual(command, "print helpanim.conf"))
4427 printf("# You can configure different element help animations here.\n");
4428 printf("# (The entries below are default and therefore commented out.)\n");
4431 for (i = 0; helpanim_config[i].token != NULL; i++)
4433 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4434 helpanim_config[i].value));
4436 if (strEqual(helpanim_config[i].token, "end"))
4442 else if (strEqual(command, "print helptext.conf"))
4444 printf("# You can configure different element help text here.\n");
4445 printf("# (The entries below are default and therefore commented out.)\n");
4448 for (i = 0; helptext_config[i].token != NULL; i++)
4449 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4450 helptext_config[i].value));
4454 else if (strncmp(command, "dump level ", 11) == 0)
4456 char *filename = &command[11];
4458 if (!fileExists(filename))
4459 Error(ERR_EXIT, "cannot open file '%s'", filename);
4461 LoadLevelFromFilename(&level, filename);
4466 else if (strncmp(command, "dump tape ", 10) == 0)
4468 char *filename = &command[10];
4470 if (!fileExists(filename))
4471 Error(ERR_EXIT, "cannot open file '%s'", filename);
4473 LoadTapeFromFilename(filename);
4478 else if (strncmp(command, "autoplay ", 9) == 0)
4480 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
4482 while (*str_ptr != '\0') /* continue parsing string */
4484 /* cut leading whitespace from string, replace it by string terminator */
4485 while (*str_ptr == ' ' || *str_ptr == '\t')
4488 if (*str_ptr == '\0') /* end of string reached */
4491 if (global.autoplay_leveldir == NULL) /* read level set string */
4493 global.autoplay_leveldir = str_ptr;
4494 global.autoplay_all = TRUE; /* default: play all tapes */
4496 for (i = 0; i < MAX_TAPES_PER_SET; i++)
4497 global.autoplay_level[i] = FALSE;
4499 else /* read level number string */
4501 int level_nr = atoi(str_ptr); /* get level_nr value */
4503 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
4504 global.autoplay_level[level_nr] = TRUE;
4506 global.autoplay_all = FALSE;
4509 /* advance string pointer to the next whitespace (or end of string) */
4510 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
4514 else if (strncmp(command, "convert ", 8) == 0)
4516 char *str_copy = getStringCopy(&command[8]);
4517 char *str_ptr = strchr(str_copy, ' ');
4519 global.convert_leveldir = str_copy;
4520 global.convert_level_nr = -1;
4522 if (str_ptr != NULL) /* level number follows */
4524 *str_ptr++ = '\0'; /* terminate leveldir string */
4525 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
4530 #if defined(TARGET_SDL)
4531 else if (strEqual(command, "SDL_ListModes"))
4536 SDL_Init(SDL_INIT_VIDEO);
4538 /* get available fullscreen/hardware modes */
4539 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
4541 /* check if there are any modes available */
4544 printf("No modes available!\n");
4549 /* check if our resolution is restricted */
4550 if (modes == (SDL_Rect **)-1)
4552 printf("All resolutions available.\n");
4556 printf("Available Modes:\n");
4558 for(i = 0; modes[i]; i++)
4559 printf(" %d x %d\n", modes[i]->w, modes[i]->h);
4569 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4573 static void InitSetup()
4575 LoadSetup(); /* global setup info */
4577 /* set some options from setup file */
4579 if (setup.options.verbose)
4580 options.verbose = TRUE;
4583 static void InitGameInfo()
4585 game.restart_level = FALSE;
4588 static void InitPlayerInfo()
4592 /* choose default local player */
4593 local_player = &stored_player[0];
4595 for (i = 0; i < MAX_PLAYERS; i++)
4596 stored_player[i].connected = FALSE;
4598 local_player->connected = TRUE;
4601 static void InitArtworkInfo()
4606 static char *get_string_in_brackets(char *string)
4608 char *string_in_brackets = checked_malloc(strlen(string) + 3);
4610 sprintf(string_in_brackets, "[%s]", string);
4612 return string_in_brackets;
4615 static char *get_level_id_suffix(int id_nr)
4617 char *id_suffix = checked_malloc(1 + 3 + 1);
4619 if (id_nr < 0 || id_nr > 999)
4622 sprintf(id_suffix, ".%03d", id_nr);
4628 static char *get_element_class_token(int element)
4630 char *element_class_name = element_info[element].class_name;
4631 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
4633 sprintf(element_class_token, "[%s]", element_class_name);
4635 return element_class_token;
4638 static char *get_action_class_token(int action)
4640 char *action_class_name = &element_action_info[action].suffix[1];
4641 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
4643 sprintf(action_class_token, "[%s]", action_class_name);
4645 return action_class_token;
4649 static void InitArtworkConfig()
4651 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
4652 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
4653 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
4654 static char *action_id_suffix[NUM_ACTIONS + 1];
4655 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
4656 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
4657 static char *level_id_suffix[MAX_LEVELS + 1];
4658 static char *dummy[1] = { NULL };
4659 static char *ignore_generic_tokens[] =
4665 static char **ignore_image_tokens;
4666 static char **ignore_sound_tokens;
4667 static char **ignore_music_tokens;
4668 int num_ignore_generic_tokens;
4669 int num_ignore_image_tokens;
4670 int num_ignore_sound_tokens;
4671 int num_ignore_music_tokens;
4674 /* dynamically determine list of generic tokens to be ignored */
4675 num_ignore_generic_tokens = 0;
4676 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
4677 num_ignore_generic_tokens++;
4679 /* dynamically determine list of image tokens to be ignored */
4680 num_ignore_image_tokens = num_ignore_generic_tokens;
4681 for (i = 0; image_config_vars[i].token != NULL; i++)
4682 num_ignore_image_tokens++;
4683 ignore_image_tokens =
4684 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
4685 for (i = 0; i < num_ignore_generic_tokens; i++)
4686 ignore_image_tokens[i] = ignore_generic_tokens[i];
4687 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
4688 ignore_image_tokens[num_ignore_generic_tokens + i] =
4689 image_config_vars[i].token;
4690 ignore_image_tokens[num_ignore_image_tokens] = NULL;
4692 /* dynamically determine list of sound tokens to be ignored */
4693 num_ignore_sound_tokens = num_ignore_generic_tokens;
4694 ignore_sound_tokens =
4695 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
4696 for (i = 0; i < num_ignore_generic_tokens; i++)
4697 ignore_sound_tokens[i] = ignore_generic_tokens[i];
4698 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
4700 /* dynamically determine list of music tokens to be ignored */
4701 num_ignore_music_tokens = num_ignore_generic_tokens;
4702 ignore_music_tokens =
4703 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
4704 for (i = 0; i < num_ignore_generic_tokens; i++)
4705 ignore_music_tokens[i] = ignore_generic_tokens[i];
4706 ignore_music_tokens[num_ignore_music_tokens] = NULL;
4708 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4709 image_id_prefix[i] = element_info[i].token_name;
4710 for (i = 0; i < NUM_FONTS; i++)
4711 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
4712 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
4714 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4715 sound_id_prefix[i] = element_info[i].token_name;
4716 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4717 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
4718 get_string_in_brackets(element_info[i].class_name);
4719 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
4721 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
4722 music_id_prefix[i] = music_prefix_info[i].prefix;
4723 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
4725 for (i = 0; i < NUM_ACTIONS; i++)
4726 action_id_suffix[i] = element_action_info[i].suffix;
4727 action_id_suffix[NUM_ACTIONS] = NULL;
4729 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
4730 direction_id_suffix[i] = element_direction_info[i].suffix;
4731 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
4733 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
4734 special_id_suffix[i] = special_suffix_info[i].suffix;
4735 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
4737 for (i = 0; i < MAX_LEVELS; i++)
4738 level_id_suffix[i] = get_level_id_suffix(i);
4739 level_id_suffix[MAX_LEVELS] = NULL;
4741 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
4742 image_id_prefix, action_id_suffix, direction_id_suffix,
4743 special_id_suffix, ignore_image_tokens);
4744 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
4745 sound_id_prefix, action_id_suffix, dummy,
4746 special_id_suffix, ignore_sound_tokens);
4747 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
4748 music_id_prefix, special_id_suffix, level_id_suffix,
4749 dummy, ignore_music_tokens);
4752 static void InitMixer()
4760 char *filename_font_initial = NULL;
4761 Bitmap *bitmap_font_initial = NULL;
4765 /* determine settings for initial font (for displaying startup messages) */
4766 for (i = 0; image_config[i].token != NULL; i++)
4768 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4770 char font_token[128];
4773 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
4774 len_font_token = strlen(font_token);
4776 if (strEqual(image_config[i].token, font_token))
4777 filename_font_initial = image_config[i].value;
4778 else if (strlen(image_config[i].token) > len_font_token &&
4779 strncmp(image_config[i].token, font_token, len_font_token) == 0)
4781 if (strEqual(&image_config[i].token[len_font_token], ".x"))
4782 font_initial[j].src_x = atoi(image_config[i].value);
4783 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
4784 font_initial[j].src_y = atoi(image_config[i].value);
4785 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
4786 font_initial[j].width = atoi(image_config[i].value);
4787 else if (strEqual(&image_config[i].token[len_font_token],".height"))
4788 font_initial[j].height = atoi(image_config[i].value);
4793 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4795 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
4796 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
4799 if (filename_font_initial == NULL) /* should not happen */
4800 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
4802 /* create additional image buffers for double-buffering and cross-fading */
4803 bitmap_db_cross = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
4804 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
4805 bitmap_db_panel = CreateBitmap(DXSIZE, DYSIZE, DEFAULT_DEPTH);
4806 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
4808 /* initialize screen properties */
4809 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
4810 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
4812 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
4813 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
4814 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
4816 bitmap_font_initial = LoadCustomImage(filename_font_initial);
4818 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4819 font_initial[j].bitmap = bitmap_font_initial;
4821 InitFontGraphicInfo();
4823 font_height = getFontHeight(FC_RED);
4826 DrawInitText(getWindowTitleString(), 20, FC_YELLOW);
4828 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
4830 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
4831 DrawInitText(PROGRAM_WEBSITE_STRING, WIN_YSIZE - 20 - font_height, FC_RED);
4833 DrawInitText("Loading graphics", 120, FC_GREEN);
4836 void RedrawBackground()
4838 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
4839 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
4841 redraw_mask = REDRAW_ALL;
4844 void InitGfxBackground()
4848 fieldbuffer = bitmap_db_field;
4849 SetDrawtoField(DRAW_BACKBUFFER);
4853 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
4854 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
4856 for (x = 0; x < MAX_BUF_XSIZE; x++)
4857 for (y = 0; y < MAX_BUF_YSIZE; y++)
4860 redraw_mask = REDRAW_ALL;
4863 static void InitLevelInfo()
4865 LoadLevelInfo(); /* global level info */
4866 LoadLevelSetup_LastSeries(); /* last played series info */
4867 LoadLevelSetup_SeriesInfo(); /* last played level info */
4870 void InitLevelArtworkInfo()
4872 LoadLevelArtworkInfo();
4875 static void InitImages()
4877 setLevelArtworkDir(artwork.gfx_first);
4880 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
4881 leveldir_current->identifier,
4882 artwork.gfx_current_identifier,
4883 artwork.gfx_current->identifier,
4884 leveldir_current->graphics_set,
4885 leveldir_current->graphics_path);
4888 ReloadCustomImages();
4890 LoadCustomElementDescriptions();
4891 LoadSpecialMenuDesignSettings();
4893 ReinitializeGraphics();
4896 static void InitSound(char *identifier)
4898 if (identifier == NULL)
4899 identifier = artwork.snd_current->identifier;
4901 /* set artwork path to send it to the sound server process */
4902 setLevelArtworkDir(artwork.snd_first);
4904 InitReloadCustomSounds(identifier);
4905 ReinitializeSounds();
4908 static void InitMusic(char *identifier)
4910 if (identifier == NULL)
4911 identifier = artwork.mus_current->identifier;
4913 /* set artwork path to send it to the sound server process */
4914 setLevelArtworkDir(artwork.mus_first);
4916 InitReloadCustomMusic(identifier);
4917 ReinitializeMusic();
4920 void InitNetworkServer()
4922 #if defined(NETWORK_AVALIABLE)
4926 if (!options.network)
4929 #if defined(NETWORK_AVALIABLE)
4930 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
4932 if (!ConnectToServer(options.server_host, options.server_port))
4933 Error(ERR_EXIT, "cannot connect to network game server");
4935 SendToServer_PlayerName(setup.player_name);
4936 SendToServer_ProtocolVersion();
4939 SendToServer_NrWanted(nr_wanted);
4943 static char *getNewArtworkIdentifier(int type)
4945 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
4946 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
4947 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
4948 static boolean initialized[3] = { FALSE, FALSE, FALSE };
4949 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
4950 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
4951 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
4952 char *leveldir_identifier = leveldir_current->identifier;
4954 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
4955 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
4957 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
4959 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
4960 char *artwork_current_identifier;
4961 char *artwork_new_identifier = NULL; /* default: nothing has changed */
4963 /* leveldir_current may be invalid (level group, parent link) */
4964 if (!validLevelSeries(leveldir_current))
4967 /* 1st step: determine artwork set to be activated in descending order:
4968 --------------------------------------------------------------------
4969 1. setup artwork (when configured to override everything else)
4970 2. artwork set configured in "levelinfo.conf" of current level set
4971 (artwork in level directory will have priority when loading later)
4972 3. artwork in level directory (stored in artwork sub-directory)
4973 4. setup artwork (currently configured in setup menu) */
4975 if (setup_override_artwork)
4976 artwork_current_identifier = setup_artwork_set;
4977 else if (leveldir_artwork_set != NULL)
4978 artwork_current_identifier = leveldir_artwork_set;
4979 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
4980 artwork_current_identifier = leveldir_identifier;
4982 artwork_current_identifier = setup_artwork_set;
4985 /* 2nd step: check if it is really needed to reload artwork set
4986 ------------------------------------------------------------ */
4989 if (type == ARTWORK_TYPE_GRAPHICS)
4990 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
4991 artwork_new_identifier,
4992 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4993 artwork_current_identifier,
4994 leveldir_current->graphics_set,
4995 leveldir_current->identifier);
4998 /* ---------- reload if level set and also artwork set has changed ------- */
4999 if (leveldir_current_identifier[type] != leveldir_identifier &&
5000 (last_has_level_artwork_set[type] || has_level_artwork_set))
5001 artwork_new_identifier = artwork_current_identifier;
5003 leveldir_current_identifier[type] = leveldir_identifier;
5004 last_has_level_artwork_set[type] = has_level_artwork_set;
5007 if (type == ARTWORK_TYPE_GRAPHICS)
5008 printf("::: 1: '%s'\n", artwork_new_identifier);
5011 /* ---------- reload if "override artwork" setting has changed ----------- */
5012 if (last_override_level_artwork[type] != setup_override_artwork)
5013 artwork_new_identifier = artwork_current_identifier;
5015 last_override_level_artwork[type] = setup_override_artwork;
5018 if (type == ARTWORK_TYPE_GRAPHICS)
5019 printf("::: 2: '%s'\n", artwork_new_identifier);
5022 /* ---------- reload if current artwork identifier has changed ----------- */
5023 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5024 artwork_current_identifier))
5025 artwork_new_identifier = artwork_current_identifier;
5027 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5030 if (type == ARTWORK_TYPE_GRAPHICS)
5031 printf("::: 3: '%s'\n", artwork_new_identifier);
5034 /* ---------- do not reload directly after starting ---------------------- */
5035 if (!initialized[type])
5036 artwork_new_identifier = NULL;
5038 initialized[type] = TRUE;
5041 if (type == ARTWORK_TYPE_GRAPHICS)
5042 printf("::: 4: '%s'\n", artwork_new_identifier);
5046 if (type == ARTWORK_TYPE_GRAPHICS)
5047 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
5048 artwork.gfx_current_identifier, artwork_current_identifier,
5049 artwork.gfx_current->identifier, leveldir_current->graphics_set,
5050 artwork_new_identifier);
5053 return artwork_new_identifier;
5056 void ReloadCustomArtwork(int force_reload)
5058 char *gfx_new_identifier;
5059 char *snd_new_identifier;
5060 char *mus_new_identifier;
5061 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5062 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5063 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5064 boolean redraw_screen = FALSE;
5066 force_reload_gfx |= AdjustGraphicsForEMC();
5068 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5069 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5070 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5072 if (gfx_new_identifier != NULL || force_reload_gfx)
5075 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5076 artwork.gfx_current_identifier,
5078 artwork.gfx_current->identifier,
5079 leveldir_current->graphics_set);
5082 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
5086 redraw_screen = TRUE;
5089 if (snd_new_identifier != NULL || force_reload_snd)
5091 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
5093 InitSound(snd_new_identifier);
5095 redraw_screen = TRUE;
5098 if (mus_new_identifier != NULL || force_reload_mus)
5100 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
5102 InitMusic(mus_new_identifier);
5104 redraw_screen = TRUE;
5111 /* force redraw of (open or closed) door graphics */
5112 SetDoorState(DOOR_OPEN_ALL);
5113 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5115 fading = fading_none;
5119 void KeyboardAutoRepeatOffUnlessAutoplay()
5121 if (global.autoplay_leveldir == NULL)
5122 KeyboardAutoRepeatOff();
5126 /* ========================================================================= */
5128 /* ========================================================================= */
5132 InitGlobal(); /* initialize some global variables */
5134 if (options.execute_command)
5135 Execute_Command(options.execute_command);
5137 if (options.serveronly)
5139 #if defined(PLATFORM_UNIX)
5140 NetworkServer(options.server_port, options.serveronly);
5142 Error(ERR_WARN, "networking only supported in Unix version");
5145 exit(0); /* never reached, server loops forever */
5152 InitArtworkInfo(); /* needed before loading gfx, sound & music */
5153 InitArtworkConfig(); /* needed before forking sound child process */
5158 InitRND(NEW_RANDOMIZE);
5159 InitSimpleRandom(NEW_RANDOMIZE);
5164 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
5166 InitEventFilter(FilterMouseMotionEvents);
5168 InitElementPropertiesStatic();
5169 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5173 // debug_print_timestamp(0, "INIT");
5175 // debug_print_timestamp(0, "TIME InitLevelInfo: ");
5176 InitLevelArtworkInfo();
5177 // debug_print_timestamp(0, "TIME InitLevelArtworkInfo: ");
5179 InitImages(); /* needs to know current level directory */
5180 InitSound(NULL); /* needs to know current level directory */
5181 InitMusic(NULL); /* needs to know current level directory */
5183 InitGfxBackground();
5189 if (global.autoplay_leveldir)
5194 else if (global.convert_leveldir)
5200 fading = fading_none;
5202 game_status = GAME_MODE_MAIN;
5206 InitNetworkServer();
5209 void CloseAllAndExit(int exit_value)
5214 CloseAudio(); /* called after freeing sounds (needed for SDL) */
5222 #if defined(TARGET_SDL)
5223 if (network_server) /* terminate network server */
5224 SDL_KillThread(server_thread);
5227 CloseVideoDisplay();
5228 ClosePlatformDependentStuff();
5230 if (exit_value != 0)
5231 NotifyUserAboutErrorFile();