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_mode = FADE_MODE_DEFAULT;
1036 graphic_info[graphic].fade_delay = -1;
1037 graphic_info[graphic].post_delay = -1;
1038 graphic_info[graphic].auto_delay = -1;
1039 graphic_info[graphic].align = ALIGN_CENTER; /* default for title screens */
1040 graphic_info[graphic].valign = VALIGN_MIDDLE; /* default for title screens */
1041 graphic_info[graphic].sort_priority = 0; /* default for title screens */
1044 /* optional zoom factor for scaling up the image to a larger size */
1045 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1046 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1047 if (graphic_info[graphic].scale_up_factor < 1)
1048 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
1052 if (graphic_info[graphic].use_image_size)
1054 /* set new default bitmap size (with scaling, but without small images) */
1055 graphic_info[graphic].width = get_scaled_graphic_width(graphic);
1056 graphic_info[graphic].height = get_scaled_graphic_height(graphic);
1060 /* optional x and y tile position of animation frame sequence */
1061 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1062 graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
1063 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1064 graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
1066 /* optional x and y pixel position of animation frame sequence */
1067 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1068 graphic_info[graphic].src_x = parameter[GFX_ARG_X];
1069 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1070 graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
1072 /* optional width and height of each animation frame */
1073 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1074 graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
1075 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1076 graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
1079 /* optional zoom factor for scaling up the image to a larger size */
1080 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1081 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1082 if (graphic_info[graphic].scale_up_factor < 1)
1083 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
1088 /* get final bitmap size (with scaling, but without small images) */
1089 int src_image_width = get_scaled_graphic_width(graphic);
1090 int src_image_height = get_scaled_graphic_height(graphic);
1092 anim_frames_per_row = src_image_width / graphic_info[graphic].width;
1093 anim_frames_per_col = src_image_height / graphic_info[graphic].height;
1095 graphic_info[graphic].src_image_width = src_image_width;
1096 graphic_info[graphic].src_image_height = src_image_height;
1099 /* correct x or y offset dependent of vertical or horizontal frame order */
1100 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1102 graphic_info[graphic].offset_y =
1103 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1104 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
1105 anim_frames_per_line = anim_frames_per_col;
1107 else /* frames are ordered horizontally */
1109 graphic_info[graphic].offset_x =
1110 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1111 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
1112 anim_frames_per_line = anim_frames_per_row;
1115 /* optionally, the x and y offset of frames can be specified directly */
1116 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1117 graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
1118 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1119 graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
1121 /* optionally, moving animations may have separate start and end graphics */
1122 graphic_info[graphic].double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1124 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1125 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1127 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1128 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1129 graphic_info[graphic].offset2_y =
1130 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1131 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].height);
1132 else /* frames are ordered horizontally */
1133 graphic_info[graphic].offset2_x =
1134 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1135 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].width);
1137 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1138 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1139 graphic_info[graphic].offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1140 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1141 graphic_info[graphic].offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1143 /* optionally, the second movement tile can be specified as start tile */
1144 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1145 graphic_info[graphic].swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1147 /* automatically determine correct number of frames, if not defined */
1148 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1149 graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
1150 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1151 graphic_info[graphic].anim_frames = anim_frames_per_row;
1152 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1153 graphic_info[graphic].anim_frames = anim_frames_per_col;
1155 graphic_info[graphic].anim_frames = 1;
1157 if (graphic_info[graphic].anim_frames == 0) /* frames must be at least 1 */
1158 graphic_info[graphic].anim_frames = 1;
1160 graphic_info[graphic].anim_frames_per_line =
1161 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1162 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1164 graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
1165 if (graphic_info[graphic].anim_delay == 0) /* delay must be at least 1 */
1166 graphic_info[graphic].anim_delay = 1;
1168 graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
1170 if (graphic_info[graphic].anim_frames == 1)
1171 graphic_info[graphic].anim_mode = ANIM_NONE;
1174 /* automatically determine correct start frame, if not defined */
1175 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1176 graphic_info[graphic].anim_start_frame = 0;
1177 else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
1178 graphic_info[graphic].anim_start_frame =
1179 graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1181 graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
1183 /* animation synchronized with global frame counter, not move position */
1184 graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1186 /* optional element for cloning crumble graphics */
1187 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1188 graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1190 /* optional element for cloning digging graphics */
1191 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1192 graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1194 /* optional border size for "crumbling" diggable graphics */
1195 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1196 graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
1198 /* this is only used for player "boring" and "sleeping" actions */
1199 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1200 graphic_info[graphic].anim_delay_fixed =
1201 parameter[GFX_ARG_ANIM_DELAY_FIXED];
1202 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1203 graphic_info[graphic].anim_delay_random =
1204 parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1205 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1206 graphic_info[graphic].post_delay_fixed =
1207 parameter[GFX_ARG_POST_DELAY_FIXED];
1208 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1209 graphic_info[graphic].post_delay_random =
1210 parameter[GFX_ARG_POST_DELAY_RANDOM];
1212 /* this is only used for toon animations */
1213 graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
1214 graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY];
1216 /* this is only used for drawing font characters */
1217 graphic_info[graphic].draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1218 graphic_info[graphic].draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1220 /* this is only used for drawing envelope graphics */
1221 graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1223 /* optional graphic for cloning all graphics settings */
1224 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1225 graphic_info[graphic].clone_from = parameter[GFX_ARG_CLONE_FROM];
1227 /* optional settings for drawing title screens and title messages */
1228 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1229 graphic_info[graphic].fade_mode = parameter[GFX_ARG_FADE_MODE];
1230 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1231 graphic_info[graphic].fade_delay = parameter[GFX_ARG_FADE_DELAY];
1232 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1233 graphic_info[graphic].post_delay = parameter[GFX_ARG_POST_DELAY];
1234 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1235 graphic_info[graphic].auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1236 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1237 graphic_info[graphic].align = parameter[GFX_ARG_ALIGN];
1238 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1239 graphic_info[graphic].valign = parameter[GFX_ARG_VALIGN];
1240 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1241 graphic_info[graphic].sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1244 static void set_cloned_graphic_parameters(int graphic)
1246 int fallback_graphic = IMG_CHAR_EXCLAM;
1247 int max_num_images = getImageListSize();
1248 int clone_graphic = graphic_info[graphic].clone_from;
1249 int num_references_followed = 1;
1251 while (graphic_info[clone_graphic].clone_from != -1 &&
1252 num_references_followed < max_num_images)
1254 clone_graphic = graphic_info[clone_graphic].clone_from;
1256 num_references_followed++;
1259 if (num_references_followed >= max_num_images)
1261 Error(ERR_INFO_LINE, "-");
1262 Error(ERR_INFO, "warning: error found in config file:");
1263 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1264 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1265 Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1266 Error(ERR_INFO, "custom graphic rejected for this element/action");
1268 if (graphic == fallback_graphic)
1269 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1271 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1272 Error(ERR_INFO_LINE, "-");
1274 graphic_info[graphic] = graphic_info[fallback_graphic];
1278 graphic_info[graphic] = graphic_info[clone_graphic];
1279 graphic_info[graphic].clone_from = clone_graphic;
1283 static void InitGraphicInfo()
1285 int fallback_graphic = IMG_CHAR_EXCLAM;
1286 int num_images = getImageListSize();
1289 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1290 static boolean clipmasks_initialized = FALSE;
1292 XGCValues clip_gc_values;
1293 unsigned long clip_gc_valuemask;
1294 GC copy_clipmask_gc = None;
1297 /* use image size as default values for width and height for these images */
1298 static int full_size_graphics[] =
1303 IMG_BACKGROUND_ENVELOPE_1,
1304 IMG_BACKGROUND_ENVELOPE_2,
1305 IMG_BACKGROUND_ENVELOPE_3,
1306 IMG_BACKGROUND_ENVELOPE_4,
1309 IMG_BACKGROUND_TITLE_INITIAL,
1310 IMG_BACKGROUND_TITLE,
1311 IMG_BACKGROUND_MAIN,
1312 IMG_BACKGROUND_LEVELS,
1313 IMG_BACKGROUND_SCORES,
1314 IMG_BACKGROUND_EDITOR,
1315 IMG_BACKGROUND_INFO,
1316 IMG_BACKGROUND_INFO_ELEMENTS,
1317 IMG_BACKGROUND_INFO_MUSIC,
1318 IMG_BACKGROUND_INFO_CREDITS,
1319 IMG_BACKGROUND_INFO_PROGRAM,
1320 IMG_BACKGROUND_INFO_LEVELSET,
1321 IMG_BACKGROUND_SETUP,
1322 IMG_BACKGROUND_DOOR,
1324 IMG_TITLESCREEN_INITIAL_1,
1325 IMG_TITLESCREEN_INITIAL_2,
1326 IMG_TITLESCREEN_INITIAL_3,
1327 IMG_TITLESCREEN_INITIAL_4,
1328 IMG_TITLESCREEN_INITIAL_5,
1338 checked_free(graphic_info);
1340 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1343 /* initialize "use_image_size" flag with default value */
1344 for (i = 0; i < num_images; i++)
1345 graphic_info[i].use_image_size = FALSE;
1347 /* initialize "use_image_size" flag from static configuration above */
1348 for (i = 0; full_size_graphics[i] != -1; i++)
1349 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1352 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1353 if (clipmasks_initialized)
1355 for (i = 0; i < num_images; i++)
1357 if (graphic_info[i].clip_mask)
1358 XFreePixmap(display, graphic_info[i].clip_mask);
1359 if (graphic_info[i].clip_gc)
1360 XFreeGC(display, graphic_info[i].clip_gc);
1362 graphic_info[i].clip_mask = None;
1363 graphic_info[i].clip_gc = None;
1368 /* first set all graphic paramaters ... */
1369 for (i = 0; i < num_images; i++)
1370 set_graphic_parameters(i);
1372 /* ... then copy these parameters for cloned graphics */
1373 for (i = 0; i < num_images; i++)
1374 if (graphic_info[i].clone_from != -1)
1375 set_cloned_graphic_parameters(i);
1377 for (i = 0; i < num_images; i++)
1382 int first_frame, last_frame;
1383 int src_bitmap_width, src_bitmap_height;
1385 /* now check if no animation frames are outside of the loaded image */
1387 if (graphic_info[i].bitmap == NULL)
1388 continue; /* skip check for optional images that are undefined */
1390 /* get image size (this can differ from the standard element tile size!) */
1391 width = graphic_info[i].width;
1392 height = graphic_info[i].height;
1394 /* get final bitmap size (with scaling, but without small images) */
1395 src_bitmap_width = graphic_info[i].src_image_width;
1396 src_bitmap_height = graphic_info[i].src_image_height;
1398 /* check if first animation frame is inside specified bitmap */
1401 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1404 /* this avoids calculating wrong start position for out-of-bounds frame */
1405 src_x = graphic_info[i].src_x;
1406 src_y = graphic_info[i].src_y;
1409 if (src_x < 0 || src_y < 0 ||
1410 src_x + width > src_bitmap_width ||
1411 src_y + height > src_bitmap_height)
1413 Error(ERR_INFO_LINE, "-");
1414 Error(ERR_INFO, "warning: error found in config file:");
1415 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1416 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1417 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1419 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1420 src_x, src_y, src_bitmap_width, src_bitmap_height);
1421 Error(ERR_INFO, "custom graphic rejected for this element/action");
1423 if (i == fallback_graphic)
1424 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1426 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1427 Error(ERR_INFO_LINE, "-");
1429 graphic_info[i] = graphic_info[fallback_graphic];
1432 /* check if last animation frame is inside specified bitmap */
1434 last_frame = graphic_info[i].anim_frames - 1;
1435 getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1437 if (src_x < 0 || src_y < 0 ||
1438 src_x + width > src_bitmap_width ||
1439 src_y + height > src_bitmap_height)
1441 Error(ERR_INFO_LINE, "-");
1442 Error(ERR_INFO, "warning: error found in config file:");
1443 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1444 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1445 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1447 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1448 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1449 Error(ERR_INFO, "custom graphic rejected for this element/action");
1451 if (i == fallback_graphic)
1452 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1454 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1455 Error(ERR_INFO_LINE, "-");
1457 graphic_info[i] = graphic_info[fallback_graphic];
1460 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1461 /* currently we only need a tile clip mask from the first frame */
1462 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1464 if (copy_clipmask_gc == None)
1466 clip_gc_values.graphics_exposures = False;
1467 clip_gc_valuemask = GCGraphicsExposures;
1468 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
1469 clip_gc_valuemask, &clip_gc_values);
1472 graphic_info[i].clip_mask =
1473 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
1475 src_pixmap = src_bitmap->clip_mask;
1476 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
1477 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
1479 clip_gc_values.graphics_exposures = False;
1480 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
1481 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
1483 graphic_info[i].clip_gc =
1484 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
1488 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1489 if (copy_clipmask_gc)
1490 XFreeGC(display, copy_clipmask_gc);
1492 clipmasks_initialized = TRUE;
1496 static void InitElementSoundInfo()
1498 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1499 int num_property_mappings = getSoundListPropertyMappingSize();
1502 /* set values to -1 to identify later as "uninitialized" values */
1503 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1504 for (act = 0; act < NUM_ACTIONS; act++)
1505 element_info[i].sound[act] = -1;
1507 /* initialize element/sound mapping from static configuration */
1508 for (i = 0; element_to_sound[i].element > -1; i++)
1510 int element = element_to_sound[i].element;
1511 int action = element_to_sound[i].action;
1512 int sound = element_to_sound[i].sound;
1513 boolean is_class = element_to_sound[i].is_class;
1516 action = ACTION_DEFAULT;
1519 element_info[element].sound[action] = sound;
1521 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1522 if (strEqual(element_info[j].class_name,
1523 element_info[element].class_name))
1524 element_info[j].sound[action] = sound;
1527 /* initialize element class/sound mapping from dynamic configuration */
1528 for (i = 0; i < num_property_mappings; i++)
1530 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1531 int action = property_mapping[i].ext1_index;
1532 int sound = property_mapping[i].artwork_index;
1534 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1538 action = ACTION_DEFAULT;
1540 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1541 if (strEqual(element_info[j].class_name,
1542 element_info[element_class].class_name))
1543 element_info[j].sound[action] = sound;
1546 /* initialize element/sound mapping from dynamic configuration */
1547 for (i = 0; i < num_property_mappings; i++)
1549 int element = property_mapping[i].base_index;
1550 int action = property_mapping[i].ext1_index;
1551 int sound = property_mapping[i].artwork_index;
1553 if (element >= MAX_NUM_ELEMENTS)
1557 action = ACTION_DEFAULT;
1559 element_info[element].sound[action] = sound;
1562 /* now set all '-1' values to element specific default values */
1563 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1565 for (act = 0; act < NUM_ACTIONS; act++)
1567 /* generic default action sound (defined by "[default]" directive) */
1568 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1570 /* look for special default action sound (classic game specific) */
1571 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1572 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1573 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1574 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1575 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1576 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1578 /* !!! there's no such thing as a "default action sound" !!! */
1580 /* look for element specific default sound (independent from action) */
1581 if (element_info[i].sound[ACTION_DEFAULT] != -1)
1582 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
1586 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1587 /* !!! make this better !!! */
1588 if (i == EL_EMPTY_SPACE)
1589 default_action_sound = element_info[EL_DEFAULT].sound[act];
1592 /* no sound for this specific action -- use default action sound */
1593 if (element_info[i].sound[act] == -1)
1594 element_info[i].sound[act] = default_action_sound;
1598 /* copy sound settings to some elements that are only stored in level file
1599 in native R'n'D levels, but are used by game engine in native EM levels */
1600 for (i = 0; copy_properties[i][0] != -1; i++)
1601 for (j = 1; j <= 4; j++)
1602 for (act = 0; act < NUM_ACTIONS; act++)
1603 element_info[copy_properties[i][j]].sound[act] =
1604 element_info[copy_properties[i][0]].sound[act];
1607 static void InitGameModeSoundInfo()
1611 /* set values to -1 to identify later as "uninitialized" values */
1612 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1615 /* initialize gamemode/sound mapping from static configuration */
1616 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1618 int gamemode = gamemode_to_sound[i].gamemode;
1619 int sound = gamemode_to_sound[i].sound;
1622 gamemode = GAME_MODE_DEFAULT;
1624 menu.sound[gamemode] = sound;
1627 /* now set all '-1' values to levelset specific default values */
1628 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1629 if (menu.sound[i] == -1)
1630 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1633 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1634 if (menu.sound[i] != -1)
1635 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
1639 static void set_sound_parameters(int sound, char **parameter_raw)
1641 int parameter[NUM_SND_ARGS];
1644 /* get integer values from string parameters */
1645 for (i = 0; i < NUM_SND_ARGS; i++)
1647 get_parameter_value(parameter_raw[i],
1648 sound_config_suffix[i].token,
1649 sound_config_suffix[i].type);
1651 /* explicit loop mode setting in configuration overrides default value */
1652 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1653 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1655 /* sound volume to change the original volume when loading the sound file */
1656 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1658 /* sound priority to give certain sounds a higher or lower priority */
1659 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
1662 static void InitSoundInfo()
1664 int *sound_effect_properties;
1665 int num_sounds = getSoundListSize();
1668 checked_free(sound_info);
1670 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1671 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1673 /* initialize sound effect for all elements to "no sound" */
1674 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1675 for (j = 0; j < NUM_ACTIONS; j++)
1676 element_info[i].sound[j] = SND_UNDEFINED;
1678 for (i = 0; i < num_sounds; i++)
1680 struct FileInfo *sound = getSoundListEntry(i);
1681 int len_effect_text = strlen(sound->token);
1683 sound_effect_properties[i] = ACTION_OTHER;
1684 sound_info[i].loop = FALSE; /* default: play sound only once */
1687 printf("::: sound %d: '%s'\n", i, sound->token);
1690 /* determine all loop sounds and identify certain sound classes */
1692 for (j = 0; element_action_info[j].suffix; j++)
1694 int len_action_text = strlen(element_action_info[j].suffix);
1696 if (len_action_text < len_effect_text &&
1697 strEqual(&sound->token[len_effect_text - len_action_text],
1698 element_action_info[j].suffix))
1700 sound_effect_properties[i] = element_action_info[j].value;
1701 sound_info[i].loop = element_action_info[j].is_loop_sound;
1707 /* associate elements and some selected sound actions */
1709 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1711 if (element_info[j].class_name)
1713 int len_class_text = strlen(element_info[j].class_name);
1715 if (len_class_text + 1 < len_effect_text &&
1716 strncmp(sound->token,
1717 element_info[j].class_name, len_class_text) == 0 &&
1718 sound->token[len_class_text] == '.')
1720 int sound_action_value = sound_effect_properties[i];
1722 element_info[j].sound[sound_action_value] = i;
1727 set_sound_parameters(i, sound->parameter);
1730 free(sound_effect_properties);
1733 static void InitGameModeMusicInfo()
1735 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1736 int num_property_mappings = getMusicListPropertyMappingSize();
1737 int default_levelset_music = -1;
1740 /* set values to -1 to identify later as "uninitialized" values */
1741 for (i = 0; i < MAX_LEVELS; i++)
1742 levelset.music[i] = -1;
1743 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1746 /* initialize gamemode/music mapping from static configuration */
1747 for (i = 0; gamemode_to_music[i].music > -1; i++)
1749 int gamemode = gamemode_to_music[i].gamemode;
1750 int music = gamemode_to_music[i].music;
1753 printf("::: gamemode == %d, music == %d\n", gamemode, music);
1757 gamemode = GAME_MODE_DEFAULT;
1759 menu.music[gamemode] = music;
1762 /* initialize gamemode/music mapping from dynamic configuration */
1763 for (i = 0; i < num_property_mappings; i++)
1765 int prefix = property_mapping[i].base_index;
1766 int gamemode = property_mapping[i].ext1_index;
1767 int level = property_mapping[i].ext2_index;
1768 int music = property_mapping[i].artwork_index;
1771 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
1772 prefix, gamemode, level, music);
1775 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1779 gamemode = GAME_MODE_DEFAULT;
1781 /* level specific music only allowed for in-game music */
1782 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1783 gamemode = GAME_MODE_PLAYING;
1788 default_levelset_music = music;
1791 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1792 levelset.music[level] = music;
1793 if (gamemode != GAME_MODE_PLAYING)
1794 menu.music[gamemode] = music;
1797 /* now set all '-1' values to menu specific default values */
1798 /* (undefined values of "levelset.music[]" might stay at "-1" to
1799 allow dynamic selection of music files from music directory!) */
1800 for (i = 0; i < MAX_LEVELS; i++)
1801 if (levelset.music[i] == -1)
1802 levelset.music[i] = default_levelset_music;
1803 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1804 if (menu.music[i] == -1)
1805 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1808 for (i = 0; i < MAX_LEVELS; i++)
1809 if (levelset.music[i] != -1)
1810 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
1811 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1812 if (menu.music[i] != -1)
1813 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
1817 static void set_music_parameters(int music, char **parameter_raw)
1819 int parameter[NUM_MUS_ARGS];
1822 /* get integer values from string parameters */
1823 for (i = 0; i < NUM_MUS_ARGS; i++)
1825 get_parameter_value(parameter_raw[i],
1826 music_config_suffix[i].token,
1827 music_config_suffix[i].type);
1829 /* explicit loop mode setting in configuration overrides default value */
1830 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1831 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1834 static void InitMusicInfo()
1836 int num_music = getMusicListSize();
1839 checked_free(music_info);
1841 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1843 for (i = 0; i < num_music; i++)
1845 struct FileInfo *music = getMusicListEntry(i);
1846 int len_music_text = strlen(music->token);
1848 music_info[i].loop = TRUE; /* default: play music in loop mode */
1850 /* determine all loop music */
1852 for (j = 0; music_prefix_info[j].prefix; j++)
1854 int len_prefix_text = strlen(music_prefix_info[j].prefix);
1856 if (len_prefix_text < len_music_text &&
1857 strncmp(music->token,
1858 music_prefix_info[j].prefix, len_prefix_text) == 0)
1860 music_info[i].loop = music_prefix_info[j].is_loop_music;
1866 set_music_parameters(i, music->parameter);
1870 static void ReinitializeGraphics()
1872 InitGraphicInfo(); /* graphic properties mapping */
1873 InitElementGraphicInfo(); /* element game graphic mapping */
1874 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
1876 InitElementSmallImages(); /* scale elements to all needed sizes */
1877 InitScaledImages(); /* scale all other images, if needed */
1878 InitFontGraphicInfo(); /* initialize text drawing functions */
1880 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
1882 SetMainBackgroundImage(IMG_BACKGROUND);
1883 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1889 static void ReinitializeSounds()
1891 InitSoundInfo(); /* sound properties mapping */
1892 InitElementSoundInfo(); /* element game sound mapping */
1893 InitGameModeSoundInfo(); /* game mode sound mapping */
1895 InitPlayLevelSound(); /* internal game sound settings */
1898 static void ReinitializeMusic()
1900 InitMusicInfo(); /* music properties mapping */
1901 InitGameModeMusicInfo(); /* game mode music mapping */
1904 static int get_special_property_bit(int element, int property_bit_nr)
1906 struct PropertyBitInfo
1912 static struct PropertyBitInfo pb_can_move_into_acid[] =
1914 /* the player may be able fall into acid when gravity is activated */
1919 { EL_SP_MURPHY, 0 },
1920 { EL_SOKOBAN_FIELD_PLAYER, 0 },
1922 /* all elements that can move may be able to also move into acid */
1925 { EL_BUG_RIGHT, 1 },
1928 { EL_SPACESHIP, 2 },
1929 { EL_SPACESHIP_LEFT, 2 },
1930 { EL_SPACESHIP_RIGHT, 2 },
1931 { EL_SPACESHIP_UP, 2 },
1932 { EL_SPACESHIP_DOWN, 2 },
1933 { EL_BD_BUTTERFLY, 3 },
1934 { EL_BD_BUTTERFLY_LEFT, 3 },
1935 { EL_BD_BUTTERFLY_RIGHT, 3 },
1936 { EL_BD_BUTTERFLY_UP, 3 },
1937 { EL_BD_BUTTERFLY_DOWN, 3 },
1938 { EL_BD_FIREFLY, 4 },
1939 { EL_BD_FIREFLY_LEFT, 4 },
1940 { EL_BD_FIREFLY_RIGHT, 4 },
1941 { EL_BD_FIREFLY_UP, 4 },
1942 { EL_BD_FIREFLY_DOWN, 4 },
1944 { EL_YAMYAM_LEFT, 5 },
1945 { EL_YAMYAM_RIGHT, 5 },
1946 { EL_YAMYAM_UP, 5 },
1947 { EL_YAMYAM_DOWN, 5 },
1948 { EL_DARK_YAMYAM, 6 },
1951 { EL_PACMAN_LEFT, 8 },
1952 { EL_PACMAN_RIGHT, 8 },
1953 { EL_PACMAN_UP, 8 },
1954 { EL_PACMAN_DOWN, 8 },
1956 { EL_MOLE_LEFT, 9 },
1957 { EL_MOLE_RIGHT, 9 },
1959 { EL_MOLE_DOWN, 9 },
1963 { EL_SATELLITE, 13 },
1964 { EL_SP_SNIKSNAK, 14 },
1965 { EL_SP_ELECTRON, 15 },
1968 { EL_EMC_ANDROID, 18 },
1973 static struct PropertyBitInfo pb_dont_collide_with[] =
1975 { EL_SP_SNIKSNAK, 0 },
1976 { EL_SP_ELECTRON, 1 },
1984 struct PropertyBitInfo *pb_info;
1987 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
1988 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
1993 struct PropertyBitInfo *pb_info = NULL;
1996 for (i = 0; pb_definition[i].bit_nr != -1; i++)
1997 if (pb_definition[i].bit_nr == property_bit_nr)
1998 pb_info = pb_definition[i].pb_info;
2000 if (pb_info == NULL)
2003 for (i = 0; pb_info[i].element != -1; i++)
2004 if (pb_info[i].element == element)
2005 return pb_info[i].bit_nr;
2010 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2011 boolean property_value)
2013 int bit_nr = get_special_property_bit(element, property_bit_nr);
2018 *bitfield |= (1 << bit_nr);
2020 *bitfield &= ~(1 << bit_nr);
2024 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2026 int bit_nr = get_special_property_bit(element, property_bit_nr);
2029 return ((*bitfield & (1 << bit_nr)) != 0);
2034 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2036 static int group_nr;
2037 static struct ElementGroupInfo *group;
2038 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2041 if (actual_group == NULL) /* not yet initialized */
2044 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
2046 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2047 group_element - EL_GROUP_START + 1);
2049 /* replace element which caused too deep recursion by question mark */
2050 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2055 if (recursion_depth == 0) /* initialization */
2057 group = actual_group;
2058 group_nr = GROUP_NR(group_element);
2060 group->num_elements_resolved = 0;
2061 group->choice_pos = 0;
2063 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2064 element_info[i].in_group[group_nr] = FALSE;
2067 for (i = 0; i < actual_group->num_elements; i++)
2069 int element = actual_group->element[i];
2071 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2074 if (IS_GROUP_ELEMENT(element))
2075 ResolveGroupElementExt(element, recursion_depth + 1);
2078 group->element_resolved[group->num_elements_resolved++] = element;
2079 element_info[element].in_group[group_nr] = TRUE;
2084 void ResolveGroupElement(int group_element)
2086 ResolveGroupElementExt(group_element, 0);
2089 void InitElementPropertiesStatic()
2091 static int ep_diggable[] =
2096 EL_SP_BUGGY_BASE_ACTIVATING,
2099 EL_INVISIBLE_SAND_ACTIVE,
2102 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2103 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2108 EL_SP_BUGGY_BASE_ACTIVE,
2115 static int ep_collectible_only[] =
2137 EL_DYNABOMB_INCREASE_NUMBER,
2138 EL_DYNABOMB_INCREASE_SIZE,
2139 EL_DYNABOMB_INCREASE_POWER,
2157 /* !!! handle separately !!! */
2158 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2164 static int ep_dont_run_into[] =
2166 /* same elements as in 'ep_dont_touch' */
2172 /* same elements as in 'ep_dont_collide_with' */
2184 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2189 EL_SP_BUGGY_BASE_ACTIVE,
2196 static int ep_dont_collide_with[] =
2198 /* same elements as in 'ep_dont_touch' */
2215 static int ep_dont_touch[] =
2225 static int ep_indestructible[] =
2229 EL_ACID_POOL_TOPLEFT,
2230 EL_ACID_POOL_TOPRIGHT,
2231 EL_ACID_POOL_BOTTOMLEFT,
2232 EL_ACID_POOL_BOTTOM,
2233 EL_ACID_POOL_BOTTOMRIGHT,
2234 EL_SP_HARDWARE_GRAY,
2235 EL_SP_HARDWARE_GREEN,
2236 EL_SP_HARDWARE_BLUE,
2238 EL_SP_HARDWARE_YELLOW,
2239 EL_SP_HARDWARE_BASE_1,
2240 EL_SP_HARDWARE_BASE_2,
2241 EL_SP_HARDWARE_BASE_3,
2242 EL_SP_HARDWARE_BASE_4,
2243 EL_SP_HARDWARE_BASE_5,
2244 EL_SP_HARDWARE_BASE_6,
2245 EL_INVISIBLE_STEELWALL,
2246 EL_INVISIBLE_STEELWALL_ACTIVE,
2247 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2248 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2249 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2250 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2251 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2252 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2253 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2254 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2255 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2256 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2257 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2258 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2260 EL_LIGHT_SWITCH_ACTIVE,
2261 EL_SIGN_EXCLAMATION,
2262 EL_SIGN_RADIOACTIVITY,
2269 EL_SIGN_ENTRY_FORBIDDEN,
2270 EL_SIGN_EMERGENCY_EXIT,
2278 EL_STEEL_EXIT_CLOSED,
2280 EL_EM_STEEL_EXIT_CLOSED,
2281 EL_EM_STEEL_EXIT_OPEN,
2282 EL_DC_STEELWALL_1_LEFT,
2283 EL_DC_STEELWALL_1_RIGHT,
2284 EL_DC_STEELWALL_1_TOP,
2285 EL_DC_STEELWALL_1_BOTTOM,
2286 EL_DC_STEELWALL_1_HORIZONTAL,
2287 EL_DC_STEELWALL_1_VERTICAL,
2288 EL_DC_STEELWALL_1_TOPLEFT,
2289 EL_DC_STEELWALL_1_TOPRIGHT,
2290 EL_DC_STEELWALL_1_BOTTOMLEFT,
2291 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2292 EL_DC_STEELWALL_1_TOPLEFT_2,
2293 EL_DC_STEELWALL_1_TOPRIGHT_2,
2294 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2295 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2296 EL_DC_STEELWALL_2_LEFT,
2297 EL_DC_STEELWALL_2_RIGHT,
2298 EL_DC_STEELWALL_2_TOP,
2299 EL_DC_STEELWALL_2_BOTTOM,
2300 EL_DC_STEELWALL_2_HORIZONTAL,
2301 EL_DC_STEELWALL_2_VERTICAL,
2302 EL_DC_STEELWALL_2_MIDDLE,
2303 EL_DC_STEELWALL_2_SINGLE,
2304 EL_STEELWALL_SLIPPERY,
2318 EL_GATE_1_GRAY_ACTIVE,
2319 EL_GATE_2_GRAY_ACTIVE,
2320 EL_GATE_3_GRAY_ACTIVE,
2321 EL_GATE_4_GRAY_ACTIVE,
2330 EL_EM_GATE_1_GRAY_ACTIVE,
2331 EL_EM_GATE_2_GRAY_ACTIVE,
2332 EL_EM_GATE_3_GRAY_ACTIVE,
2333 EL_EM_GATE_4_GRAY_ACTIVE,
2342 EL_EMC_GATE_5_GRAY_ACTIVE,
2343 EL_EMC_GATE_6_GRAY_ACTIVE,
2344 EL_EMC_GATE_7_GRAY_ACTIVE,
2345 EL_EMC_GATE_8_GRAY_ACTIVE,
2347 EL_DC_GATE_WHITE_GRAY,
2348 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2349 EL_DC_GATE_FAKE_GRAY,
2351 EL_SWITCHGATE_OPENING,
2352 EL_SWITCHGATE_CLOSED,
2353 EL_SWITCHGATE_CLOSING,
2355 EL_DC_SWITCHGATE_SWITCH_UP,
2356 EL_DC_SWITCHGATE_SWITCH_DOWN,
2359 EL_TIMEGATE_OPENING,
2361 EL_TIMEGATE_CLOSING,
2363 EL_DC_TIMEGATE_SWITCH,
2364 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2369 EL_TUBE_VERTICAL_LEFT,
2370 EL_TUBE_VERTICAL_RIGHT,
2371 EL_TUBE_HORIZONTAL_UP,
2372 EL_TUBE_HORIZONTAL_DOWN,
2377 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2378 EL_EXPANDABLE_STEELWALL_VERTICAL,
2379 EL_EXPANDABLE_STEELWALL_ANY,
2384 static int ep_slippery[] =
2398 EL_ROBOT_WHEEL_ACTIVE,
2404 EL_ACID_POOL_TOPLEFT,
2405 EL_ACID_POOL_TOPRIGHT,
2415 EL_STEELWALL_SLIPPERY,
2418 EL_EMC_WALL_SLIPPERY_1,
2419 EL_EMC_WALL_SLIPPERY_2,
2420 EL_EMC_WALL_SLIPPERY_3,
2421 EL_EMC_WALL_SLIPPERY_4,
2423 EL_EMC_MAGIC_BALL_ACTIVE,
2428 static int ep_can_change[] =
2433 static int ep_can_move[] =
2435 /* same elements as in 'pb_can_move_into_acid' */
2458 static int ep_can_fall[] =
2472 EL_QUICKSAND_FAST_FULL,
2474 EL_BD_MAGIC_WALL_FULL,
2475 EL_DC_MAGIC_WALL_FULL,
2489 static int ep_can_smash_player[] =
2515 static int ep_can_smash_enemies[] =
2524 static int ep_can_smash_everything[] =
2533 static int ep_explodes_by_fire[] =
2535 /* same elements as in 'ep_explodes_impact' */
2540 /* same elements as in 'ep_explodes_smashed' */
2550 EL_EM_DYNAMITE_ACTIVE,
2551 EL_DYNABOMB_PLAYER_1_ACTIVE,
2552 EL_DYNABOMB_PLAYER_2_ACTIVE,
2553 EL_DYNABOMB_PLAYER_3_ACTIVE,
2554 EL_DYNABOMB_PLAYER_4_ACTIVE,
2555 EL_DYNABOMB_INCREASE_NUMBER,
2556 EL_DYNABOMB_INCREASE_SIZE,
2557 EL_DYNABOMB_INCREASE_POWER,
2558 EL_SP_DISK_RED_ACTIVE,
2572 static int ep_explodes_smashed[] =
2574 /* same elements as in 'ep_explodes_impact' */
2588 static int ep_explodes_impact[] =
2597 static int ep_walkable_over[] =
2601 EL_SOKOBAN_FIELD_EMPTY,
2607 EL_EM_STEEL_EXIT_OPEN,
2616 EL_GATE_1_GRAY_ACTIVE,
2617 EL_GATE_2_GRAY_ACTIVE,
2618 EL_GATE_3_GRAY_ACTIVE,
2619 EL_GATE_4_GRAY_ACTIVE,
2627 static int ep_walkable_inside[] =
2632 EL_TUBE_VERTICAL_LEFT,
2633 EL_TUBE_VERTICAL_RIGHT,
2634 EL_TUBE_HORIZONTAL_UP,
2635 EL_TUBE_HORIZONTAL_DOWN,
2644 static int ep_walkable_under[] =
2649 static int ep_passable_over[] =
2659 EL_EM_GATE_1_GRAY_ACTIVE,
2660 EL_EM_GATE_2_GRAY_ACTIVE,
2661 EL_EM_GATE_3_GRAY_ACTIVE,
2662 EL_EM_GATE_4_GRAY_ACTIVE,
2671 EL_EMC_GATE_5_GRAY_ACTIVE,
2672 EL_EMC_GATE_6_GRAY_ACTIVE,
2673 EL_EMC_GATE_7_GRAY_ACTIVE,
2674 EL_EMC_GATE_8_GRAY_ACTIVE,
2676 EL_DC_GATE_WHITE_GRAY,
2677 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2684 static int ep_passable_inside[] =
2690 EL_SP_PORT_HORIZONTAL,
2691 EL_SP_PORT_VERTICAL,
2693 EL_SP_GRAVITY_PORT_LEFT,
2694 EL_SP_GRAVITY_PORT_RIGHT,
2695 EL_SP_GRAVITY_PORT_UP,
2696 EL_SP_GRAVITY_PORT_DOWN,
2697 EL_SP_GRAVITY_ON_PORT_LEFT,
2698 EL_SP_GRAVITY_ON_PORT_RIGHT,
2699 EL_SP_GRAVITY_ON_PORT_UP,
2700 EL_SP_GRAVITY_ON_PORT_DOWN,
2701 EL_SP_GRAVITY_OFF_PORT_LEFT,
2702 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2703 EL_SP_GRAVITY_OFF_PORT_UP,
2704 EL_SP_GRAVITY_OFF_PORT_DOWN,
2709 static int ep_passable_under[] =
2714 static int ep_droppable[] =
2719 static int ep_explodes_1x1_old[] =
2724 static int ep_pushable[] =
2736 EL_SOKOBAN_FIELD_FULL,
2745 static int ep_explodes_cross_old[] =
2750 static int ep_protected[] =
2752 /* same elements as in 'ep_walkable_inside' */
2756 EL_TUBE_VERTICAL_LEFT,
2757 EL_TUBE_VERTICAL_RIGHT,
2758 EL_TUBE_HORIZONTAL_UP,
2759 EL_TUBE_HORIZONTAL_DOWN,
2765 /* same elements as in 'ep_passable_over' */
2774 EL_EM_GATE_1_GRAY_ACTIVE,
2775 EL_EM_GATE_2_GRAY_ACTIVE,
2776 EL_EM_GATE_3_GRAY_ACTIVE,
2777 EL_EM_GATE_4_GRAY_ACTIVE,
2786 EL_EMC_GATE_5_GRAY_ACTIVE,
2787 EL_EMC_GATE_6_GRAY_ACTIVE,
2788 EL_EMC_GATE_7_GRAY_ACTIVE,
2789 EL_EMC_GATE_8_GRAY_ACTIVE,
2791 EL_DC_GATE_WHITE_GRAY,
2792 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2796 /* same elements as in 'ep_passable_inside' */
2801 EL_SP_PORT_HORIZONTAL,
2802 EL_SP_PORT_VERTICAL,
2804 EL_SP_GRAVITY_PORT_LEFT,
2805 EL_SP_GRAVITY_PORT_RIGHT,
2806 EL_SP_GRAVITY_PORT_UP,
2807 EL_SP_GRAVITY_PORT_DOWN,
2808 EL_SP_GRAVITY_ON_PORT_LEFT,
2809 EL_SP_GRAVITY_ON_PORT_RIGHT,
2810 EL_SP_GRAVITY_ON_PORT_UP,
2811 EL_SP_GRAVITY_ON_PORT_DOWN,
2812 EL_SP_GRAVITY_OFF_PORT_LEFT,
2813 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2814 EL_SP_GRAVITY_OFF_PORT_UP,
2815 EL_SP_GRAVITY_OFF_PORT_DOWN,
2820 static int ep_throwable[] =
2825 static int ep_can_explode[] =
2827 /* same elements as in 'ep_explodes_impact' */
2832 /* same elements as in 'ep_explodes_smashed' */
2838 /* elements that can explode by explosion or by dragonfire */
2842 EL_EM_DYNAMITE_ACTIVE,
2843 EL_DYNABOMB_PLAYER_1_ACTIVE,
2844 EL_DYNABOMB_PLAYER_2_ACTIVE,
2845 EL_DYNABOMB_PLAYER_3_ACTIVE,
2846 EL_DYNABOMB_PLAYER_4_ACTIVE,
2847 EL_DYNABOMB_INCREASE_NUMBER,
2848 EL_DYNABOMB_INCREASE_SIZE,
2849 EL_DYNABOMB_INCREASE_POWER,
2850 EL_SP_DISK_RED_ACTIVE,
2858 /* elements that can explode only by explosion */
2864 static int ep_gravity_reachable[] =
2870 EL_INVISIBLE_SAND_ACTIVE,
2875 EL_SP_PORT_HORIZONTAL,
2876 EL_SP_PORT_VERTICAL,
2878 EL_SP_GRAVITY_PORT_LEFT,
2879 EL_SP_GRAVITY_PORT_RIGHT,
2880 EL_SP_GRAVITY_PORT_UP,
2881 EL_SP_GRAVITY_PORT_DOWN,
2882 EL_SP_GRAVITY_ON_PORT_LEFT,
2883 EL_SP_GRAVITY_ON_PORT_RIGHT,
2884 EL_SP_GRAVITY_ON_PORT_UP,
2885 EL_SP_GRAVITY_ON_PORT_DOWN,
2886 EL_SP_GRAVITY_OFF_PORT_LEFT,
2887 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2888 EL_SP_GRAVITY_OFF_PORT_UP,
2889 EL_SP_GRAVITY_OFF_PORT_DOWN,
2895 static int ep_player[] =
2902 EL_SOKOBAN_FIELD_PLAYER,
2908 static int ep_can_pass_magic_wall[] =
2922 static int ep_can_pass_dc_magic_wall[] =
2938 static int ep_switchable[] =
2942 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2943 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2944 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2945 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2946 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2947 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2948 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2949 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2950 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2951 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2952 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2953 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2954 EL_SWITCHGATE_SWITCH_UP,
2955 EL_SWITCHGATE_SWITCH_DOWN,
2956 EL_DC_SWITCHGATE_SWITCH_UP,
2957 EL_DC_SWITCHGATE_SWITCH_DOWN,
2959 EL_LIGHT_SWITCH_ACTIVE,
2961 EL_DC_TIMEGATE_SWITCH,
2962 EL_BALLOON_SWITCH_LEFT,
2963 EL_BALLOON_SWITCH_RIGHT,
2964 EL_BALLOON_SWITCH_UP,
2965 EL_BALLOON_SWITCH_DOWN,
2966 EL_BALLOON_SWITCH_ANY,
2967 EL_BALLOON_SWITCH_NONE,
2970 EL_EMC_MAGIC_BALL_SWITCH,
2971 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
2976 static int ep_bd_element[] =
3010 static int ep_sp_element[] =
3012 /* should always be valid */
3015 /* standard classic Supaplex elements */
3022 EL_SP_HARDWARE_GRAY,
3030 EL_SP_GRAVITY_PORT_RIGHT,
3031 EL_SP_GRAVITY_PORT_DOWN,
3032 EL_SP_GRAVITY_PORT_LEFT,
3033 EL_SP_GRAVITY_PORT_UP,
3038 EL_SP_PORT_VERTICAL,
3039 EL_SP_PORT_HORIZONTAL,
3045 EL_SP_HARDWARE_BASE_1,
3046 EL_SP_HARDWARE_GREEN,
3047 EL_SP_HARDWARE_BLUE,
3049 EL_SP_HARDWARE_YELLOW,
3050 EL_SP_HARDWARE_BASE_2,
3051 EL_SP_HARDWARE_BASE_3,
3052 EL_SP_HARDWARE_BASE_4,
3053 EL_SP_HARDWARE_BASE_5,
3054 EL_SP_HARDWARE_BASE_6,
3058 /* additional elements that appeared in newer Supaplex levels */
3061 /* additional gravity port elements (not switching, but setting gravity) */
3062 EL_SP_GRAVITY_ON_PORT_LEFT,
3063 EL_SP_GRAVITY_ON_PORT_RIGHT,
3064 EL_SP_GRAVITY_ON_PORT_UP,
3065 EL_SP_GRAVITY_ON_PORT_DOWN,
3066 EL_SP_GRAVITY_OFF_PORT_LEFT,
3067 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3068 EL_SP_GRAVITY_OFF_PORT_UP,
3069 EL_SP_GRAVITY_OFF_PORT_DOWN,
3071 /* more than one Murphy in a level results in an inactive clone */
3074 /* runtime Supaplex elements */
3075 EL_SP_DISK_RED_ACTIVE,
3076 EL_SP_TERMINAL_ACTIVE,
3077 EL_SP_BUGGY_BASE_ACTIVATING,
3078 EL_SP_BUGGY_BASE_ACTIVE,
3085 static int ep_sb_element[] =
3090 EL_SOKOBAN_FIELD_EMPTY,
3091 EL_SOKOBAN_FIELD_FULL,
3092 EL_SOKOBAN_FIELD_PLAYER,
3097 EL_INVISIBLE_STEELWALL,
3102 static int ep_gem[] =
3114 static int ep_food_dark_yamyam[] =
3142 static int ep_food_penguin[] =
3156 static int ep_food_pig[] =
3168 static int ep_historic_wall[] =
3179 EL_GATE_1_GRAY_ACTIVE,
3180 EL_GATE_2_GRAY_ACTIVE,
3181 EL_GATE_3_GRAY_ACTIVE,
3182 EL_GATE_4_GRAY_ACTIVE,
3191 EL_EM_GATE_1_GRAY_ACTIVE,
3192 EL_EM_GATE_2_GRAY_ACTIVE,
3193 EL_EM_GATE_3_GRAY_ACTIVE,
3194 EL_EM_GATE_4_GRAY_ACTIVE,
3201 EL_EXPANDABLE_WALL_HORIZONTAL,
3202 EL_EXPANDABLE_WALL_VERTICAL,
3203 EL_EXPANDABLE_WALL_ANY,
3204 EL_EXPANDABLE_WALL_GROWING,
3205 EL_BD_EXPANDABLE_WALL,
3212 EL_SP_HARDWARE_GRAY,
3213 EL_SP_HARDWARE_GREEN,
3214 EL_SP_HARDWARE_BLUE,
3216 EL_SP_HARDWARE_YELLOW,
3217 EL_SP_HARDWARE_BASE_1,
3218 EL_SP_HARDWARE_BASE_2,
3219 EL_SP_HARDWARE_BASE_3,
3220 EL_SP_HARDWARE_BASE_4,
3221 EL_SP_HARDWARE_BASE_5,
3222 EL_SP_HARDWARE_BASE_6,
3224 EL_SP_TERMINAL_ACTIVE,
3227 EL_INVISIBLE_STEELWALL,
3228 EL_INVISIBLE_STEELWALL_ACTIVE,
3230 EL_INVISIBLE_WALL_ACTIVE,
3231 EL_STEELWALL_SLIPPERY,
3248 static int ep_historic_solid[] =
3252 EL_EXPANDABLE_WALL_HORIZONTAL,
3253 EL_EXPANDABLE_WALL_VERTICAL,
3254 EL_EXPANDABLE_WALL_ANY,
3255 EL_BD_EXPANDABLE_WALL,
3268 EL_QUICKSAND_FILLING,
3269 EL_QUICKSAND_EMPTYING,
3271 EL_MAGIC_WALL_ACTIVE,
3272 EL_MAGIC_WALL_EMPTYING,
3273 EL_MAGIC_WALL_FILLING,
3277 EL_BD_MAGIC_WALL_ACTIVE,
3278 EL_BD_MAGIC_WALL_EMPTYING,
3279 EL_BD_MAGIC_WALL_FULL,
3280 EL_BD_MAGIC_WALL_FILLING,
3281 EL_BD_MAGIC_WALL_DEAD,
3290 EL_SP_TERMINAL_ACTIVE,
3294 EL_INVISIBLE_WALL_ACTIVE,
3295 EL_SWITCHGATE_SWITCH_UP,
3296 EL_SWITCHGATE_SWITCH_DOWN,
3297 EL_DC_SWITCHGATE_SWITCH_UP,
3298 EL_DC_SWITCHGATE_SWITCH_DOWN,
3300 EL_TIMEGATE_SWITCH_ACTIVE,
3301 EL_DC_TIMEGATE_SWITCH,
3302 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3314 /* the following elements are a direct copy of "indestructible" elements,
3315 except "EL_ACID", which is "indestructible", but not "solid"! */
3320 EL_ACID_POOL_TOPLEFT,
3321 EL_ACID_POOL_TOPRIGHT,
3322 EL_ACID_POOL_BOTTOMLEFT,
3323 EL_ACID_POOL_BOTTOM,
3324 EL_ACID_POOL_BOTTOMRIGHT,
3325 EL_SP_HARDWARE_GRAY,
3326 EL_SP_HARDWARE_GREEN,
3327 EL_SP_HARDWARE_BLUE,
3329 EL_SP_HARDWARE_YELLOW,
3330 EL_SP_HARDWARE_BASE_1,
3331 EL_SP_HARDWARE_BASE_2,
3332 EL_SP_HARDWARE_BASE_3,
3333 EL_SP_HARDWARE_BASE_4,
3334 EL_SP_HARDWARE_BASE_5,
3335 EL_SP_HARDWARE_BASE_6,
3336 EL_INVISIBLE_STEELWALL,
3337 EL_INVISIBLE_STEELWALL_ACTIVE,
3338 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3339 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3340 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3341 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3342 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3343 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3344 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3345 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3346 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3347 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3348 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3349 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3351 EL_LIGHT_SWITCH_ACTIVE,
3352 EL_SIGN_EXCLAMATION,
3353 EL_SIGN_RADIOACTIVITY,
3360 EL_SIGN_ENTRY_FORBIDDEN,
3361 EL_SIGN_EMERGENCY_EXIT,
3369 EL_STEEL_EXIT_CLOSED,
3371 EL_DC_STEELWALL_1_LEFT,
3372 EL_DC_STEELWALL_1_RIGHT,
3373 EL_DC_STEELWALL_1_TOP,
3374 EL_DC_STEELWALL_1_BOTTOM,
3375 EL_DC_STEELWALL_1_HORIZONTAL,
3376 EL_DC_STEELWALL_1_VERTICAL,
3377 EL_DC_STEELWALL_1_TOPLEFT,
3378 EL_DC_STEELWALL_1_TOPRIGHT,
3379 EL_DC_STEELWALL_1_BOTTOMLEFT,
3380 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3381 EL_DC_STEELWALL_1_TOPLEFT_2,
3382 EL_DC_STEELWALL_1_TOPRIGHT_2,
3383 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3384 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3385 EL_DC_STEELWALL_2_LEFT,
3386 EL_DC_STEELWALL_2_RIGHT,
3387 EL_DC_STEELWALL_2_TOP,
3388 EL_DC_STEELWALL_2_BOTTOM,
3389 EL_DC_STEELWALL_2_HORIZONTAL,
3390 EL_DC_STEELWALL_2_VERTICAL,
3391 EL_DC_STEELWALL_2_MIDDLE,
3392 EL_DC_STEELWALL_2_SINGLE,
3393 EL_STEELWALL_SLIPPERY,
3407 EL_GATE_1_GRAY_ACTIVE,
3408 EL_GATE_2_GRAY_ACTIVE,
3409 EL_GATE_3_GRAY_ACTIVE,
3410 EL_GATE_4_GRAY_ACTIVE,
3419 EL_EM_GATE_1_GRAY_ACTIVE,
3420 EL_EM_GATE_2_GRAY_ACTIVE,
3421 EL_EM_GATE_3_GRAY_ACTIVE,
3422 EL_EM_GATE_4_GRAY_ACTIVE,
3424 EL_SWITCHGATE_OPENING,
3425 EL_SWITCHGATE_CLOSED,
3426 EL_SWITCHGATE_CLOSING,
3428 EL_TIMEGATE_OPENING,
3430 EL_TIMEGATE_CLOSING,
3434 EL_TUBE_VERTICAL_LEFT,
3435 EL_TUBE_VERTICAL_RIGHT,
3436 EL_TUBE_HORIZONTAL_UP,
3437 EL_TUBE_HORIZONTAL_DOWN,
3446 static int ep_classic_enemy[] =
3463 static int ep_belt[] =
3465 EL_CONVEYOR_BELT_1_LEFT,
3466 EL_CONVEYOR_BELT_1_MIDDLE,
3467 EL_CONVEYOR_BELT_1_RIGHT,
3468 EL_CONVEYOR_BELT_2_LEFT,
3469 EL_CONVEYOR_BELT_2_MIDDLE,
3470 EL_CONVEYOR_BELT_2_RIGHT,
3471 EL_CONVEYOR_BELT_3_LEFT,
3472 EL_CONVEYOR_BELT_3_MIDDLE,
3473 EL_CONVEYOR_BELT_3_RIGHT,
3474 EL_CONVEYOR_BELT_4_LEFT,
3475 EL_CONVEYOR_BELT_4_MIDDLE,
3476 EL_CONVEYOR_BELT_4_RIGHT,
3481 static int ep_belt_active[] =
3483 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3484 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3485 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3486 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3487 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3488 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3489 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3490 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3491 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3492 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3493 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3494 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3499 static int ep_belt_switch[] =
3501 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3502 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3503 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3504 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3505 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3506 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3507 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3508 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3509 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3510 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3511 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3512 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3517 static int ep_tube[] =
3524 EL_TUBE_HORIZONTAL_UP,
3525 EL_TUBE_HORIZONTAL_DOWN,
3527 EL_TUBE_VERTICAL_LEFT,
3528 EL_TUBE_VERTICAL_RIGHT,
3534 static int ep_acid_pool[] =
3536 EL_ACID_POOL_TOPLEFT,
3537 EL_ACID_POOL_TOPRIGHT,
3538 EL_ACID_POOL_BOTTOMLEFT,
3539 EL_ACID_POOL_BOTTOM,
3540 EL_ACID_POOL_BOTTOMRIGHT,
3545 static int ep_keygate[] =
3555 EL_GATE_1_GRAY_ACTIVE,
3556 EL_GATE_2_GRAY_ACTIVE,
3557 EL_GATE_3_GRAY_ACTIVE,
3558 EL_GATE_4_GRAY_ACTIVE,
3567 EL_EM_GATE_1_GRAY_ACTIVE,
3568 EL_EM_GATE_2_GRAY_ACTIVE,
3569 EL_EM_GATE_3_GRAY_ACTIVE,
3570 EL_EM_GATE_4_GRAY_ACTIVE,
3579 EL_EMC_GATE_5_GRAY_ACTIVE,
3580 EL_EMC_GATE_6_GRAY_ACTIVE,
3581 EL_EMC_GATE_7_GRAY_ACTIVE,
3582 EL_EMC_GATE_8_GRAY_ACTIVE,
3584 EL_DC_GATE_WHITE_GRAY,
3585 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3590 static int ep_amoeboid[] =
3602 static int ep_amoebalive[] =
3613 static int ep_has_editor_content[] =
3635 static int ep_can_turn_each_move[] =
3637 /* !!! do something with this one !!! */
3641 static int ep_can_grow[] =
3655 static int ep_active_bomb[] =
3658 EL_EM_DYNAMITE_ACTIVE,
3659 EL_DYNABOMB_PLAYER_1_ACTIVE,
3660 EL_DYNABOMB_PLAYER_2_ACTIVE,
3661 EL_DYNABOMB_PLAYER_3_ACTIVE,
3662 EL_DYNABOMB_PLAYER_4_ACTIVE,
3663 EL_SP_DISK_RED_ACTIVE,
3668 static int ep_inactive[] =
3678 EL_QUICKSAND_FAST_EMPTY,
3701 EL_GATE_1_GRAY_ACTIVE,
3702 EL_GATE_2_GRAY_ACTIVE,
3703 EL_GATE_3_GRAY_ACTIVE,
3704 EL_GATE_4_GRAY_ACTIVE,
3713 EL_EM_GATE_1_GRAY_ACTIVE,
3714 EL_EM_GATE_2_GRAY_ACTIVE,
3715 EL_EM_GATE_3_GRAY_ACTIVE,
3716 EL_EM_GATE_4_GRAY_ACTIVE,
3725 EL_EMC_GATE_5_GRAY_ACTIVE,
3726 EL_EMC_GATE_6_GRAY_ACTIVE,
3727 EL_EMC_GATE_7_GRAY_ACTIVE,
3728 EL_EMC_GATE_8_GRAY_ACTIVE,
3730 EL_DC_GATE_WHITE_GRAY,
3731 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3732 EL_DC_GATE_FAKE_GRAY,
3735 EL_INVISIBLE_STEELWALL,
3743 EL_WALL_EMERALD_YELLOW,
3744 EL_DYNABOMB_INCREASE_NUMBER,
3745 EL_DYNABOMB_INCREASE_SIZE,
3746 EL_DYNABOMB_INCREASE_POWER,
3750 EL_SOKOBAN_FIELD_EMPTY,
3751 EL_SOKOBAN_FIELD_FULL,
3752 EL_WALL_EMERALD_RED,
3753 EL_WALL_EMERALD_PURPLE,
3754 EL_ACID_POOL_TOPLEFT,
3755 EL_ACID_POOL_TOPRIGHT,
3756 EL_ACID_POOL_BOTTOMLEFT,
3757 EL_ACID_POOL_BOTTOM,
3758 EL_ACID_POOL_BOTTOMRIGHT,
3762 EL_BD_MAGIC_WALL_DEAD,
3764 EL_DC_MAGIC_WALL_DEAD,
3765 EL_AMOEBA_TO_DIAMOND,
3773 EL_SP_GRAVITY_PORT_RIGHT,
3774 EL_SP_GRAVITY_PORT_DOWN,
3775 EL_SP_GRAVITY_PORT_LEFT,
3776 EL_SP_GRAVITY_PORT_UP,
3777 EL_SP_PORT_HORIZONTAL,
3778 EL_SP_PORT_VERTICAL,
3789 EL_SP_HARDWARE_GRAY,
3790 EL_SP_HARDWARE_GREEN,
3791 EL_SP_HARDWARE_BLUE,
3793 EL_SP_HARDWARE_YELLOW,
3794 EL_SP_HARDWARE_BASE_1,
3795 EL_SP_HARDWARE_BASE_2,
3796 EL_SP_HARDWARE_BASE_3,
3797 EL_SP_HARDWARE_BASE_4,
3798 EL_SP_HARDWARE_BASE_5,
3799 EL_SP_HARDWARE_BASE_6,
3800 EL_SP_GRAVITY_ON_PORT_LEFT,
3801 EL_SP_GRAVITY_ON_PORT_RIGHT,
3802 EL_SP_GRAVITY_ON_PORT_UP,
3803 EL_SP_GRAVITY_ON_PORT_DOWN,
3804 EL_SP_GRAVITY_OFF_PORT_LEFT,
3805 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3806 EL_SP_GRAVITY_OFF_PORT_UP,
3807 EL_SP_GRAVITY_OFF_PORT_DOWN,
3808 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3809 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3810 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3811 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3812 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3813 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3814 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3815 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3816 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3817 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3818 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3819 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3820 EL_SIGN_EXCLAMATION,
3821 EL_SIGN_RADIOACTIVITY,
3828 EL_SIGN_ENTRY_FORBIDDEN,
3829 EL_SIGN_EMERGENCY_EXIT,
3837 EL_DC_STEELWALL_1_LEFT,
3838 EL_DC_STEELWALL_1_RIGHT,
3839 EL_DC_STEELWALL_1_TOP,
3840 EL_DC_STEELWALL_1_BOTTOM,
3841 EL_DC_STEELWALL_1_HORIZONTAL,
3842 EL_DC_STEELWALL_1_VERTICAL,
3843 EL_DC_STEELWALL_1_TOPLEFT,
3844 EL_DC_STEELWALL_1_TOPRIGHT,
3845 EL_DC_STEELWALL_1_BOTTOMLEFT,
3846 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3847 EL_DC_STEELWALL_1_TOPLEFT_2,
3848 EL_DC_STEELWALL_1_TOPRIGHT_2,
3849 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3850 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3851 EL_DC_STEELWALL_2_LEFT,
3852 EL_DC_STEELWALL_2_RIGHT,
3853 EL_DC_STEELWALL_2_TOP,
3854 EL_DC_STEELWALL_2_BOTTOM,
3855 EL_DC_STEELWALL_2_HORIZONTAL,
3856 EL_DC_STEELWALL_2_VERTICAL,
3857 EL_DC_STEELWALL_2_MIDDLE,
3858 EL_DC_STEELWALL_2_SINGLE,
3859 EL_STEELWALL_SLIPPERY,
3864 EL_EMC_WALL_SLIPPERY_1,
3865 EL_EMC_WALL_SLIPPERY_2,
3866 EL_EMC_WALL_SLIPPERY_3,
3867 EL_EMC_WALL_SLIPPERY_4,
3888 static int ep_em_slippery_wall[] =
3893 static int ep_gfx_crumbled[] =
3904 static int ep_editor_cascade_active[] =
3906 EL_INTERNAL_CASCADE_BD_ACTIVE,
3907 EL_INTERNAL_CASCADE_EM_ACTIVE,
3908 EL_INTERNAL_CASCADE_EMC_ACTIVE,
3909 EL_INTERNAL_CASCADE_RND_ACTIVE,
3910 EL_INTERNAL_CASCADE_SB_ACTIVE,
3911 EL_INTERNAL_CASCADE_SP_ACTIVE,
3912 EL_INTERNAL_CASCADE_DC_ACTIVE,
3913 EL_INTERNAL_CASCADE_DX_ACTIVE,
3914 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
3915 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
3916 EL_INTERNAL_CASCADE_CE_ACTIVE,
3917 EL_INTERNAL_CASCADE_GE_ACTIVE,
3918 EL_INTERNAL_CASCADE_REF_ACTIVE,
3919 EL_INTERNAL_CASCADE_USER_ACTIVE,
3920 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
3925 static int ep_editor_cascade_inactive[] =
3927 EL_INTERNAL_CASCADE_BD,
3928 EL_INTERNAL_CASCADE_EM,
3929 EL_INTERNAL_CASCADE_EMC,
3930 EL_INTERNAL_CASCADE_RND,
3931 EL_INTERNAL_CASCADE_SB,
3932 EL_INTERNAL_CASCADE_SP,
3933 EL_INTERNAL_CASCADE_DC,
3934 EL_INTERNAL_CASCADE_DX,
3935 EL_INTERNAL_CASCADE_CHARS,
3936 EL_INTERNAL_CASCADE_STEEL_CHARS,
3937 EL_INTERNAL_CASCADE_CE,
3938 EL_INTERNAL_CASCADE_GE,
3939 EL_INTERNAL_CASCADE_REF,
3940 EL_INTERNAL_CASCADE_USER,
3941 EL_INTERNAL_CASCADE_DYNAMIC,
3946 static int ep_obsolete[] =
3950 EL_EM_KEY_1_FILE_OBSOLETE,
3951 EL_EM_KEY_2_FILE_OBSOLETE,
3952 EL_EM_KEY_3_FILE_OBSOLETE,
3953 EL_EM_KEY_4_FILE_OBSOLETE,
3954 EL_ENVELOPE_OBSOLETE,
3963 } element_properties[] =
3965 { ep_diggable, EP_DIGGABLE },
3966 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
3967 { ep_dont_run_into, EP_DONT_RUN_INTO },
3968 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
3969 { ep_dont_touch, EP_DONT_TOUCH },
3970 { ep_indestructible, EP_INDESTRUCTIBLE },
3971 { ep_slippery, EP_SLIPPERY },
3972 { ep_can_change, EP_CAN_CHANGE },
3973 { ep_can_move, EP_CAN_MOVE },
3974 { ep_can_fall, EP_CAN_FALL },
3975 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
3976 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
3977 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
3978 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
3979 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
3980 { ep_explodes_impact, EP_EXPLODES_IMPACT },
3981 { ep_walkable_over, EP_WALKABLE_OVER },
3982 { ep_walkable_inside, EP_WALKABLE_INSIDE },
3983 { ep_walkable_under, EP_WALKABLE_UNDER },
3984 { ep_passable_over, EP_PASSABLE_OVER },
3985 { ep_passable_inside, EP_PASSABLE_INSIDE },
3986 { ep_passable_under, EP_PASSABLE_UNDER },
3987 { ep_droppable, EP_DROPPABLE },
3988 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
3989 { ep_pushable, EP_PUSHABLE },
3990 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
3991 { ep_protected, EP_PROTECTED },
3992 { ep_throwable, EP_THROWABLE },
3993 { ep_can_explode, EP_CAN_EXPLODE },
3994 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
3996 { ep_player, EP_PLAYER },
3997 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
3998 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
3999 { ep_switchable, EP_SWITCHABLE },
4000 { ep_bd_element, EP_BD_ELEMENT },
4001 { ep_sp_element, EP_SP_ELEMENT },
4002 { ep_sb_element, EP_SB_ELEMENT },
4004 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4005 { ep_food_penguin, EP_FOOD_PENGUIN },
4006 { ep_food_pig, EP_FOOD_PIG },
4007 { ep_historic_wall, EP_HISTORIC_WALL },
4008 { ep_historic_solid, EP_HISTORIC_SOLID },
4009 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4010 { ep_belt, EP_BELT },
4011 { ep_belt_active, EP_BELT_ACTIVE },
4012 { ep_belt_switch, EP_BELT_SWITCH },
4013 { ep_tube, EP_TUBE },
4014 { ep_acid_pool, EP_ACID_POOL },
4015 { ep_keygate, EP_KEYGATE },
4016 { ep_amoeboid, EP_AMOEBOID },
4017 { ep_amoebalive, EP_AMOEBALIVE },
4018 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4019 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4020 { ep_can_grow, EP_CAN_GROW },
4021 { ep_active_bomb, EP_ACTIVE_BOMB },
4022 { ep_inactive, EP_INACTIVE },
4024 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4026 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4028 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4029 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4031 { ep_obsolete, EP_OBSOLETE },
4038 /* always start with reliable default values (element has no properties) */
4039 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4040 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4041 SET_PROPERTY(i, j, FALSE);
4043 /* set all base element properties from above array definitions */
4044 for (i = 0; element_properties[i].elements != NULL; i++)
4045 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4046 SET_PROPERTY((element_properties[i].elements)[j],
4047 element_properties[i].property, TRUE);
4049 /* copy properties to some elements that are only stored in level file */
4050 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4051 for (j = 0; copy_properties[j][0] != -1; j++)
4052 if (HAS_PROPERTY(copy_properties[j][0], i))
4053 for (k = 1; k <= 4; k++)
4054 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4056 /* set static element properties that are not listed in array definitions */
4057 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4058 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4061 void InitElementPropertiesEngine(int engine_version)
4063 static int no_wall_properties[] =
4066 EP_COLLECTIBLE_ONLY,
4068 EP_DONT_COLLIDE_WITH,
4071 EP_CAN_SMASH_PLAYER,
4072 EP_CAN_SMASH_ENEMIES,
4073 EP_CAN_SMASH_EVERYTHING,
4078 EP_FOOD_DARK_YAMYAM,
4094 /* important: after initialization in InitElementPropertiesStatic(), the
4095 elements are not again initialized to a default value; therefore all
4096 changes have to make sure that they leave the element with a defined
4097 property (which means that conditional property changes must be set to
4098 a reliable default value before) */
4100 /* resolve group elements */
4101 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4102 ResolveGroupElement(EL_GROUP_START + i);
4104 /* set all special, combined or engine dependent element properties */
4105 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4107 /* ---------- INACTIVE ------------------------------------------------- */
4108 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4109 i <= EL_CHAR_END) ||
4110 (i >= EL_STEEL_CHAR_START &&
4111 i <= EL_STEEL_CHAR_END)));
4113 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4114 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4115 IS_WALKABLE_INSIDE(i) ||
4116 IS_WALKABLE_UNDER(i)));
4118 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4119 IS_PASSABLE_INSIDE(i) ||
4120 IS_PASSABLE_UNDER(i)));
4122 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4123 IS_PASSABLE_OVER(i)));
4125 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4126 IS_PASSABLE_INSIDE(i)));
4128 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4129 IS_PASSABLE_UNDER(i)));
4131 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4134 /* ---------- COLLECTIBLE ---------------------------------------------- */
4135 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4139 /* ---------- SNAPPABLE ------------------------------------------------ */
4140 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4141 IS_COLLECTIBLE(i) ||
4145 /* ---------- WALL ----------------------------------------------------- */
4146 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4148 for (j = 0; no_wall_properties[j] != -1; j++)
4149 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4150 i >= EL_FIRST_RUNTIME_UNREAL)
4151 SET_PROPERTY(i, EP_WALL, FALSE);
4153 if (IS_HISTORIC_WALL(i))
4154 SET_PROPERTY(i, EP_WALL, TRUE);
4156 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4157 if (engine_version < VERSION_IDENT(2,2,0,0))
4158 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4160 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4162 !IS_COLLECTIBLE(i)));
4164 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4165 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4166 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4168 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4169 IS_INDESTRUCTIBLE(i)));
4171 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4173 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4174 else if (engine_version < VERSION_IDENT(2,2,0,0))
4175 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4177 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4181 if (IS_CUSTOM_ELEMENT(i))
4183 /* these are additional properties which are initially false when set */
4185 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4187 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4188 if (DONT_COLLIDE_WITH(i))
4189 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4191 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4192 if (CAN_SMASH_EVERYTHING(i))
4193 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4194 if (CAN_SMASH_ENEMIES(i))
4195 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4198 /* ---------- CAN_SMASH ------------------------------------------------ */
4199 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4200 CAN_SMASH_ENEMIES(i) ||
4201 CAN_SMASH_EVERYTHING(i)));
4203 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4204 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4205 EXPLODES_BY_FIRE(i)));
4207 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4208 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4209 EXPLODES_SMASHED(i)));
4211 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4212 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4213 EXPLODES_IMPACT(i)));
4215 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4216 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4218 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4219 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4220 i == EL_BLACK_ORB));
4222 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4223 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4225 IS_CUSTOM_ELEMENT(i)));
4227 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4228 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4229 i == EL_SP_ELECTRON));
4231 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4232 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4233 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4234 getMoveIntoAcidProperty(&level, i));
4236 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4237 if (MAYBE_DONT_COLLIDE_WITH(i))
4238 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4239 getDontCollideWithProperty(&level, i));
4241 /* ---------- SP_PORT -------------------------------------------------- */
4242 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4243 IS_PASSABLE_INSIDE(i)));
4245 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4246 for (j = 0; j < level.num_android_clone_elements; j++)
4247 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4249 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4251 /* ---------- CAN_CHANGE ----------------------------------------------- */
4252 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4253 for (j = 0; j < element_info[i].num_change_pages; j++)
4254 if (element_info[i].change_page[j].can_change)
4255 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4257 /* ---------- HAS_ACTION ----------------------------------------------- */
4258 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4259 for (j = 0; j < element_info[i].num_change_pages; j++)
4260 if (element_info[i].change_page[j].has_action)
4261 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4263 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4264 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4267 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4269 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4270 element_info[i].crumbled[ACTION_DEFAULT] !=
4271 element_info[i].graphic[ACTION_DEFAULT]);
4273 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
4274 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4275 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
4278 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4279 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4280 IS_EDITOR_CASCADE_INACTIVE(i)));
4283 /* dynamically adjust element properties according to game engine version */
4285 static int ep_em_slippery_wall[] =
4290 EL_EXPANDABLE_WALL_HORIZONTAL,
4291 EL_EXPANDABLE_WALL_VERTICAL,
4292 EL_EXPANDABLE_WALL_ANY,
4293 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4294 EL_EXPANDABLE_STEELWALL_VERTICAL,
4295 EL_EXPANDABLE_STEELWALL_ANY,
4296 EL_EXPANDABLE_STEELWALL_GROWING,
4300 /* special EM style gems behaviour */
4301 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4302 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4303 level.em_slippery_gems);
4305 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4306 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4307 (level.em_slippery_gems &&
4308 engine_version > VERSION_IDENT(2,0,1,0)));
4311 /* this is needed because some graphics depend on element properties */
4312 if (game_status == GAME_MODE_PLAYING)
4313 InitElementGraphicInfo();
4316 void InitElementPropertiesAfterLoading(int engine_version)
4320 /* set some other uninitialized values of custom elements in older levels */
4321 if (engine_version < VERSION_IDENT(3,1,0,0))
4323 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4325 int element = EL_CUSTOM_START + i;
4327 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4329 element_info[element].explosion_delay = 17;
4330 element_info[element].ignition_delay = 8;
4335 static void InitGlobal()
4339 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4341 /* check if element_name_info entry defined for each element in "main.h" */
4342 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4343 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4345 element_info[i].token_name = element_name_info[i].token_name;
4346 element_info[i].class_name = element_name_info[i].class_name;
4347 element_info[i].editor_description=element_name_info[i].editor_description;
4350 printf("%04d: %s\n", i, element_name_info[i].token_name);
4354 global.autoplay_leveldir = NULL;
4355 global.convert_leveldir = NULL;
4357 global.frames_per_second = 0;
4358 global.fps_slowdown = FALSE;
4359 global.fps_slowdown_factor = 1;
4362 void Execute_Command(char *command)
4366 if (strEqual(command, "print graphicsinfo.conf"))
4368 printf("# You can configure additional/alternative image files here.\n");
4369 printf("# (The entries below are default and therefore commented out.)\n");
4371 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4373 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4376 for (i = 0; image_config[i].token != NULL; i++)
4377 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
4378 image_config[i].value));
4382 else if (strEqual(command, "print soundsinfo.conf"))
4384 printf("# You can configure additional/alternative sound files here.\n");
4385 printf("# (The entries below are default and therefore commented out.)\n");
4387 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4389 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4392 for (i = 0; sound_config[i].token != NULL; i++)
4393 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4394 sound_config[i].value));
4398 else if (strEqual(command, "print musicinfo.conf"))
4400 printf("# You can configure additional/alternative music files here.\n");
4401 printf("# (The entries below are default and therefore commented out.)\n");
4403 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4405 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4408 for (i = 0; music_config[i].token != NULL; i++)
4409 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
4410 music_config[i].value));
4414 else if (strEqual(command, "print editorsetup.conf"))
4416 printf("# You can configure your personal editor element list here.\n");
4417 printf("# (The entries below are default and therefore commented out.)\n");
4420 /* this is needed to be able to check element list for cascade elements */
4421 InitElementPropertiesStatic();
4422 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4424 PrintEditorElementList();
4428 else if (strEqual(command, "print helpanim.conf"))
4430 printf("# You can configure different element help animations here.\n");
4431 printf("# (The entries below are default and therefore commented out.)\n");
4434 for (i = 0; helpanim_config[i].token != NULL; i++)
4436 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4437 helpanim_config[i].value));
4439 if (strEqual(helpanim_config[i].token, "end"))
4445 else if (strEqual(command, "print helptext.conf"))
4447 printf("# You can configure different element help text here.\n");
4448 printf("# (The entries below are default and therefore commented out.)\n");
4451 for (i = 0; helptext_config[i].token != NULL; i++)
4452 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4453 helptext_config[i].value));
4457 else if (strncmp(command, "dump level ", 11) == 0)
4459 char *filename = &command[11];
4461 if (!fileExists(filename))
4462 Error(ERR_EXIT, "cannot open file '%s'", filename);
4464 LoadLevelFromFilename(&level, filename);
4469 else if (strncmp(command, "dump tape ", 10) == 0)
4471 char *filename = &command[10];
4473 if (!fileExists(filename))
4474 Error(ERR_EXIT, "cannot open file '%s'", filename);
4476 LoadTapeFromFilename(filename);
4481 else if (strncmp(command, "autoplay ", 9) == 0)
4483 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
4485 while (*str_ptr != '\0') /* continue parsing string */
4487 /* cut leading whitespace from string, replace it by string terminator */
4488 while (*str_ptr == ' ' || *str_ptr == '\t')
4491 if (*str_ptr == '\0') /* end of string reached */
4494 if (global.autoplay_leveldir == NULL) /* read level set string */
4496 global.autoplay_leveldir = str_ptr;
4497 global.autoplay_all = TRUE; /* default: play all tapes */
4499 for (i = 0; i < MAX_TAPES_PER_SET; i++)
4500 global.autoplay_level[i] = FALSE;
4502 else /* read level number string */
4504 int level_nr = atoi(str_ptr); /* get level_nr value */
4506 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
4507 global.autoplay_level[level_nr] = TRUE;
4509 global.autoplay_all = FALSE;
4512 /* advance string pointer to the next whitespace (or end of string) */
4513 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
4517 else if (strncmp(command, "convert ", 8) == 0)
4519 char *str_copy = getStringCopy(&command[8]);
4520 char *str_ptr = strchr(str_copy, ' ');
4522 global.convert_leveldir = str_copy;
4523 global.convert_level_nr = -1;
4525 if (str_ptr != NULL) /* level number follows */
4527 *str_ptr++ = '\0'; /* terminate leveldir string */
4528 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
4533 #if defined(TARGET_SDL)
4534 else if (strEqual(command, "SDL_ListModes"))
4539 SDL_Init(SDL_INIT_VIDEO);
4541 /* get available fullscreen/hardware modes */
4542 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
4544 /* check if there are any modes available */
4547 printf("No modes available!\n");
4552 /* check if our resolution is restricted */
4553 if (modes == (SDL_Rect **)-1)
4555 printf("All resolutions available.\n");
4559 printf("Available Modes:\n");
4561 for(i = 0; modes[i]; i++)
4562 printf(" %d x %d\n", modes[i]->w, modes[i]->h);
4572 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4576 static void InitSetup()
4578 LoadSetup(); /* global setup info */
4580 /* set some options from setup file */
4582 if (setup.options.verbose)
4583 options.verbose = TRUE;
4586 static void InitGameInfo()
4588 game.restart_level = FALSE;
4591 static void InitPlayerInfo()
4595 /* choose default local player */
4596 local_player = &stored_player[0];
4598 for (i = 0; i < MAX_PLAYERS; i++)
4599 stored_player[i].connected = FALSE;
4601 local_player->connected = TRUE;
4604 static void InitArtworkInfo()
4609 static char *get_string_in_brackets(char *string)
4611 char *string_in_brackets = checked_malloc(strlen(string) + 3);
4613 sprintf(string_in_brackets, "[%s]", string);
4615 return string_in_brackets;
4618 static char *get_level_id_suffix(int id_nr)
4620 char *id_suffix = checked_malloc(1 + 3 + 1);
4622 if (id_nr < 0 || id_nr > 999)
4625 sprintf(id_suffix, ".%03d", id_nr);
4631 static char *get_element_class_token(int element)
4633 char *element_class_name = element_info[element].class_name;
4634 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
4636 sprintf(element_class_token, "[%s]", element_class_name);
4638 return element_class_token;
4641 static char *get_action_class_token(int action)
4643 char *action_class_name = &element_action_info[action].suffix[1];
4644 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
4646 sprintf(action_class_token, "[%s]", action_class_name);
4648 return action_class_token;
4652 static void InitArtworkConfig()
4654 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
4655 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
4656 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
4657 static char *action_id_suffix[NUM_ACTIONS + 1];
4658 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
4659 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
4660 static char *level_id_suffix[MAX_LEVELS + 1];
4661 static char *dummy[1] = { NULL };
4662 static char *ignore_generic_tokens[] =
4668 static char **ignore_image_tokens;
4669 static char **ignore_sound_tokens;
4670 static char **ignore_music_tokens;
4671 int num_ignore_generic_tokens;
4672 int num_ignore_image_tokens;
4673 int num_ignore_sound_tokens;
4674 int num_ignore_music_tokens;
4677 /* dynamically determine list of generic tokens to be ignored */
4678 num_ignore_generic_tokens = 0;
4679 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
4680 num_ignore_generic_tokens++;
4682 /* dynamically determine list of image tokens to be ignored */
4683 num_ignore_image_tokens = num_ignore_generic_tokens;
4684 for (i = 0; image_config_vars[i].token != NULL; i++)
4685 num_ignore_image_tokens++;
4686 ignore_image_tokens =
4687 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
4688 for (i = 0; i < num_ignore_generic_tokens; i++)
4689 ignore_image_tokens[i] = ignore_generic_tokens[i];
4690 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
4691 ignore_image_tokens[num_ignore_generic_tokens + i] =
4692 image_config_vars[i].token;
4693 ignore_image_tokens[num_ignore_image_tokens] = NULL;
4695 /* dynamically determine list of sound tokens to be ignored */
4696 num_ignore_sound_tokens = num_ignore_generic_tokens;
4697 ignore_sound_tokens =
4698 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
4699 for (i = 0; i < num_ignore_generic_tokens; i++)
4700 ignore_sound_tokens[i] = ignore_generic_tokens[i];
4701 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
4703 /* dynamically determine list of music tokens to be ignored */
4704 num_ignore_music_tokens = num_ignore_generic_tokens;
4705 ignore_music_tokens =
4706 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
4707 for (i = 0; i < num_ignore_generic_tokens; i++)
4708 ignore_music_tokens[i] = ignore_generic_tokens[i];
4709 ignore_music_tokens[num_ignore_music_tokens] = NULL;
4711 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4712 image_id_prefix[i] = element_info[i].token_name;
4713 for (i = 0; i < NUM_FONTS; i++)
4714 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
4715 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
4717 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4718 sound_id_prefix[i] = element_info[i].token_name;
4719 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4720 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
4721 get_string_in_brackets(element_info[i].class_name);
4722 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
4724 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
4725 music_id_prefix[i] = music_prefix_info[i].prefix;
4726 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
4728 for (i = 0; i < NUM_ACTIONS; i++)
4729 action_id_suffix[i] = element_action_info[i].suffix;
4730 action_id_suffix[NUM_ACTIONS] = NULL;
4732 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
4733 direction_id_suffix[i] = element_direction_info[i].suffix;
4734 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
4736 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
4737 special_id_suffix[i] = special_suffix_info[i].suffix;
4738 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
4740 for (i = 0; i < MAX_LEVELS; i++)
4741 level_id_suffix[i] = get_level_id_suffix(i);
4742 level_id_suffix[MAX_LEVELS] = NULL;
4744 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
4745 image_id_prefix, action_id_suffix, direction_id_suffix,
4746 special_id_suffix, ignore_image_tokens);
4747 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
4748 sound_id_prefix, action_id_suffix, dummy,
4749 special_id_suffix, ignore_sound_tokens);
4750 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
4751 music_id_prefix, special_id_suffix, level_id_suffix,
4752 dummy, ignore_music_tokens);
4755 static void InitMixer()
4763 char *filename_font_initial = NULL;
4764 Bitmap *bitmap_font_initial = NULL;
4768 /* determine settings for initial font (for displaying startup messages) */
4769 for (i = 0; image_config[i].token != NULL; i++)
4771 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4773 char font_token[128];
4776 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
4777 len_font_token = strlen(font_token);
4779 if (strEqual(image_config[i].token, font_token))
4780 filename_font_initial = image_config[i].value;
4781 else if (strlen(image_config[i].token) > len_font_token &&
4782 strncmp(image_config[i].token, font_token, len_font_token) == 0)
4784 if (strEqual(&image_config[i].token[len_font_token], ".x"))
4785 font_initial[j].src_x = atoi(image_config[i].value);
4786 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
4787 font_initial[j].src_y = atoi(image_config[i].value);
4788 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
4789 font_initial[j].width = atoi(image_config[i].value);
4790 else if (strEqual(&image_config[i].token[len_font_token],".height"))
4791 font_initial[j].height = atoi(image_config[i].value);
4796 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4798 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
4799 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
4802 if (filename_font_initial == NULL) /* should not happen */
4803 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
4805 /* create additional image buffers for double-buffering and cross-fading */
4806 bitmap_db_cross = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
4807 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
4808 bitmap_db_panel = CreateBitmap(DXSIZE, DYSIZE, DEFAULT_DEPTH);
4809 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
4811 /* initialize screen properties */
4812 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
4813 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
4815 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
4816 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
4817 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
4819 bitmap_font_initial = LoadCustomImage(filename_font_initial);
4821 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4822 font_initial[j].bitmap = bitmap_font_initial;
4824 InitFontGraphicInfo();
4826 font_height = getFontHeight(FC_RED);
4829 DrawInitText(getWindowTitleString(), 20, FC_YELLOW);
4831 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
4833 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
4834 DrawInitText(PROGRAM_WEBSITE_STRING, WIN_YSIZE - 20 - font_height, FC_RED);
4836 DrawInitText("Loading graphics", 120, FC_GREEN);
4839 void RedrawBackground()
4841 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
4842 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
4844 redraw_mask = REDRAW_ALL;
4847 void InitGfxBackground()
4851 fieldbuffer = bitmap_db_field;
4852 SetDrawtoField(DRAW_BACKBUFFER);
4855 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
4859 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
4860 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
4863 for (x = 0; x < MAX_BUF_XSIZE; x++)
4864 for (y = 0; y < MAX_BUF_YSIZE; y++)
4867 redraw_mask = REDRAW_ALL;
4870 static void InitLevelInfo()
4872 LoadLevelInfo(); /* global level info */
4873 LoadLevelSetup_LastSeries(); /* last played series info */
4874 LoadLevelSetup_SeriesInfo(); /* last played level info */
4877 void InitLevelArtworkInfo()
4879 LoadLevelArtworkInfo();
4882 static void InitImages()
4884 setLevelArtworkDir(artwork.gfx_first);
4887 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
4888 leveldir_current->identifier,
4889 artwork.gfx_current_identifier,
4890 artwork.gfx_current->identifier,
4891 leveldir_current->graphics_set,
4892 leveldir_current->graphics_path);
4895 ReloadCustomImages();
4897 LoadCustomElementDescriptions();
4898 LoadSpecialMenuDesignSettings();
4900 ReinitializeGraphics();
4903 static void InitSound(char *identifier)
4905 if (identifier == NULL)
4906 identifier = artwork.snd_current->identifier;
4908 /* set artwork path to send it to the sound server process */
4909 setLevelArtworkDir(artwork.snd_first);
4911 InitReloadCustomSounds(identifier);
4912 ReinitializeSounds();
4915 static void InitMusic(char *identifier)
4917 if (identifier == NULL)
4918 identifier = artwork.mus_current->identifier;
4920 /* set artwork path to send it to the sound server process */
4921 setLevelArtworkDir(artwork.mus_first);
4923 InitReloadCustomMusic(identifier);
4924 ReinitializeMusic();
4927 void InitNetworkServer()
4929 #if defined(NETWORK_AVALIABLE)
4933 if (!options.network)
4936 #if defined(NETWORK_AVALIABLE)
4937 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
4939 if (!ConnectToServer(options.server_host, options.server_port))
4940 Error(ERR_EXIT, "cannot connect to network game server");
4942 SendToServer_PlayerName(setup.player_name);
4943 SendToServer_ProtocolVersion();
4946 SendToServer_NrWanted(nr_wanted);
4950 static char *getNewArtworkIdentifier(int type)
4952 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
4953 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
4954 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
4955 static boolean initialized[3] = { FALSE, FALSE, FALSE };
4956 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
4957 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
4958 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
4959 char *leveldir_identifier = leveldir_current->identifier;
4961 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
4962 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
4964 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
4966 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
4967 char *artwork_current_identifier;
4968 char *artwork_new_identifier = NULL; /* default: nothing has changed */
4970 /* leveldir_current may be invalid (level group, parent link) */
4971 if (!validLevelSeries(leveldir_current))
4974 /* 1st step: determine artwork set to be activated in descending order:
4975 --------------------------------------------------------------------
4976 1. setup artwork (when configured to override everything else)
4977 2. artwork set configured in "levelinfo.conf" of current level set
4978 (artwork in level directory will have priority when loading later)
4979 3. artwork in level directory (stored in artwork sub-directory)
4980 4. setup artwork (currently configured in setup menu) */
4982 if (setup_override_artwork)
4983 artwork_current_identifier = setup_artwork_set;
4984 else if (leveldir_artwork_set != NULL)
4985 artwork_current_identifier = leveldir_artwork_set;
4986 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
4987 artwork_current_identifier = leveldir_identifier;
4989 artwork_current_identifier = setup_artwork_set;
4992 /* 2nd step: check if it is really needed to reload artwork set
4993 ------------------------------------------------------------ */
4996 if (type == ARTWORK_TYPE_GRAPHICS)
4997 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
4998 artwork_new_identifier,
4999 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5000 artwork_current_identifier,
5001 leveldir_current->graphics_set,
5002 leveldir_current->identifier);
5005 /* ---------- reload if level set and also artwork set has changed ------- */
5006 if (leveldir_current_identifier[type] != leveldir_identifier &&
5007 (last_has_level_artwork_set[type] || has_level_artwork_set))
5008 artwork_new_identifier = artwork_current_identifier;
5010 leveldir_current_identifier[type] = leveldir_identifier;
5011 last_has_level_artwork_set[type] = has_level_artwork_set;
5014 if (type == ARTWORK_TYPE_GRAPHICS)
5015 printf("::: 1: '%s'\n", artwork_new_identifier);
5018 /* ---------- reload if "override artwork" setting has changed ----------- */
5019 if (last_override_level_artwork[type] != setup_override_artwork)
5020 artwork_new_identifier = artwork_current_identifier;
5022 last_override_level_artwork[type] = setup_override_artwork;
5025 if (type == ARTWORK_TYPE_GRAPHICS)
5026 printf("::: 2: '%s'\n", artwork_new_identifier);
5029 /* ---------- reload if current artwork identifier has changed ----------- */
5030 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5031 artwork_current_identifier))
5032 artwork_new_identifier = artwork_current_identifier;
5034 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5037 if (type == ARTWORK_TYPE_GRAPHICS)
5038 printf("::: 3: '%s'\n", artwork_new_identifier);
5041 /* ---------- do not reload directly after starting ---------------------- */
5042 if (!initialized[type])
5043 artwork_new_identifier = NULL;
5045 initialized[type] = TRUE;
5048 if (type == ARTWORK_TYPE_GRAPHICS)
5049 printf("::: 4: '%s'\n", artwork_new_identifier);
5053 if (type == ARTWORK_TYPE_GRAPHICS)
5054 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
5055 artwork.gfx_current_identifier, artwork_current_identifier,
5056 artwork.gfx_current->identifier, leveldir_current->graphics_set,
5057 artwork_new_identifier);
5060 return artwork_new_identifier;
5063 void ReloadCustomArtwork(int force_reload)
5065 char *gfx_new_identifier;
5066 char *snd_new_identifier;
5067 char *mus_new_identifier;
5068 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5069 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5070 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5071 boolean redraw_screen = FALSE;
5073 force_reload_gfx |= AdjustGraphicsForEMC();
5075 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5076 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5077 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5079 if (gfx_new_identifier != NULL || force_reload_gfx)
5082 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5083 artwork.gfx_current_identifier,
5085 artwork.gfx_current->identifier,
5086 leveldir_current->graphics_set);
5089 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
5093 redraw_screen = TRUE;
5096 if (snd_new_identifier != NULL || force_reload_snd)
5098 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
5100 InitSound(snd_new_identifier);
5102 redraw_screen = TRUE;
5105 if (mus_new_identifier != NULL || force_reload_mus)
5107 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
5109 InitMusic(mus_new_identifier);
5111 redraw_screen = TRUE;
5118 /* force redraw of (open or closed) door graphics */
5119 SetDoorState(DOOR_OPEN_ALL);
5120 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5124 FadeSetEnterScreen();
5125 // FadeSkipNextFadeOut();
5126 // FadeSetDisabled();
5131 fading = fading_none;
5136 void KeyboardAutoRepeatOffUnlessAutoplay()
5138 if (global.autoplay_leveldir == NULL)
5139 KeyboardAutoRepeatOff();
5143 /* ========================================================================= */
5145 /* ========================================================================= */
5149 InitGlobal(); /* initialize some global variables */
5151 if (options.execute_command)
5152 Execute_Command(options.execute_command);
5154 if (options.serveronly)
5156 #if defined(PLATFORM_UNIX)
5157 NetworkServer(options.server_port, options.serveronly);
5159 Error(ERR_WARN, "networking only supported in Unix version");
5162 exit(0); /* never reached, server loops forever */
5169 InitArtworkInfo(); /* needed before loading gfx, sound & music */
5170 InitArtworkConfig(); /* needed before forking sound child process */
5175 InitRND(NEW_RANDOMIZE);
5176 InitSimpleRandom(NEW_RANDOMIZE);
5181 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
5183 InitEventFilter(FilterMouseMotionEvents);
5185 InitElementPropertiesStatic();
5186 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5190 // debug_print_timestamp(0, "INIT");
5192 // debug_print_timestamp(0, "TIME InitLevelInfo: ");
5193 InitLevelArtworkInfo();
5194 // debug_print_timestamp(0, "TIME InitLevelArtworkInfo: ");
5196 InitImages(); /* needs to know current level directory */
5197 InitSound(NULL); /* needs to know current level directory */
5198 InitMusic(NULL); /* needs to know current level directory */
5200 InitGfxBackground();
5206 if (global.autoplay_leveldir)
5211 else if (global.convert_leveldir)
5217 game_status = GAME_MODE_MAIN;
5220 FadeSetEnterScreen();
5221 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
5222 FadeSkipNextFadeOut();
5223 // FadeSetDisabled();
5225 fading = fading_none;
5230 InitNetworkServer();
5233 void CloseAllAndExit(int exit_value)
5238 CloseAudio(); /* called after freeing sounds (needed for SDL) */
5246 #if defined(TARGET_SDL)
5247 if (network_server) /* terminate network server */
5248 SDL_KillThread(server_thread);
5251 CloseVideoDisplay();
5252 ClosePlatformDependentStuff();
5254 if (exit_value != 0)
5255 NotifyUserAboutErrorFile();