1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2006 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
14 #include "libgame/libgame.h"
29 #include "conf_e2g.c" /* include auto-generated data structure definitions */
30 #include "conf_esg.c" /* include auto-generated data structure definitions */
31 #include "conf_e2s.c" /* include auto-generated data structure definitions */
32 #include "conf_fnt.c" /* include auto-generated data structure definitions */
33 #include "conf_g2s.c" /* include auto-generated data structure definitions */
34 #include "conf_g2m.c" /* include auto-generated data structure definitions */
37 #define CONFIG_TOKEN_FONT_INITIAL "font.initial"
40 static struct FontBitmapInfo font_initial[NUM_INITIAL_FONTS];
42 static int copy_properties[][5] =
46 EL_BUG_LEFT, EL_BUG_RIGHT,
47 EL_BUG_UP, EL_BUG_DOWN
51 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
52 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
56 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
57 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
61 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
62 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
66 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
67 EL_PACMAN_UP, EL_PACMAN_DOWN
71 EL_YAMYAM_LEFT, EL_YAMYAM_RIGHT,
72 EL_YAMYAM_UP, EL_YAMYAM_DOWN
76 EL_MOLE_LEFT, EL_MOLE_RIGHT,
77 EL_MOLE_UP, EL_MOLE_DOWN
87 FreeLevelEditorGadgets();
96 static boolean gadgets_initialized = FALSE;
98 if (gadgets_initialized)
101 CreateLevelEditorGadgets();
105 CreateScreenGadgets();
107 InitGadgetsSoundCallback(PlaySoundActivating, PlaySoundSelecting);
109 gadgets_initialized = TRUE;
112 inline void InitElementSmallImagesScaledUp(int graphic)
114 CreateImageWithSmallImages(graphic, graphic_info[graphic].scale_up_factor);
117 void InitElementSmallImages()
119 static int special_graphics[] =
121 IMG_EDITOR_ELEMENT_BORDER,
122 IMG_EDITOR_ELEMENT_BORDER_INPUT,
123 IMG_EDITOR_CASCADE_LIST,
124 IMG_EDITOR_CASCADE_LIST_ACTIVE,
127 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
128 int num_property_mappings = getImageListPropertyMappingSize();
131 /* initialize normal images from static configuration */
132 for (i = 0; element_to_graphic[i].element > -1; i++)
133 InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
135 /* initialize special images from static configuration */
136 for (i = 0; element_to_special_graphic[i].element > -1; i++)
137 InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
139 /* initialize images from dynamic configuration (may be elements or other) */
140 for (i = 0; i < num_property_mappings; i++)
141 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
143 /* initialize special images from above list (non-element images) */
144 for (i = 0; special_graphics[i] > -1; i++)
145 InitElementSmallImagesScaledUp(special_graphics[i]);
148 void InitScaledImages()
152 /* scale normal images from static configuration, if not already scaled */
153 for (i = 0; i < NUM_IMAGE_FILES; i++)
154 ScaleImage(i, graphic_info[i].scale_up_factor);
158 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
159 void SetBitmaps_EM(Bitmap **em_bitmap)
161 em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
162 em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].bitmap;
166 static int getFontBitmapID(int font_nr)
170 if (game_status >= GAME_MODE_TITLE && game_status <= GAME_MODE_PSEUDO_PREVIEW)
171 special = game_status;
172 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
173 special = GFX_SPECIAL_ARG_MAIN;
174 else if (game_status == GAME_MODE_PLAYING)
175 special = GFX_SPECIAL_ARG_DOOR;
178 return font_info[font_nr].special_bitmap_id[special];
183 void InitFontGraphicInfo()
185 static struct FontBitmapInfo *font_bitmap_info = NULL;
186 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
187 int num_property_mappings = getImageListPropertyMappingSize();
188 int num_font_bitmaps = NUM_FONTS;
191 if (graphic_info == NULL) /* still at startup phase */
193 InitFontInfo(font_initial, NUM_INITIAL_FONTS, getFontBitmapID);
198 /* ---------- initialize font graphic definitions ---------- */
200 /* always start with reliable default values (normal font graphics) */
201 for (i = 0; i < NUM_FONTS; i++)
202 font_info[i].graphic = IMG_FONT_INITIAL_1;
204 /* initialize normal font/graphic mapping from static configuration */
205 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
207 int font_nr = font_to_graphic[i].font_nr;
208 int special = font_to_graphic[i].special;
209 int graphic = font_to_graphic[i].graphic;
214 font_info[font_nr].graphic = graphic;
217 /* always start with reliable default values (special font graphics) */
218 for (i = 0; i < NUM_FONTS; i++)
220 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
222 font_info[i].special_graphic[j] = font_info[i].graphic;
223 font_info[i].special_bitmap_id[j] = i;
227 /* initialize special font/graphic mapping from static configuration */
228 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
230 int font_nr = font_to_graphic[i].font_nr;
231 int special = font_to_graphic[i].special;
232 int graphic = font_to_graphic[i].graphic;
233 int base_graphic = font2baseimg(font_nr);
235 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
237 boolean base_redefined =
238 getImageListEntryFromImageID(base_graphic)->redefined;
239 boolean special_redefined =
240 getImageListEntryFromImageID(graphic)->redefined;
241 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
244 printf("::: %d, %d, %d / %d, %d, %d\n",
245 font_nr, special, graphic,
246 base_redefined, special_redefined, special_cloned);
250 // special_cloned = 0;
253 /* if the base font ("font.title_1", for example) has been redefined,
254 but not the special font ("font.title_1.LEVELS", for example), do not
255 use an existing (in this case considered obsolete) special font
256 anymore, but use the automatically determined default font */
257 /* special case: cloned special fonts must be explicitly redefined,
258 but are not automatically redefined by redefining base font */
259 if (base_redefined && !special_redefined && !special_cloned)
262 font_info[font_nr].special_graphic[special] = graphic;
263 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
268 /* initialize special font/graphic mapping from dynamic configuration */
269 for (i = 0; i < num_property_mappings; i++)
271 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
272 int special = property_mapping[i].ext3_index;
273 int graphic = property_mapping[i].artwork_index;
278 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
280 font_info[font_nr].special_graphic[special] = graphic;
281 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
287 printf("-0- T3.P: %d, %d\n",
288 font_info[FONT_TEXT_3].special_graphic[GFX_SPECIAL_ARG_PREVIEW],
289 font_info[FONT_TEXT_3].special_bitmap_id[GFX_SPECIAL_ARG_PREVIEW]);
291 printf("-0- T4.M: %d, %d\n",
292 font_info[FONT_TEXT_4].special_graphic[GFX_SPECIAL_ARG_MAIN],
293 font_info[FONT_TEXT_4].special_bitmap_id[GFX_SPECIAL_ARG_MAIN]);
297 /* correct special font/graphic mapping for cloned fonts
298 (per definition only needed for static configuration) */
299 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
301 int font_nr = font_to_graphic[i].font_nr;
302 int special = font_to_graphic[i].special;
303 int graphic = font_to_graphic[i].graphic;
305 int base_graphic = font2baseimg(font_nr);
308 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
311 boolean base_redefined =
312 getImageListEntryFromImageID(base_graphic)->redefined;
314 boolean special_redefined =
315 getImageListEntryFromImageID(graphic)->redefined;
316 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
318 if (special_cloned && !special_redefined)
323 printf(":2: %d, %d, %d / %d, %d, %d\n",
324 font_nr, special, graphic,
325 base_redefined, special_redefined, special_cloned);
328 for (j = 0; font_to_graphic[j].font_nr > -1; j++)
330 int font_nr2 = font_to_graphic[j].font_nr;
331 int special2 = font_to_graphic[j].special;
332 int graphic2 = font_to_graphic[j].graphic;
334 int base_graphic2 = font2baseimg(font_nr2);
337 if (graphic2 == graphic_info[graphic].clone_from)
340 printf(":2.1: %d, %d, %d, %d\n",
341 font_nr2, special2, graphic2, base_graphic2);
345 font_info[font_nr].special_graphic[special] =
346 font_info[font_nr2].special_graphic[special2];
347 font_info[font_nr].special_bitmap_id[special] =
348 font_info[font_nr2].special_bitmap_id[special2];
351 font_info[font_nr].special_graphic[special] = graphic2;
352 font_info[font_nr].special_bitmap_id[special] =
353 font_info[font_nr2].special_bitmap_id[special2];
355 font_info[font_nr].special_graphic[special] = graphic2;
356 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
367 /* reset non-redefined ".active" font graphics if normal font is redefined */
368 /* (this different treatment is needed because normal and active fonts are
369 independently defined ("active" is not a property of font definitions!) */
370 for (i = 0; i < NUM_FONTS; i++)
372 int font_nr_base = i;
373 int font_nr_active = FONT_ACTIVE(font_nr_base);
375 /* check only those fonts with exist as normal and ".active" variant */
376 if (font_nr_base != font_nr_active)
378 int base_graphic = font_info[font_nr_base].graphic;
379 int active_graphic = font_info[font_nr_active].graphic;
380 boolean base_redefined =
381 getImageListEntryFromImageID(base_graphic)->redefined;
382 boolean active_redefined =
383 getImageListEntryFromImageID(active_graphic)->redefined;
385 /* if the base font ("font.menu_1", for example) has been redefined,
386 but not the active font ("font.menu_1.active", for example), do not
387 use an existing (in this case considered obsolete) active font
388 anymore, but use the automatically determined default font */
389 if (base_redefined && !active_redefined)
390 font_info[font_nr_active].graphic = base_graphic;
392 /* now also check each "special" font (which may be the same as above) */
393 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
395 int base_graphic = font_info[font_nr_base].special_graphic[j];
396 int active_graphic = font_info[font_nr_active].special_graphic[j];
397 boolean base_redefined =
398 getImageListEntryFromImageID(base_graphic)->redefined;
399 boolean active_redefined =
400 getImageListEntryFromImageID(active_graphic)->redefined;
402 /* same as above, but check special graphic definitions, for example:
403 redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN" */
404 if (base_redefined && !active_redefined)
406 font_info[font_nr_active].special_graphic[j] =
407 font_info[font_nr_base].special_graphic[j];
408 font_info[font_nr_active].special_bitmap_id[j] =
409 font_info[font_nr_base].special_bitmap_id[j];
416 printf("-1- T4.M: %d, %d\n",
417 font_info[FONT_TEXT_4].special_graphic[GFX_SPECIAL_ARG_MAIN],
418 font_info[FONT_TEXT_4].special_bitmap_id[GFX_SPECIAL_ARG_MAIN]);
420 font_info[FONT_TEXT_4].special_graphic[GFX_SPECIAL_ARG_MAIN] =
422 font_info[FONT_TEXT_4].special_bitmap_id[GFX_SPECIAL_ARG_MAIN] =
426 font_info[FONT_TEXT_4].special_graphic[GFX_SPECIAL_ARG_MAIN] =
427 IMG_FONT_TEXT_3_PREVIEW;
428 font_info[FONT_TEXT_4].special_bitmap_id[GFX_SPECIAL_ARG_MAIN] =
433 /* ---------- initialize font bitmap array ---------- */
435 if (font_bitmap_info != NULL)
436 FreeFontInfo(font_bitmap_info);
439 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
441 /* ---------- initialize font bitmap definitions ---------- */
443 for (i = 0; i < NUM_FONTS; i++)
445 if (i < NUM_INITIAL_FONTS)
447 font_bitmap_info[i] = font_initial[i];
451 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
453 int font_bitmap_id = font_info[i].special_bitmap_id[j];
454 int graphic = font_info[i].special_graphic[j];
456 /* set 'graphic_info' for font entries, if uninitialized (guessed) */
457 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
459 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
460 graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
463 /* copy font relevant information from graphics information */
464 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
465 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
466 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
467 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
468 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
470 font_bitmap_info[font_bitmap_id].draw_xoffset =
471 graphic_info[graphic].draw_xoffset;
472 font_bitmap_info[font_bitmap_id].draw_yoffset =
473 graphic_info[graphic].draw_yoffset;
475 font_bitmap_info[font_bitmap_id].num_chars =
476 graphic_info[graphic].anim_frames;
477 font_bitmap_info[font_bitmap_id].num_chars_per_line =
478 graphic_info[graphic].anim_frames_per_line;
482 InitFontInfo(font_bitmap_info, num_font_bitmaps, getFontBitmapID);
485 printf("-X- T3.P: %d, %d\n",
486 font_info[FONT_TEXT_3].special_graphic[GFX_SPECIAL_ARG_PREVIEW],
487 font_info[FONT_TEXT_3].special_bitmap_id[GFX_SPECIAL_ARG_PREVIEW]);
489 printf("-4- T4.M: %d, %d\n",
490 font_info[FONT_TEXT_4].special_graphic[GFX_SPECIAL_ARG_MAIN],
491 font_info[FONT_TEXT_4].special_bitmap_id[GFX_SPECIAL_ARG_MAIN]);
495 void InitElementGraphicInfo()
497 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
498 int num_property_mappings = getImageListPropertyMappingSize();
501 if (graphic_info == NULL) /* still at startup phase */
504 /* set values to -1 to identify later as "uninitialized" values */
505 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
507 for (act = 0; act < NUM_ACTIONS; act++)
509 element_info[i].graphic[act] = -1;
510 element_info[i].crumbled[act] = -1;
512 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
514 element_info[i].direction_graphic[act][dir] = -1;
515 element_info[i].direction_crumbled[act][dir] = -1;
520 /* initialize normal element/graphic mapping from static configuration */
521 for (i = 0; element_to_graphic[i].element > -1; i++)
523 int element = element_to_graphic[i].element;
524 int action = element_to_graphic[i].action;
525 int direction = element_to_graphic[i].direction;
526 boolean crumbled = element_to_graphic[i].crumbled;
527 int graphic = element_to_graphic[i].graphic;
528 int base_graphic = el2baseimg(element);
530 if (graphic_info[graphic].bitmap == NULL)
533 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
536 boolean base_redefined =
537 getImageListEntryFromImageID(base_graphic)->redefined;
538 boolean act_dir_redefined =
539 getImageListEntryFromImageID(graphic)->redefined;
541 /* if the base graphic ("emerald", for example) has been redefined,
542 but not the action graphic ("emerald.falling", for example), do not
543 use an existing (in this case considered obsolete) action graphic
544 anymore, but use the automatically determined default graphic */
545 if (base_redefined && !act_dir_redefined)
550 action = ACTION_DEFAULT;
555 element_info[element].direction_crumbled[action][direction] = graphic;
557 element_info[element].crumbled[action] = graphic;
562 element_info[element].direction_graphic[action][direction] = graphic;
564 element_info[element].graphic[action] = graphic;
568 /* initialize normal element/graphic mapping from dynamic configuration */
569 for (i = 0; i < num_property_mappings; i++)
571 int element = property_mapping[i].base_index;
572 int action = property_mapping[i].ext1_index;
573 int direction = property_mapping[i].ext2_index;
574 int special = property_mapping[i].ext3_index;
575 int graphic = property_mapping[i].artwork_index;
576 boolean crumbled = FALSE;
578 if (special == GFX_SPECIAL_ARG_CRUMBLED)
584 if (graphic_info[graphic].bitmap == NULL)
587 if (element >= MAX_NUM_ELEMENTS || special != -1)
591 action = ACTION_DEFAULT;
596 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
597 element_info[element].direction_crumbled[action][dir] = -1;
600 element_info[element].direction_crumbled[action][direction] = graphic;
602 element_info[element].crumbled[action] = graphic;
607 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
608 element_info[element].direction_graphic[action][dir] = -1;
611 element_info[element].direction_graphic[action][direction] = graphic;
613 element_info[element].graphic[action] = graphic;
617 /* now copy all graphics that are defined to be cloned from other graphics */
618 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
620 int graphic = element_info[i].graphic[ACTION_DEFAULT];
621 int crumbled_like, diggable_like;
626 crumbled_like = graphic_info[graphic].crumbled_like;
627 diggable_like = graphic_info[graphic].diggable_like;
629 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
631 for (act = 0; act < NUM_ACTIONS; act++)
632 element_info[i].crumbled[act] =
633 element_info[crumbled_like].crumbled[act];
634 for (act = 0; act < NUM_ACTIONS; act++)
635 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
636 element_info[i].direction_crumbled[act][dir] =
637 element_info[crumbled_like].direction_crumbled[act][dir];
640 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
642 element_info[i].graphic[ACTION_DIGGING] =
643 element_info[diggable_like].graphic[ACTION_DIGGING];
644 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
645 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
646 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
651 /* set hardcoded definitions for some runtime elements without graphic */
652 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
656 /* set hardcoded definitions for some internal elements without graphic */
657 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
659 if (IS_EDITOR_CASCADE_INACTIVE(i))
660 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
661 else if (IS_EDITOR_CASCADE_ACTIVE(i))
662 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
666 /* now set all undefined/invalid graphics to -1 to set to default after it */
667 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
669 for (act = 0; act < NUM_ACTIONS; act++)
673 graphic = element_info[i].graphic[act];
674 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
675 element_info[i].graphic[act] = -1;
677 graphic = element_info[i].crumbled[act];
678 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
679 element_info[i].crumbled[act] = -1;
681 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
683 graphic = element_info[i].direction_graphic[act][dir];
684 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
685 element_info[i].direction_graphic[act][dir] = -1;
687 graphic = element_info[i].direction_crumbled[act][dir];
688 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
689 element_info[i].direction_crumbled[act][dir] = -1;
694 /* adjust graphics with 2nd tile for movement according to direction
695 (do this before correcting '-1' values to minimize calculations) */
696 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
698 for (act = 0; act < NUM_ACTIONS; act++)
700 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
702 int graphic = element_info[i].direction_graphic[act][dir];
703 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
705 if (act == ACTION_FALLING) /* special case */
706 graphic = element_info[i].graphic[act];
709 graphic_info[graphic].double_movement &&
710 graphic_info[graphic].swap_double_tiles != 0)
712 struct GraphicInfo *g = &graphic_info[graphic];
713 int src_x_front = g->src_x;
714 int src_y_front = g->src_y;
715 int src_x_back = g->src_x + g->offset2_x;
716 int src_y_back = g->src_y + g->offset2_y;
717 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
719 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
720 src_y_front < src_y_back);
721 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
722 boolean swap_movement_tiles_autodetected =
723 (!frames_are_ordered_diagonally &&
724 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
725 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
726 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
727 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
730 /* swap frontside and backside graphic tile coordinates, if needed */
731 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
733 /* get current (wrong) backside tile coordinates */
734 getGraphicSourceExt(graphic, 0, &dummy, &src_x_back, &src_y_back,
737 /* set frontside tile coordinates to backside tile coordinates */
738 g->src_x = src_x_back;
739 g->src_y = src_y_back;
741 /* invert tile offset to point to new backside tile coordinates */
745 /* do not swap front and backside tiles again after correction */
746 g->swap_double_tiles = 0;
753 /* now set all '-1' values to element specific default values */
754 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
756 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
757 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
758 int default_direction_graphic[NUM_DIRECTIONS_FULL];
759 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
761 if (default_graphic == -1)
762 default_graphic = IMG_UNKNOWN;
764 if (default_crumbled == -1)
765 default_crumbled = default_graphic;
767 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
768 if (default_crumbled == -1)
769 default_crumbled = IMG_EMPTY;
772 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
774 default_direction_graphic[dir] =
775 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
776 default_direction_crumbled[dir] =
777 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
779 if (default_direction_graphic[dir] == -1)
780 default_direction_graphic[dir] = default_graphic;
782 if (default_direction_crumbled[dir] == -1)
783 default_direction_crumbled[dir] = default_direction_graphic[dir];
785 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
786 if (default_direction_crumbled[dir] == -1)
787 default_direction_crumbled[dir] = default_crumbled;
791 for (act = 0; act < NUM_ACTIONS; act++)
793 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
794 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
795 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
796 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
797 act == ACTION_TURNING_FROM_RIGHT ||
798 act == ACTION_TURNING_FROM_UP ||
799 act == ACTION_TURNING_FROM_DOWN);
801 /* generic default action graphic (defined by "[default]" directive) */
802 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
803 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
804 int default_remove_graphic = IMG_EMPTY;
806 if (act_remove && default_action_graphic != -1)
807 default_remove_graphic = default_action_graphic;
809 /* look for special default action graphic (classic game specific) */
810 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
811 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
812 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
813 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
814 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
815 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
817 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
818 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
819 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
820 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
821 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
822 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
825 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
826 /* !!! make this better !!! */
827 if (i == EL_EMPTY_SPACE)
829 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
830 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
834 if (default_action_graphic == -1)
835 default_action_graphic = default_graphic;
837 if (default_action_crumbled == -1)
838 default_action_crumbled = default_action_graphic;
840 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
841 if (default_action_crumbled == -1)
842 default_action_crumbled = default_crumbled;
845 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
847 /* use action graphic as the default direction graphic, if undefined */
848 int default_action_direction_graphic = element_info[i].graphic[act];
849 int default_action_direction_crumbled = element_info[i].crumbled[act];
851 /* no graphic for current action -- use default direction graphic */
852 if (default_action_direction_graphic == -1)
853 default_action_direction_graphic =
854 (act_remove ? default_remove_graphic :
856 element_info[i].direction_graphic[ACTION_TURNING][dir] :
857 default_action_graphic != default_graphic ?
858 default_action_graphic :
859 default_direction_graphic[dir]);
861 if (element_info[i].direction_graphic[act][dir] == -1)
862 element_info[i].direction_graphic[act][dir] =
863 default_action_direction_graphic;
866 if (default_action_direction_crumbled == -1)
867 default_action_direction_crumbled =
868 element_info[i].direction_graphic[act][dir];
870 if (default_action_direction_crumbled == -1)
871 default_action_direction_crumbled =
872 (act_remove ? default_remove_graphic :
874 element_info[i].direction_crumbled[ACTION_TURNING][dir] :
875 default_action_crumbled != default_crumbled ?
876 default_action_crumbled :
877 default_direction_crumbled[dir]);
880 if (element_info[i].direction_crumbled[act][dir] == -1)
881 element_info[i].direction_crumbled[act][dir] =
882 default_action_direction_crumbled;
885 /* no graphic for this specific action -- use default action graphic */
886 if (element_info[i].graphic[act] == -1)
887 element_info[i].graphic[act] =
888 (act_remove ? default_remove_graphic :
889 act_turning ? element_info[i].graphic[ACTION_TURNING] :
890 default_action_graphic);
892 if (element_info[i].crumbled[act] == -1)
893 element_info[i].crumbled[act] = element_info[i].graphic[act];
895 if (element_info[i].crumbled[act] == -1)
896 element_info[i].crumbled[act] =
897 (act_remove ? default_remove_graphic :
898 act_turning ? element_info[i].crumbled[ACTION_TURNING] :
899 default_action_crumbled);
905 /* !!! THIS ALSO CLEARS SPECIAL FLAGS (AND IS NOT NEEDED ANYWAY) !!! */
906 /* set animation mode to "none" for each graphic with only 1 frame */
907 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
909 for (act = 0; act < NUM_ACTIONS; act++)
911 int graphic = element_info[i].graphic[act];
912 int crumbled = element_info[i].crumbled[act];
914 if (graphic_info[graphic].anim_frames == 1)
915 graphic_info[graphic].anim_mode = ANIM_NONE;
916 if (graphic_info[crumbled].anim_frames == 1)
917 graphic_info[crumbled].anim_mode = ANIM_NONE;
919 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
921 graphic = element_info[i].direction_graphic[act][dir];
922 crumbled = element_info[i].direction_crumbled[act][dir];
924 if (graphic_info[graphic].anim_frames == 1)
925 graphic_info[graphic].anim_mode = ANIM_NONE;
926 if (graphic_info[crumbled].anim_frames == 1)
927 graphic_info[crumbled].anim_mode = ANIM_NONE;
937 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
938 if (element_info[i].graphic[ACTION_DEFAULT] == IMG_UNKNOWN &&
940 Error(ERR_INFO, "warning: no graphic for element '%s' (%d)",
941 element_info[i].token_name, i);
947 void InitElementSpecialGraphicInfo()
949 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
950 int num_property_mappings = getImageListPropertyMappingSize();
953 /* always start with reliable default values */
954 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
955 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
956 element_info[i].special_graphic[j] =
957 element_info[i].graphic[ACTION_DEFAULT];
959 /* initialize special element/graphic mapping from static configuration */
960 for (i = 0; element_to_special_graphic[i].element > -1; i++)
962 int element = element_to_special_graphic[i].element;
963 int special = element_to_special_graphic[i].special;
964 int graphic = element_to_special_graphic[i].graphic;
965 int base_graphic = el2baseimg(element);
966 boolean base_redefined =
967 getImageListEntryFromImageID(base_graphic)->redefined;
968 boolean special_redefined =
969 getImageListEntryFromImageID(graphic)->redefined;
971 /* if the base graphic ("emerald", for example) has been redefined,
972 but not the special graphic ("emerald.EDITOR", for example), do not
973 use an existing (in this case considered obsolete) special graphic
974 anymore, but use the automatically created (down-scaled) graphic */
975 if (base_redefined && !special_redefined)
978 element_info[element].special_graphic[special] = graphic;
981 /* initialize special element/graphic mapping from dynamic configuration */
982 for (i = 0; i < num_property_mappings; i++)
984 int element = property_mapping[i].base_index;
985 int special = property_mapping[i].ext3_index;
986 int graphic = property_mapping[i].artwork_index;
988 if (element >= MAX_NUM_ELEMENTS)
991 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
992 element_info[element].special_graphic[special] = graphic;
995 /* now set all undefined/invalid graphics to default */
996 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
997 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
998 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
999 element_info[i].special_graphic[j] =
1000 element_info[i].graphic[ACTION_DEFAULT];
1003 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
1008 if (type != TYPE_TOKEN)
1009 return get_parameter_value(value_raw, suffix, type);
1011 if (strEqual(value_raw, ARG_UNDEFINED))
1012 return ARG_UNDEFINED_VALUE;
1014 /* !!! OPTIMIZE THIS BY USING HASH !!! */
1015 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1016 if (strEqual(element_info[i].token_name, value_raw))
1019 /* !!! OPTIMIZE THIS BY USING HASH !!! */
1020 for (i = 0; image_config[i].token != NULL; i++)
1022 int len_config_value = strlen(image_config[i].value);
1024 if (!strEqual(&image_config[i].value[len_config_value - 4], ".pcx") &&
1025 !strEqual(&image_config[i].value[len_config_value - 4], ".wav") &&
1026 !strEqual(image_config[i].value, UNDEFINED_FILENAME))
1029 if (strEqual(image_config[i].token, value_raw))
1038 static int get_scaled_graphic_width(int graphic)
1040 int original_width = getOriginalImageWidthFromImageID(graphic);
1041 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1043 return original_width * scale_up_factor;
1046 static int get_scaled_graphic_height(int graphic)
1048 int original_height = getOriginalImageHeightFromImageID(graphic);
1049 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1051 return original_height * scale_up_factor;
1054 static void set_graphic_parameters(int graphic)
1056 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1057 char **parameter_raw = image->parameter;
1058 Bitmap *src_bitmap = getBitmapFromImageID(graphic);
1059 int parameter[NUM_GFX_ARGS];
1060 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1061 int anim_frames_per_line = 1;
1064 /* if fallback to default artwork is done, also use the default parameters */
1065 if (image->fallback_to_default)
1066 parameter_raw = image->default_parameter;
1068 /* get integer values from string parameters */
1069 for (i = 0; i < NUM_GFX_ARGS; i++)
1070 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1071 image_config_suffix[i].token,
1072 image_config_suffix[i].type);
1074 graphic_info[graphic].bitmap = src_bitmap;
1076 /* always start with reliable default values */
1077 graphic_info[graphic].src_image_width = 0;
1078 graphic_info[graphic].src_image_height = 0;
1079 graphic_info[graphic].src_x = 0;
1080 graphic_info[graphic].src_y = 0;
1081 graphic_info[graphic].width = TILEX; /* default for element graphics */
1082 graphic_info[graphic].height = TILEY; /* default for element graphics */
1083 graphic_info[graphic].offset_x = 0; /* one or both of these values ... */
1084 graphic_info[graphic].offset_y = 0; /* ... will be corrected later */
1085 graphic_info[graphic].offset2_x = 0; /* one or both of these values ... */
1086 graphic_info[graphic].offset2_y = 0; /* ... will be corrected later */
1087 graphic_info[graphic].swap_double_tiles = -1; /* auto-detect tile swapping */
1088 graphic_info[graphic].crumbled_like = -1; /* do not use clone element */
1089 graphic_info[graphic].diggable_like = -1; /* do not use clone element */
1090 graphic_info[graphic].border_size = TILEX / 8; /* "CRUMBLED" border size */
1091 graphic_info[graphic].scale_up_factor = 1; /* default: no scaling up */
1092 graphic_info[graphic].clone_from = -1; /* do not use clone graphic */
1093 graphic_info[graphic].anim_delay_fixed = 0;
1094 graphic_info[graphic].anim_delay_random = 0;
1095 graphic_info[graphic].post_delay_fixed = 0;
1096 graphic_info[graphic].post_delay_random = 0;
1097 graphic_info[graphic].fade_delay = -1;
1098 graphic_info[graphic].post_delay = -1;
1099 graphic_info[graphic].auto_delay = -1;
1100 graphic_info[graphic].align = ALIGN_CENTER; /* default for title screens */
1101 graphic_info[graphic].sort_priority = 0; /* default for title screens */
1104 /* optional zoom factor for scaling up the image to a larger size */
1105 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1106 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1107 if (graphic_info[graphic].scale_up_factor < 1)
1108 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
1112 if (graphic_info[graphic].use_image_size)
1114 /* set new default bitmap size (with scaling, but without small images) */
1115 graphic_info[graphic].width = get_scaled_graphic_width(graphic);
1116 graphic_info[graphic].height = get_scaled_graphic_height(graphic);
1120 /* optional x and y tile position of animation frame sequence */
1121 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1122 graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
1123 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1124 graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
1126 /* optional x and y pixel position of animation frame sequence */
1127 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1128 graphic_info[graphic].src_x = parameter[GFX_ARG_X];
1129 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1130 graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
1132 /* optional width and height of each animation frame */
1133 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1134 graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
1135 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1136 graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
1139 /* optional zoom factor for scaling up the image to a larger size */
1140 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1141 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1142 if (graphic_info[graphic].scale_up_factor < 1)
1143 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
1148 /* get final bitmap size (with scaling, but without small images) */
1149 int src_image_width = get_scaled_graphic_width(graphic);
1150 int src_image_height = get_scaled_graphic_height(graphic);
1152 anim_frames_per_row = src_image_width / graphic_info[graphic].width;
1153 anim_frames_per_col = src_image_height / graphic_info[graphic].height;
1155 graphic_info[graphic].src_image_width = src_image_width;
1156 graphic_info[graphic].src_image_height = src_image_height;
1159 /* correct x or y offset dependent of vertical or horizontal frame order */
1160 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1162 graphic_info[graphic].offset_y =
1163 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1164 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
1165 anim_frames_per_line = anim_frames_per_col;
1167 else /* frames are ordered horizontally */
1169 graphic_info[graphic].offset_x =
1170 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1171 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
1172 anim_frames_per_line = anim_frames_per_row;
1175 /* optionally, the x and y offset of frames can be specified directly */
1176 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1177 graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
1178 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1179 graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
1181 /* optionally, moving animations may have separate start and end graphics */
1182 graphic_info[graphic].double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1184 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1185 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1187 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1188 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1189 graphic_info[graphic].offset2_y =
1190 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1191 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].height);
1192 else /* frames are ordered horizontally */
1193 graphic_info[graphic].offset2_x =
1194 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1195 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].width);
1197 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1198 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1199 graphic_info[graphic].offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1200 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1201 graphic_info[graphic].offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1203 /* optionally, the second movement tile can be specified as start tile */
1204 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1205 graphic_info[graphic].swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1207 /* automatically determine correct number of frames, if not defined */
1208 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1209 graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
1210 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1211 graphic_info[graphic].anim_frames = anim_frames_per_row;
1212 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1213 graphic_info[graphic].anim_frames = anim_frames_per_col;
1215 graphic_info[graphic].anim_frames = 1;
1217 if (graphic_info[graphic].anim_frames == 0) /* frames must be at least 1 */
1218 graphic_info[graphic].anim_frames = 1;
1220 graphic_info[graphic].anim_frames_per_line =
1221 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1222 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1224 graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
1225 if (graphic_info[graphic].anim_delay == 0) /* delay must be at least 1 */
1226 graphic_info[graphic].anim_delay = 1;
1228 graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
1230 if (graphic_info[graphic].anim_frames == 1)
1231 graphic_info[graphic].anim_mode = ANIM_NONE;
1234 /* automatically determine correct start frame, if not defined */
1235 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1236 graphic_info[graphic].anim_start_frame = 0;
1237 else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
1238 graphic_info[graphic].anim_start_frame =
1239 graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1241 graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
1243 /* animation synchronized with global frame counter, not move position */
1244 graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1246 /* optional element for cloning crumble graphics */
1247 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1248 graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1250 /* optional element for cloning digging graphics */
1251 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1252 graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1254 /* optional border size for "crumbling" diggable graphics */
1255 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1256 graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
1258 /* this is only used for player "boring" and "sleeping" actions */
1259 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1260 graphic_info[graphic].anim_delay_fixed =
1261 parameter[GFX_ARG_ANIM_DELAY_FIXED];
1262 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1263 graphic_info[graphic].anim_delay_random =
1264 parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1265 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1266 graphic_info[graphic].post_delay_fixed =
1267 parameter[GFX_ARG_POST_DELAY_FIXED];
1268 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1269 graphic_info[graphic].post_delay_random =
1270 parameter[GFX_ARG_POST_DELAY_RANDOM];
1272 /* this is only used for toon animations */
1273 graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
1274 graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY];
1276 /* this is only used for drawing font characters */
1277 graphic_info[graphic].draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1278 graphic_info[graphic].draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1280 /* this is only used for drawing envelope graphics */
1281 graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1283 /* optional graphic for cloning all graphics settings */
1284 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1285 graphic_info[graphic].clone_from = parameter[GFX_ARG_CLONE_FROM];
1287 /* optional settings for drawing title screens */
1288 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1289 graphic_info[graphic].fade_delay = parameter[GFX_ARG_FADE_DELAY];
1290 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1291 graphic_info[graphic].post_delay = parameter[GFX_ARG_POST_DELAY];
1292 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1293 graphic_info[graphic].auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1294 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1295 graphic_info[graphic].align = parameter[GFX_ARG_ALIGN];
1296 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1297 graphic_info[graphic].sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1300 static void set_cloned_graphic_parameters(int graphic)
1302 int fallback_graphic = IMG_CHAR_EXCLAM;
1303 int max_num_images = getImageListSize();
1304 int clone_graphic = graphic_info[graphic].clone_from;
1305 int num_references_followed = 1;
1307 while (graphic_info[clone_graphic].clone_from != -1 &&
1308 num_references_followed < max_num_images)
1310 clone_graphic = graphic_info[clone_graphic].clone_from;
1312 num_references_followed++;
1315 if (num_references_followed >= max_num_images)
1317 Error(ERR_INFO_LINE, "-");
1318 Error(ERR_INFO, "warning: error found in config file:");
1319 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1320 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1321 Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1322 Error(ERR_INFO, "custom graphic rejected for this element/action");
1324 if (graphic == fallback_graphic)
1325 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1327 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1328 Error(ERR_INFO_LINE, "-");
1330 graphic_info[graphic] = graphic_info[fallback_graphic];
1334 graphic_info[graphic] = graphic_info[clone_graphic];
1335 graphic_info[graphic].clone_from = clone_graphic;
1339 static void InitGraphicInfo()
1341 int fallback_graphic = IMG_CHAR_EXCLAM;
1342 int num_images = getImageListSize();
1345 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1346 static boolean clipmasks_initialized = FALSE;
1348 XGCValues clip_gc_values;
1349 unsigned long clip_gc_valuemask;
1350 GC copy_clipmask_gc = None;
1353 /* use image size as default values for width and height for these images */
1354 static int full_size_graphics[] =
1359 IMG_BACKGROUND_ENVELOPE_1,
1360 IMG_BACKGROUND_ENVELOPE_2,
1361 IMG_BACKGROUND_ENVELOPE_3,
1362 IMG_BACKGROUND_ENVELOPE_4,
1365 IMG_BACKGROUND_TITLE,
1366 IMG_BACKGROUND_MESSAGE,
1367 IMG_BACKGROUND_MAIN,
1368 IMG_BACKGROUND_LEVELS,
1369 IMG_BACKGROUND_SCORES,
1370 IMG_BACKGROUND_EDITOR,
1371 IMG_BACKGROUND_INFO,
1372 IMG_BACKGROUND_INFO_ELEMENTS,
1373 IMG_BACKGROUND_INFO_MUSIC,
1374 IMG_BACKGROUND_INFO_CREDITS,
1375 IMG_BACKGROUND_INFO_PROGRAM,
1376 IMG_BACKGROUND_INFO_LEVELSET,
1377 IMG_BACKGROUND_SETUP,
1378 IMG_BACKGROUND_DOOR,
1380 IMG_TITLESCREEN_INITIAL_1,
1381 IMG_TITLESCREEN_INITIAL_2,
1382 IMG_TITLESCREEN_INITIAL_3,
1383 IMG_TITLESCREEN_INITIAL_4,
1384 IMG_TITLESCREEN_INITIAL_5,
1394 checked_free(graphic_info);
1396 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1399 /* initialize "use_image_size" flag with default value */
1400 for (i = 0; i < num_images; i++)
1401 graphic_info[i].use_image_size = FALSE;
1403 /* initialize "use_image_size" flag from static configuration above */
1404 for (i = 0; full_size_graphics[i] != -1; i++)
1405 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1408 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1409 if (clipmasks_initialized)
1411 for (i = 0; i < num_images; i++)
1413 if (graphic_info[i].clip_mask)
1414 XFreePixmap(display, graphic_info[i].clip_mask);
1415 if (graphic_info[i].clip_gc)
1416 XFreeGC(display, graphic_info[i].clip_gc);
1418 graphic_info[i].clip_mask = None;
1419 graphic_info[i].clip_gc = None;
1424 /* first set all graphic paramaters ... */
1425 for (i = 0; i < num_images; i++)
1426 set_graphic_parameters(i);
1428 /* ... then copy these parameters for cloned graphics */
1429 for (i = 0; i < num_images; i++)
1430 if (graphic_info[i].clone_from != -1)
1431 set_cloned_graphic_parameters(i);
1433 for (i = 0; i < num_images; i++)
1438 int first_frame, last_frame;
1439 int src_bitmap_width, src_bitmap_height;
1441 /* now check if no animation frames are outside of the loaded image */
1443 if (graphic_info[i].bitmap == NULL)
1444 continue; /* skip check for optional images that are undefined */
1446 /* get image size (this can differ from the standard element tile size!) */
1447 width = graphic_info[i].width;
1448 height = graphic_info[i].height;
1450 /* get final bitmap size (with scaling, but without small images) */
1451 src_bitmap_width = graphic_info[i].src_image_width;
1452 src_bitmap_height = graphic_info[i].src_image_height;
1454 /* check if first animation frame is inside specified bitmap */
1457 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1460 /* this avoids calculating wrong start position for out-of-bounds frame */
1461 src_x = graphic_info[i].src_x;
1462 src_y = graphic_info[i].src_y;
1465 if (src_x < 0 || src_y < 0 ||
1466 src_x + width > src_bitmap_width ||
1467 src_y + height > src_bitmap_height)
1469 Error(ERR_INFO_LINE, "-");
1470 Error(ERR_INFO, "warning: error found in config file:");
1471 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1472 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1473 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1475 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1476 src_x, src_y, src_bitmap_width, src_bitmap_height);
1477 Error(ERR_INFO, "custom graphic rejected for this element/action");
1479 if (i == fallback_graphic)
1480 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1482 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1483 Error(ERR_INFO_LINE, "-");
1485 graphic_info[i] = graphic_info[fallback_graphic];
1488 /* check if last animation frame is inside specified bitmap */
1490 last_frame = graphic_info[i].anim_frames - 1;
1491 getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1493 if (src_x < 0 || src_y < 0 ||
1494 src_x + width > src_bitmap_width ||
1495 src_y + height > src_bitmap_height)
1497 Error(ERR_INFO_LINE, "-");
1498 Error(ERR_INFO, "warning: error found in config file:");
1499 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1500 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1501 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1503 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1504 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1505 Error(ERR_INFO, "custom graphic rejected for this element/action");
1507 if (i == fallback_graphic)
1508 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1510 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1511 Error(ERR_INFO_LINE, "-");
1513 graphic_info[i] = graphic_info[fallback_graphic];
1516 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1517 /* currently we only need a tile clip mask from the first frame */
1518 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1520 if (copy_clipmask_gc == None)
1522 clip_gc_values.graphics_exposures = False;
1523 clip_gc_valuemask = GCGraphicsExposures;
1524 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
1525 clip_gc_valuemask, &clip_gc_values);
1528 graphic_info[i].clip_mask =
1529 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
1531 src_pixmap = src_bitmap->clip_mask;
1532 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
1533 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
1535 clip_gc_values.graphics_exposures = False;
1536 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
1537 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
1539 graphic_info[i].clip_gc =
1540 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
1544 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1545 if (copy_clipmask_gc)
1546 XFreeGC(display, copy_clipmask_gc);
1548 clipmasks_initialized = TRUE;
1552 static void InitElementSoundInfo()
1554 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1555 int num_property_mappings = getSoundListPropertyMappingSize();
1558 /* set values to -1 to identify later as "uninitialized" values */
1559 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1560 for (act = 0; act < NUM_ACTIONS; act++)
1561 element_info[i].sound[act] = -1;
1563 /* initialize element/sound mapping from static configuration */
1564 for (i = 0; element_to_sound[i].element > -1; i++)
1566 int element = element_to_sound[i].element;
1567 int action = element_to_sound[i].action;
1568 int sound = element_to_sound[i].sound;
1569 boolean is_class = element_to_sound[i].is_class;
1572 action = ACTION_DEFAULT;
1575 element_info[element].sound[action] = sound;
1577 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1578 if (strEqual(element_info[j].class_name,
1579 element_info[element].class_name))
1580 element_info[j].sound[action] = sound;
1583 /* initialize element class/sound mapping from dynamic configuration */
1584 for (i = 0; i < num_property_mappings; i++)
1586 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1587 int action = property_mapping[i].ext1_index;
1588 int sound = property_mapping[i].artwork_index;
1590 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1594 action = ACTION_DEFAULT;
1596 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1597 if (strEqual(element_info[j].class_name,
1598 element_info[element_class].class_name))
1599 element_info[j].sound[action] = sound;
1602 /* initialize element/sound mapping from dynamic configuration */
1603 for (i = 0; i < num_property_mappings; i++)
1605 int element = property_mapping[i].base_index;
1606 int action = property_mapping[i].ext1_index;
1607 int sound = property_mapping[i].artwork_index;
1609 if (element >= MAX_NUM_ELEMENTS)
1613 action = ACTION_DEFAULT;
1615 element_info[element].sound[action] = sound;
1618 /* now set all '-1' values to element specific default values */
1619 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1621 for (act = 0; act < NUM_ACTIONS; act++)
1623 /* generic default action sound (defined by "[default]" directive) */
1624 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1626 /* look for special default action sound (classic game specific) */
1627 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1628 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1629 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1630 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1631 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1632 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1634 /* !!! there's no such thing as a "default action sound" !!! */
1636 /* look for element specific default sound (independent from action) */
1637 if (element_info[i].sound[ACTION_DEFAULT] != -1)
1638 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
1642 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1643 /* !!! make this better !!! */
1644 if (i == EL_EMPTY_SPACE)
1645 default_action_sound = element_info[EL_DEFAULT].sound[act];
1648 /* no sound for this specific action -- use default action sound */
1649 if (element_info[i].sound[act] == -1)
1650 element_info[i].sound[act] = default_action_sound;
1654 /* copy sound settings to some elements that are only stored in level file
1655 in native R'n'D levels, but are used by game engine in native EM levels */
1656 for (i = 0; copy_properties[i][0] != -1; i++)
1657 for (j = 1; j <= 4; j++)
1658 for (act = 0; act < NUM_ACTIONS; act++)
1659 element_info[copy_properties[i][j]].sound[act] =
1660 element_info[copy_properties[i][0]].sound[act];
1663 static void InitGameModeSoundInfo()
1667 /* set values to -1 to identify later as "uninitialized" values */
1668 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1671 /* initialize gamemode/sound mapping from static configuration */
1672 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1674 int gamemode = gamemode_to_sound[i].gamemode;
1675 int sound = gamemode_to_sound[i].sound;
1678 gamemode = GAME_MODE_DEFAULT;
1680 menu.sound[gamemode] = sound;
1683 /* now set all '-1' values to levelset specific default values */
1684 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1685 if (menu.sound[i] == -1)
1686 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1689 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1690 if (menu.sound[i] != -1)
1691 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
1695 static void set_sound_parameters(int sound, char **parameter_raw)
1697 int parameter[NUM_SND_ARGS];
1700 /* get integer values from string parameters */
1701 for (i = 0; i < NUM_SND_ARGS; i++)
1703 get_parameter_value(parameter_raw[i],
1704 sound_config_suffix[i].token,
1705 sound_config_suffix[i].type);
1707 /* explicit loop mode setting in configuration overrides default value */
1708 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1709 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1711 /* sound volume to change the original volume when loading the sound file */
1712 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1714 /* sound priority to give certain sounds a higher or lower priority */
1715 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1718 static void InitSoundInfo()
1720 int *sound_effect_properties;
1721 int num_sounds = getSoundListSize();
1724 checked_free(sound_info);
1726 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1727 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1729 /* initialize sound effect for all elements to "no sound" */
1730 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1731 for (j = 0; j < NUM_ACTIONS; j++)
1732 element_info[i].sound[j] = SND_UNDEFINED;
1734 for (i = 0; i < num_sounds; i++)
1736 struct FileInfo *sound = getSoundListEntry(i);
1737 int len_effect_text = strlen(sound->token);
1739 sound_effect_properties[i] = ACTION_OTHER;
1740 sound_info[i].loop = FALSE; /* default: play sound only once */
1743 printf("::: sound %d: '%s'\n", i, sound->token);
1746 /* determine all loop sounds and identify certain sound classes */
1748 for (j = 0; element_action_info[j].suffix; j++)
1750 int len_action_text = strlen(element_action_info[j].suffix);
1752 if (len_action_text < len_effect_text &&
1753 strEqual(&sound->token[len_effect_text - len_action_text],
1754 element_action_info[j].suffix))
1756 sound_effect_properties[i] = element_action_info[j].value;
1757 sound_info[i].loop = element_action_info[j].is_loop_sound;
1763 /* associate elements and some selected sound actions */
1765 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1767 if (element_info[j].class_name)
1769 int len_class_text = strlen(element_info[j].class_name);
1771 if (len_class_text + 1 < len_effect_text &&
1772 strncmp(sound->token,
1773 element_info[j].class_name, len_class_text) == 0 &&
1774 sound->token[len_class_text] == '.')
1776 int sound_action_value = sound_effect_properties[i];
1778 element_info[j].sound[sound_action_value] = i;
1783 set_sound_parameters(i, sound->parameter);
1786 free(sound_effect_properties);
1789 static void InitGameModeMusicInfo()
1791 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1792 int num_property_mappings = getMusicListPropertyMappingSize();
1793 int default_levelset_music = -1;
1796 /* set values to -1 to identify later as "uninitialized" values */
1797 for (i = 0; i < MAX_LEVELS; i++)
1798 levelset.music[i] = -1;
1799 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1802 /* initialize gamemode/music mapping from static configuration */
1803 for (i = 0; gamemode_to_music[i].music > -1; i++)
1805 int gamemode = gamemode_to_music[i].gamemode;
1806 int music = gamemode_to_music[i].music;
1809 printf("::: gamemode == %d, music == %d\n", gamemode, music);
1813 gamemode = GAME_MODE_DEFAULT;
1815 menu.music[gamemode] = music;
1818 /* initialize gamemode/music mapping from dynamic configuration */
1819 for (i = 0; i < num_property_mappings; i++)
1821 int prefix = property_mapping[i].base_index;
1822 int gamemode = property_mapping[i].ext1_index;
1823 int level = property_mapping[i].ext2_index;
1824 int music = property_mapping[i].artwork_index;
1827 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
1828 prefix, gamemode, level, music);
1831 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1835 gamemode = GAME_MODE_DEFAULT;
1837 /* level specific music only allowed for in-game music */
1838 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1839 gamemode = GAME_MODE_PLAYING;
1844 default_levelset_music = music;
1847 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1848 levelset.music[level] = music;
1849 if (gamemode != GAME_MODE_PLAYING)
1850 menu.music[gamemode] = music;
1853 /* now set all '-1' values to menu specific default values */
1854 /* (undefined values of "levelset.music[]" might stay at "-1" to
1855 allow dynamic selection of music files from music directory!) */
1856 for (i = 0; i < MAX_LEVELS; i++)
1857 if (levelset.music[i] == -1)
1858 levelset.music[i] = default_levelset_music;
1859 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1860 if (menu.music[i] == -1)
1861 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1864 for (i = 0; i < MAX_LEVELS; i++)
1865 if (levelset.music[i] != -1)
1866 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
1867 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1868 if (menu.music[i] != -1)
1869 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
1873 static void set_music_parameters(int music, char **parameter_raw)
1875 int parameter[NUM_MUS_ARGS];
1878 /* get integer values from string parameters */
1879 for (i = 0; i < NUM_MUS_ARGS; i++)
1881 get_parameter_value(parameter_raw[i],
1882 music_config_suffix[i].token,
1883 music_config_suffix[i].type);
1885 /* explicit loop mode setting in configuration overrides default value */
1886 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1887 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1890 static void InitMusicInfo()
1892 int num_music = getMusicListSize();
1895 checked_free(music_info);
1897 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1899 for (i = 0; i < num_music; i++)
1901 struct FileInfo *music = getMusicListEntry(i);
1902 int len_music_text = strlen(music->token);
1904 music_info[i].loop = TRUE; /* default: play music in loop mode */
1906 /* determine all loop music */
1908 for (j = 0; music_prefix_info[j].prefix; j++)
1910 int len_prefix_text = strlen(music_prefix_info[j].prefix);
1912 if (len_prefix_text < len_music_text &&
1913 strncmp(music->token,
1914 music_prefix_info[j].prefix, len_prefix_text) == 0)
1916 music_info[i].loop = music_prefix_info[j].is_loop_music;
1922 set_music_parameters(i, music->parameter);
1926 static void ReinitializeGraphics()
1928 InitGraphicInfo(); /* graphic properties mapping */
1929 InitElementGraphicInfo(); /* element game graphic mapping */
1930 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
1932 InitElementSmallImages(); /* scale elements to all needed sizes */
1933 InitScaledImages(); /* scale all other images, if needed */
1934 InitFontGraphicInfo(); /* initialize text drawing functions */
1936 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
1938 SetMainBackgroundImage(IMG_BACKGROUND);
1939 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1945 static void ReinitializeSounds()
1947 InitSoundInfo(); /* sound properties mapping */
1948 InitElementSoundInfo(); /* element game sound mapping */
1949 InitGameModeSoundInfo(); /* game mode sound mapping */
1951 InitPlayLevelSound(); /* internal game sound settings */
1954 static void ReinitializeMusic()
1956 InitMusicInfo(); /* music properties mapping */
1957 InitGameModeMusicInfo(); /* game mode music mapping */
1960 static int get_special_property_bit(int element, int property_bit_nr)
1962 struct PropertyBitInfo
1968 static struct PropertyBitInfo pb_can_move_into_acid[] =
1970 /* the player may be able fall into acid when gravity is activated */
1975 { EL_SP_MURPHY, 0 },
1976 { EL_SOKOBAN_FIELD_PLAYER, 0 },
1978 /* all elements that can move may be able to also move into acid */
1981 { EL_BUG_RIGHT, 1 },
1984 { EL_SPACESHIP, 2 },
1985 { EL_SPACESHIP_LEFT, 2 },
1986 { EL_SPACESHIP_RIGHT, 2 },
1987 { EL_SPACESHIP_UP, 2 },
1988 { EL_SPACESHIP_DOWN, 2 },
1989 { EL_BD_BUTTERFLY, 3 },
1990 { EL_BD_BUTTERFLY_LEFT, 3 },
1991 { EL_BD_BUTTERFLY_RIGHT, 3 },
1992 { EL_BD_BUTTERFLY_UP, 3 },
1993 { EL_BD_BUTTERFLY_DOWN, 3 },
1994 { EL_BD_FIREFLY, 4 },
1995 { EL_BD_FIREFLY_LEFT, 4 },
1996 { EL_BD_FIREFLY_RIGHT, 4 },
1997 { EL_BD_FIREFLY_UP, 4 },
1998 { EL_BD_FIREFLY_DOWN, 4 },
2000 { EL_YAMYAM_LEFT, 5 },
2001 { EL_YAMYAM_RIGHT, 5 },
2002 { EL_YAMYAM_UP, 5 },
2003 { EL_YAMYAM_DOWN, 5 },
2004 { EL_DARK_YAMYAM, 6 },
2007 { EL_PACMAN_LEFT, 8 },
2008 { EL_PACMAN_RIGHT, 8 },
2009 { EL_PACMAN_UP, 8 },
2010 { EL_PACMAN_DOWN, 8 },
2012 { EL_MOLE_LEFT, 9 },
2013 { EL_MOLE_RIGHT, 9 },
2015 { EL_MOLE_DOWN, 9 },
2019 { EL_SATELLITE, 13 },
2020 { EL_SP_SNIKSNAK, 14 },
2021 { EL_SP_ELECTRON, 15 },
2024 { EL_EMC_ANDROID, 18 },
2029 static struct PropertyBitInfo pb_dont_collide_with[] =
2031 { EL_SP_SNIKSNAK, 0 },
2032 { EL_SP_ELECTRON, 1 },
2040 struct PropertyBitInfo *pb_info;
2043 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2044 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2049 struct PropertyBitInfo *pb_info = NULL;
2052 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2053 if (pb_definition[i].bit_nr == property_bit_nr)
2054 pb_info = pb_definition[i].pb_info;
2056 if (pb_info == NULL)
2059 for (i = 0; pb_info[i].element != -1; i++)
2060 if (pb_info[i].element == element)
2061 return pb_info[i].bit_nr;
2066 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2067 boolean property_value)
2069 int bit_nr = get_special_property_bit(element, property_bit_nr);
2074 *bitfield |= (1 << bit_nr);
2076 *bitfield &= ~(1 << bit_nr);
2080 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2082 int bit_nr = get_special_property_bit(element, property_bit_nr);
2085 return ((*bitfield & (1 << bit_nr)) != 0);
2090 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2092 static int group_nr;
2093 static struct ElementGroupInfo *group;
2094 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2097 if (actual_group == NULL) /* not yet initialized */
2100 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
2102 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2103 group_element - EL_GROUP_START + 1);
2105 /* replace element which caused too deep recursion by question mark */
2106 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2111 if (recursion_depth == 0) /* initialization */
2113 group = actual_group;
2114 group_nr = GROUP_NR(group_element);
2116 group->num_elements_resolved = 0;
2117 group->choice_pos = 0;
2119 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2120 element_info[i].in_group[group_nr] = FALSE;
2123 for (i = 0; i < actual_group->num_elements; i++)
2125 int element = actual_group->element[i];
2127 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2130 if (IS_GROUP_ELEMENT(element))
2131 ResolveGroupElementExt(element, recursion_depth + 1);
2134 group->element_resolved[group->num_elements_resolved++] = element;
2135 element_info[element].in_group[group_nr] = TRUE;
2140 void ResolveGroupElement(int group_element)
2142 ResolveGroupElementExt(group_element, 0);
2145 void InitElementPropertiesStatic()
2147 static int ep_diggable[] =
2152 EL_SP_BUGGY_BASE_ACTIVATING,
2155 EL_INVISIBLE_SAND_ACTIVE,
2158 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2159 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2164 EL_SP_BUGGY_BASE_ACTIVE,
2171 static int ep_collectible_only[] =
2193 EL_DYNABOMB_INCREASE_NUMBER,
2194 EL_DYNABOMB_INCREASE_SIZE,
2195 EL_DYNABOMB_INCREASE_POWER,
2213 /* !!! handle separately !!! */
2214 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2220 static int ep_dont_run_into[] =
2222 /* same elements as in 'ep_dont_touch' */
2228 /* same elements as in 'ep_dont_collide_with' */
2240 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2245 EL_SP_BUGGY_BASE_ACTIVE,
2252 static int ep_dont_collide_with[] =
2254 /* same elements as in 'ep_dont_touch' */
2271 static int ep_dont_touch[] =
2281 static int ep_indestructible[] =
2285 EL_ACID_POOL_TOPLEFT,
2286 EL_ACID_POOL_TOPRIGHT,
2287 EL_ACID_POOL_BOTTOMLEFT,
2288 EL_ACID_POOL_BOTTOM,
2289 EL_ACID_POOL_BOTTOMRIGHT,
2290 EL_SP_HARDWARE_GRAY,
2291 EL_SP_HARDWARE_GREEN,
2292 EL_SP_HARDWARE_BLUE,
2294 EL_SP_HARDWARE_YELLOW,
2295 EL_SP_HARDWARE_BASE_1,
2296 EL_SP_HARDWARE_BASE_2,
2297 EL_SP_HARDWARE_BASE_3,
2298 EL_SP_HARDWARE_BASE_4,
2299 EL_SP_HARDWARE_BASE_5,
2300 EL_SP_HARDWARE_BASE_6,
2301 EL_INVISIBLE_STEELWALL,
2302 EL_INVISIBLE_STEELWALL_ACTIVE,
2303 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2304 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2305 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2306 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2307 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2308 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2309 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2310 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2311 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2312 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2313 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2314 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2316 EL_LIGHT_SWITCH_ACTIVE,
2317 EL_SIGN_EXCLAMATION,
2318 EL_SIGN_RADIOACTIVITY,
2325 EL_SIGN_ENTRY_FORBIDDEN,
2326 EL_SIGN_EMERGENCY_EXIT,
2334 EL_STEEL_EXIT_CLOSED,
2336 EL_EM_STEEL_EXIT_CLOSED,
2337 EL_EM_STEEL_EXIT_OPEN,
2338 EL_DC_STEELWALL_1_LEFT,
2339 EL_DC_STEELWALL_1_RIGHT,
2340 EL_DC_STEELWALL_1_TOP,
2341 EL_DC_STEELWALL_1_BOTTOM,
2342 EL_DC_STEELWALL_1_HORIZONTAL,
2343 EL_DC_STEELWALL_1_VERTICAL,
2344 EL_DC_STEELWALL_1_TOPLEFT,
2345 EL_DC_STEELWALL_1_TOPRIGHT,
2346 EL_DC_STEELWALL_1_BOTTOMLEFT,
2347 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2348 EL_DC_STEELWALL_1_TOPLEFT_2,
2349 EL_DC_STEELWALL_1_TOPRIGHT_2,
2350 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2351 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2352 EL_DC_STEELWALL_2_LEFT,
2353 EL_DC_STEELWALL_2_RIGHT,
2354 EL_DC_STEELWALL_2_TOP,
2355 EL_DC_STEELWALL_2_BOTTOM,
2356 EL_DC_STEELWALL_2_HORIZONTAL,
2357 EL_DC_STEELWALL_2_VERTICAL,
2358 EL_DC_STEELWALL_2_MIDDLE,
2359 EL_DC_STEELWALL_2_SINGLE,
2360 EL_STEELWALL_SLIPPERY,
2374 EL_GATE_1_GRAY_ACTIVE,
2375 EL_GATE_2_GRAY_ACTIVE,
2376 EL_GATE_3_GRAY_ACTIVE,
2377 EL_GATE_4_GRAY_ACTIVE,
2386 EL_EM_GATE_1_GRAY_ACTIVE,
2387 EL_EM_GATE_2_GRAY_ACTIVE,
2388 EL_EM_GATE_3_GRAY_ACTIVE,
2389 EL_EM_GATE_4_GRAY_ACTIVE,
2398 EL_EMC_GATE_5_GRAY_ACTIVE,
2399 EL_EMC_GATE_6_GRAY_ACTIVE,
2400 EL_EMC_GATE_7_GRAY_ACTIVE,
2401 EL_EMC_GATE_8_GRAY_ACTIVE,
2403 EL_DC_GATE_WHITE_GRAY,
2404 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2405 EL_DC_GATE_FAKE_GRAY,
2407 EL_SWITCHGATE_OPENING,
2408 EL_SWITCHGATE_CLOSED,
2409 EL_SWITCHGATE_CLOSING,
2411 EL_DC_SWITCHGATE_SWITCH_UP,
2412 EL_DC_SWITCHGATE_SWITCH_DOWN,
2415 EL_TIMEGATE_OPENING,
2417 EL_TIMEGATE_CLOSING,
2419 EL_DC_TIMEGATE_SWITCH,
2420 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2425 EL_TUBE_VERTICAL_LEFT,
2426 EL_TUBE_VERTICAL_RIGHT,
2427 EL_TUBE_HORIZONTAL_UP,
2428 EL_TUBE_HORIZONTAL_DOWN,
2433 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2434 EL_EXPANDABLE_STEELWALL_VERTICAL,
2435 EL_EXPANDABLE_STEELWALL_ANY,
2440 static int ep_slippery[] =
2454 EL_ROBOT_WHEEL_ACTIVE,
2460 EL_ACID_POOL_TOPLEFT,
2461 EL_ACID_POOL_TOPRIGHT,
2471 EL_STEELWALL_SLIPPERY,
2474 EL_EMC_WALL_SLIPPERY_1,
2475 EL_EMC_WALL_SLIPPERY_2,
2476 EL_EMC_WALL_SLIPPERY_3,
2477 EL_EMC_WALL_SLIPPERY_4,
2479 EL_EMC_MAGIC_BALL_ACTIVE,
2484 static int ep_can_change[] =
2489 static int ep_can_move[] =
2491 /* same elements as in 'pb_can_move_into_acid' */
2514 static int ep_can_fall[] =
2528 EL_QUICKSAND_FAST_FULL,
2530 EL_BD_MAGIC_WALL_FULL,
2531 EL_DC_MAGIC_WALL_FULL,
2545 static int ep_can_smash_player[] =
2571 static int ep_can_smash_enemies[] =
2580 static int ep_can_smash_everything[] =
2589 static int ep_explodes_by_fire[] =
2591 /* same elements as in 'ep_explodes_impact' */
2596 /* same elements as in 'ep_explodes_smashed' */
2606 EL_EM_DYNAMITE_ACTIVE,
2607 EL_DYNABOMB_PLAYER_1_ACTIVE,
2608 EL_DYNABOMB_PLAYER_2_ACTIVE,
2609 EL_DYNABOMB_PLAYER_3_ACTIVE,
2610 EL_DYNABOMB_PLAYER_4_ACTIVE,
2611 EL_DYNABOMB_INCREASE_NUMBER,
2612 EL_DYNABOMB_INCREASE_SIZE,
2613 EL_DYNABOMB_INCREASE_POWER,
2614 EL_SP_DISK_RED_ACTIVE,
2628 static int ep_explodes_smashed[] =
2630 /* same elements as in 'ep_explodes_impact' */
2644 static int ep_explodes_impact[] =
2653 static int ep_walkable_over[] =
2657 EL_SOKOBAN_FIELD_EMPTY,
2663 EL_EM_STEEL_EXIT_OPEN,
2672 EL_GATE_1_GRAY_ACTIVE,
2673 EL_GATE_2_GRAY_ACTIVE,
2674 EL_GATE_3_GRAY_ACTIVE,
2675 EL_GATE_4_GRAY_ACTIVE,
2683 static int ep_walkable_inside[] =
2688 EL_TUBE_VERTICAL_LEFT,
2689 EL_TUBE_VERTICAL_RIGHT,
2690 EL_TUBE_HORIZONTAL_UP,
2691 EL_TUBE_HORIZONTAL_DOWN,
2700 static int ep_walkable_under[] =
2705 static int ep_passable_over[] =
2715 EL_EM_GATE_1_GRAY_ACTIVE,
2716 EL_EM_GATE_2_GRAY_ACTIVE,
2717 EL_EM_GATE_3_GRAY_ACTIVE,
2718 EL_EM_GATE_4_GRAY_ACTIVE,
2727 EL_EMC_GATE_5_GRAY_ACTIVE,
2728 EL_EMC_GATE_6_GRAY_ACTIVE,
2729 EL_EMC_GATE_7_GRAY_ACTIVE,
2730 EL_EMC_GATE_8_GRAY_ACTIVE,
2732 EL_DC_GATE_WHITE_GRAY,
2733 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2740 static int ep_passable_inside[] =
2746 EL_SP_PORT_HORIZONTAL,
2747 EL_SP_PORT_VERTICAL,
2749 EL_SP_GRAVITY_PORT_LEFT,
2750 EL_SP_GRAVITY_PORT_RIGHT,
2751 EL_SP_GRAVITY_PORT_UP,
2752 EL_SP_GRAVITY_PORT_DOWN,
2753 EL_SP_GRAVITY_ON_PORT_LEFT,
2754 EL_SP_GRAVITY_ON_PORT_RIGHT,
2755 EL_SP_GRAVITY_ON_PORT_UP,
2756 EL_SP_GRAVITY_ON_PORT_DOWN,
2757 EL_SP_GRAVITY_OFF_PORT_LEFT,
2758 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2759 EL_SP_GRAVITY_OFF_PORT_UP,
2760 EL_SP_GRAVITY_OFF_PORT_DOWN,
2765 static int ep_passable_under[] =
2770 static int ep_droppable[] =
2775 static int ep_explodes_1x1_old[] =
2780 static int ep_pushable[] =
2792 EL_SOKOBAN_FIELD_FULL,
2801 static int ep_explodes_cross_old[] =
2806 static int ep_protected[] =
2808 /* same elements as in 'ep_walkable_inside' */
2812 EL_TUBE_VERTICAL_LEFT,
2813 EL_TUBE_VERTICAL_RIGHT,
2814 EL_TUBE_HORIZONTAL_UP,
2815 EL_TUBE_HORIZONTAL_DOWN,
2821 /* same elements as in 'ep_passable_over' */
2830 EL_EM_GATE_1_GRAY_ACTIVE,
2831 EL_EM_GATE_2_GRAY_ACTIVE,
2832 EL_EM_GATE_3_GRAY_ACTIVE,
2833 EL_EM_GATE_4_GRAY_ACTIVE,
2842 EL_EMC_GATE_5_GRAY_ACTIVE,
2843 EL_EMC_GATE_6_GRAY_ACTIVE,
2844 EL_EMC_GATE_7_GRAY_ACTIVE,
2845 EL_EMC_GATE_8_GRAY_ACTIVE,
2847 EL_DC_GATE_WHITE_GRAY,
2848 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2852 /* same elements as in 'ep_passable_inside' */
2857 EL_SP_PORT_HORIZONTAL,
2858 EL_SP_PORT_VERTICAL,
2860 EL_SP_GRAVITY_PORT_LEFT,
2861 EL_SP_GRAVITY_PORT_RIGHT,
2862 EL_SP_GRAVITY_PORT_UP,
2863 EL_SP_GRAVITY_PORT_DOWN,
2864 EL_SP_GRAVITY_ON_PORT_LEFT,
2865 EL_SP_GRAVITY_ON_PORT_RIGHT,
2866 EL_SP_GRAVITY_ON_PORT_UP,
2867 EL_SP_GRAVITY_ON_PORT_DOWN,
2868 EL_SP_GRAVITY_OFF_PORT_LEFT,
2869 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2870 EL_SP_GRAVITY_OFF_PORT_UP,
2871 EL_SP_GRAVITY_OFF_PORT_DOWN,
2876 static int ep_throwable[] =
2881 static int ep_can_explode[] =
2883 /* same elements as in 'ep_explodes_impact' */
2888 /* same elements as in 'ep_explodes_smashed' */
2894 /* elements that can explode by explosion or by dragonfire */
2898 EL_EM_DYNAMITE_ACTIVE,
2899 EL_DYNABOMB_PLAYER_1_ACTIVE,
2900 EL_DYNABOMB_PLAYER_2_ACTIVE,
2901 EL_DYNABOMB_PLAYER_3_ACTIVE,
2902 EL_DYNABOMB_PLAYER_4_ACTIVE,
2903 EL_DYNABOMB_INCREASE_NUMBER,
2904 EL_DYNABOMB_INCREASE_SIZE,
2905 EL_DYNABOMB_INCREASE_POWER,
2906 EL_SP_DISK_RED_ACTIVE,
2914 /* elements that can explode only by explosion */
2920 static int ep_gravity_reachable[] =
2926 EL_INVISIBLE_SAND_ACTIVE,
2931 EL_SP_PORT_HORIZONTAL,
2932 EL_SP_PORT_VERTICAL,
2934 EL_SP_GRAVITY_PORT_LEFT,
2935 EL_SP_GRAVITY_PORT_RIGHT,
2936 EL_SP_GRAVITY_PORT_UP,
2937 EL_SP_GRAVITY_PORT_DOWN,
2938 EL_SP_GRAVITY_ON_PORT_LEFT,
2939 EL_SP_GRAVITY_ON_PORT_RIGHT,
2940 EL_SP_GRAVITY_ON_PORT_UP,
2941 EL_SP_GRAVITY_ON_PORT_DOWN,
2942 EL_SP_GRAVITY_OFF_PORT_LEFT,
2943 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2944 EL_SP_GRAVITY_OFF_PORT_UP,
2945 EL_SP_GRAVITY_OFF_PORT_DOWN,
2951 static int ep_player[] =
2958 EL_SOKOBAN_FIELD_PLAYER,
2964 static int ep_can_pass_magic_wall[] =
2978 static int ep_can_pass_dc_magic_wall[] =
2994 static int ep_switchable[] =
2998 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2999 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3000 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3001 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3002 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3003 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3004 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3005 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3006 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3007 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3008 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3009 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3010 EL_SWITCHGATE_SWITCH_UP,
3011 EL_SWITCHGATE_SWITCH_DOWN,
3012 EL_DC_SWITCHGATE_SWITCH_UP,
3013 EL_DC_SWITCHGATE_SWITCH_DOWN,
3015 EL_LIGHT_SWITCH_ACTIVE,
3017 EL_DC_TIMEGATE_SWITCH,
3018 EL_BALLOON_SWITCH_LEFT,
3019 EL_BALLOON_SWITCH_RIGHT,
3020 EL_BALLOON_SWITCH_UP,
3021 EL_BALLOON_SWITCH_DOWN,
3022 EL_BALLOON_SWITCH_ANY,
3023 EL_BALLOON_SWITCH_NONE,
3026 EL_EMC_MAGIC_BALL_SWITCH,
3027 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3032 static int ep_bd_element[] =
3066 static int ep_sp_element[] =
3068 /* should always be valid */
3071 /* standard classic Supaplex elements */
3078 EL_SP_HARDWARE_GRAY,
3086 EL_SP_GRAVITY_PORT_RIGHT,
3087 EL_SP_GRAVITY_PORT_DOWN,
3088 EL_SP_GRAVITY_PORT_LEFT,
3089 EL_SP_GRAVITY_PORT_UP,
3094 EL_SP_PORT_VERTICAL,
3095 EL_SP_PORT_HORIZONTAL,
3101 EL_SP_HARDWARE_BASE_1,
3102 EL_SP_HARDWARE_GREEN,
3103 EL_SP_HARDWARE_BLUE,
3105 EL_SP_HARDWARE_YELLOW,
3106 EL_SP_HARDWARE_BASE_2,
3107 EL_SP_HARDWARE_BASE_3,
3108 EL_SP_HARDWARE_BASE_4,
3109 EL_SP_HARDWARE_BASE_5,
3110 EL_SP_HARDWARE_BASE_6,
3114 /* additional elements that appeared in newer Supaplex levels */
3117 /* additional gravity port elements (not switching, but setting gravity) */
3118 EL_SP_GRAVITY_ON_PORT_LEFT,
3119 EL_SP_GRAVITY_ON_PORT_RIGHT,
3120 EL_SP_GRAVITY_ON_PORT_UP,
3121 EL_SP_GRAVITY_ON_PORT_DOWN,
3122 EL_SP_GRAVITY_OFF_PORT_LEFT,
3123 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3124 EL_SP_GRAVITY_OFF_PORT_UP,
3125 EL_SP_GRAVITY_OFF_PORT_DOWN,
3127 /* more than one Murphy in a level results in an inactive clone */
3130 /* runtime Supaplex elements */
3131 EL_SP_DISK_RED_ACTIVE,
3132 EL_SP_TERMINAL_ACTIVE,
3133 EL_SP_BUGGY_BASE_ACTIVATING,
3134 EL_SP_BUGGY_BASE_ACTIVE,
3141 static int ep_sb_element[] =
3146 EL_SOKOBAN_FIELD_EMPTY,
3147 EL_SOKOBAN_FIELD_FULL,
3148 EL_SOKOBAN_FIELD_PLAYER,
3153 EL_INVISIBLE_STEELWALL,
3158 static int ep_gem[] =
3170 static int ep_food_dark_yamyam[] =
3198 static int ep_food_penguin[] =
3212 static int ep_food_pig[] =
3224 static int ep_historic_wall[] =
3235 EL_GATE_1_GRAY_ACTIVE,
3236 EL_GATE_2_GRAY_ACTIVE,
3237 EL_GATE_3_GRAY_ACTIVE,
3238 EL_GATE_4_GRAY_ACTIVE,
3247 EL_EM_GATE_1_GRAY_ACTIVE,
3248 EL_EM_GATE_2_GRAY_ACTIVE,
3249 EL_EM_GATE_3_GRAY_ACTIVE,
3250 EL_EM_GATE_4_GRAY_ACTIVE,
3257 EL_EXPANDABLE_WALL_HORIZONTAL,
3258 EL_EXPANDABLE_WALL_VERTICAL,
3259 EL_EXPANDABLE_WALL_ANY,
3260 EL_EXPANDABLE_WALL_GROWING,
3261 EL_BD_EXPANDABLE_WALL,
3268 EL_SP_HARDWARE_GRAY,
3269 EL_SP_HARDWARE_GREEN,
3270 EL_SP_HARDWARE_BLUE,
3272 EL_SP_HARDWARE_YELLOW,
3273 EL_SP_HARDWARE_BASE_1,
3274 EL_SP_HARDWARE_BASE_2,
3275 EL_SP_HARDWARE_BASE_3,
3276 EL_SP_HARDWARE_BASE_4,
3277 EL_SP_HARDWARE_BASE_5,
3278 EL_SP_HARDWARE_BASE_6,
3280 EL_SP_TERMINAL_ACTIVE,
3283 EL_INVISIBLE_STEELWALL,
3284 EL_INVISIBLE_STEELWALL_ACTIVE,
3286 EL_INVISIBLE_WALL_ACTIVE,
3287 EL_STEELWALL_SLIPPERY,
3304 static int ep_historic_solid[] =
3308 EL_EXPANDABLE_WALL_HORIZONTAL,
3309 EL_EXPANDABLE_WALL_VERTICAL,
3310 EL_EXPANDABLE_WALL_ANY,
3311 EL_BD_EXPANDABLE_WALL,
3324 EL_QUICKSAND_FILLING,
3325 EL_QUICKSAND_EMPTYING,
3327 EL_MAGIC_WALL_ACTIVE,
3328 EL_MAGIC_WALL_EMPTYING,
3329 EL_MAGIC_WALL_FILLING,
3333 EL_BD_MAGIC_WALL_ACTIVE,
3334 EL_BD_MAGIC_WALL_EMPTYING,
3335 EL_BD_MAGIC_WALL_FULL,
3336 EL_BD_MAGIC_WALL_FILLING,
3337 EL_BD_MAGIC_WALL_DEAD,
3346 EL_SP_TERMINAL_ACTIVE,
3350 EL_INVISIBLE_WALL_ACTIVE,
3351 EL_SWITCHGATE_SWITCH_UP,
3352 EL_SWITCHGATE_SWITCH_DOWN,
3353 EL_DC_SWITCHGATE_SWITCH_UP,
3354 EL_DC_SWITCHGATE_SWITCH_DOWN,
3356 EL_TIMEGATE_SWITCH_ACTIVE,
3357 EL_DC_TIMEGATE_SWITCH,
3358 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3370 /* the following elements are a direct copy of "indestructible" elements,
3371 except "EL_ACID", which is "indestructible", but not "solid"! */
3376 EL_ACID_POOL_TOPLEFT,
3377 EL_ACID_POOL_TOPRIGHT,
3378 EL_ACID_POOL_BOTTOMLEFT,
3379 EL_ACID_POOL_BOTTOM,
3380 EL_ACID_POOL_BOTTOMRIGHT,
3381 EL_SP_HARDWARE_GRAY,
3382 EL_SP_HARDWARE_GREEN,
3383 EL_SP_HARDWARE_BLUE,
3385 EL_SP_HARDWARE_YELLOW,
3386 EL_SP_HARDWARE_BASE_1,
3387 EL_SP_HARDWARE_BASE_2,
3388 EL_SP_HARDWARE_BASE_3,
3389 EL_SP_HARDWARE_BASE_4,
3390 EL_SP_HARDWARE_BASE_5,
3391 EL_SP_HARDWARE_BASE_6,
3392 EL_INVISIBLE_STEELWALL,
3393 EL_INVISIBLE_STEELWALL_ACTIVE,
3394 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3395 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3396 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3397 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3398 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3399 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3400 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3401 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3402 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3403 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3404 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3405 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3407 EL_LIGHT_SWITCH_ACTIVE,
3408 EL_SIGN_EXCLAMATION,
3409 EL_SIGN_RADIOACTIVITY,
3416 EL_SIGN_ENTRY_FORBIDDEN,
3417 EL_SIGN_EMERGENCY_EXIT,
3425 EL_STEEL_EXIT_CLOSED,
3427 EL_DC_STEELWALL_1_LEFT,
3428 EL_DC_STEELWALL_1_RIGHT,
3429 EL_DC_STEELWALL_1_TOP,
3430 EL_DC_STEELWALL_1_BOTTOM,
3431 EL_DC_STEELWALL_1_HORIZONTAL,
3432 EL_DC_STEELWALL_1_VERTICAL,
3433 EL_DC_STEELWALL_1_TOPLEFT,
3434 EL_DC_STEELWALL_1_TOPRIGHT,
3435 EL_DC_STEELWALL_1_BOTTOMLEFT,
3436 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3437 EL_DC_STEELWALL_1_TOPLEFT_2,
3438 EL_DC_STEELWALL_1_TOPRIGHT_2,
3439 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3440 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3441 EL_DC_STEELWALL_2_LEFT,
3442 EL_DC_STEELWALL_2_RIGHT,
3443 EL_DC_STEELWALL_2_TOP,
3444 EL_DC_STEELWALL_2_BOTTOM,
3445 EL_DC_STEELWALL_2_HORIZONTAL,
3446 EL_DC_STEELWALL_2_VERTICAL,
3447 EL_DC_STEELWALL_2_MIDDLE,
3448 EL_DC_STEELWALL_2_SINGLE,
3449 EL_STEELWALL_SLIPPERY,
3463 EL_GATE_1_GRAY_ACTIVE,
3464 EL_GATE_2_GRAY_ACTIVE,
3465 EL_GATE_3_GRAY_ACTIVE,
3466 EL_GATE_4_GRAY_ACTIVE,
3475 EL_EM_GATE_1_GRAY_ACTIVE,
3476 EL_EM_GATE_2_GRAY_ACTIVE,
3477 EL_EM_GATE_3_GRAY_ACTIVE,
3478 EL_EM_GATE_4_GRAY_ACTIVE,
3480 EL_SWITCHGATE_OPENING,
3481 EL_SWITCHGATE_CLOSED,
3482 EL_SWITCHGATE_CLOSING,
3484 EL_TIMEGATE_OPENING,
3486 EL_TIMEGATE_CLOSING,
3490 EL_TUBE_VERTICAL_LEFT,
3491 EL_TUBE_VERTICAL_RIGHT,
3492 EL_TUBE_HORIZONTAL_UP,
3493 EL_TUBE_HORIZONTAL_DOWN,
3502 static int ep_classic_enemy[] =
3519 static int ep_belt[] =
3521 EL_CONVEYOR_BELT_1_LEFT,
3522 EL_CONVEYOR_BELT_1_MIDDLE,
3523 EL_CONVEYOR_BELT_1_RIGHT,
3524 EL_CONVEYOR_BELT_2_LEFT,
3525 EL_CONVEYOR_BELT_2_MIDDLE,
3526 EL_CONVEYOR_BELT_2_RIGHT,
3527 EL_CONVEYOR_BELT_3_LEFT,
3528 EL_CONVEYOR_BELT_3_MIDDLE,
3529 EL_CONVEYOR_BELT_3_RIGHT,
3530 EL_CONVEYOR_BELT_4_LEFT,
3531 EL_CONVEYOR_BELT_4_MIDDLE,
3532 EL_CONVEYOR_BELT_4_RIGHT,
3537 static int ep_belt_active[] =
3539 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3540 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3541 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3542 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3543 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3544 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3545 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3546 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3547 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3548 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3549 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3550 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3555 static int ep_belt_switch[] =
3557 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3558 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3559 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3560 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3561 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3562 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3563 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3564 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3565 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3566 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3567 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3568 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3573 static int ep_tube[] =
3580 EL_TUBE_HORIZONTAL_UP,
3581 EL_TUBE_HORIZONTAL_DOWN,
3583 EL_TUBE_VERTICAL_LEFT,
3584 EL_TUBE_VERTICAL_RIGHT,
3590 static int ep_acid_pool[] =
3592 EL_ACID_POOL_TOPLEFT,
3593 EL_ACID_POOL_TOPRIGHT,
3594 EL_ACID_POOL_BOTTOMLEFT,
3595 EL_ACID_POOL_BOTTOM,
3596 EL_ACID_POOL_BOTTOMRIGHT,
3601 static int ep_keygate[] =
3611 EL_GATE_1_GRAY_ACTIVE,
3612 EL_GATE_2_GRAY_ACTIVE,
3613 EL_GATE_3_GRAY_ACTIVE,
3614 EL_GATE_4_GRAY_ACTIVE,
3623 EL_EM_GATE_1_GRAY_ACTIVE,
3624 EL_EM_GATE_2_GRAY_ACTIVE,
3625 EL_EM_GATE_3_GRAY_ACTIVE,
3626 EL_EM_GATE_4_GRAY_ACTIVE,
3635 EL_EMC_GATE_5_GRAY_ACTIVE,
3636 EL_EMC_GATE_6_GRAY_ACTIVE,
3637 EL_EMC_GATE_7_GRAY_ACTIVE,
3638 EL_EMC_GATE_8_GRAY_ACTIVE,
3640 EL_DC_GATE_WHITE_GRAY,
3641 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3646 static int ep_amoeboid[] =
3658 static int ep_amoebalive[] =
3669 static int ep_has_editor_content[] =
3691 static int ep_can_turn_each_move[] =
3693 /* !!! do something with this one !!! */
3697 static int ep_can_grow[] =
3711 static int ep_active_bomb[] =
3714 EL_EM_DYNAMITE_ACTIVE,
3715 EL_DYNABOMB_PLAYER_1_ACTIVE,
3716 EL_DYNABOMB_PLAYER_2_ACTIVE,
3717 EL_DYNABOMB_PLAYER_3_ACTIVE,
3718 EL_DYNABOMB_PLAYER_4_ACTIVE,
3719 EL_SP_DISK_RED_ACTIVE,
3724 static int ep_inactive[] =
3734 EL_QUICKSAND_FAST_EMPTY,
3757 EL_GATE_1_GRAY_ACTIVE,
3758 EL_GATE_2_GRAY_ACTIVE,
3759 EL_GATE_3_GRAY_ACTIVE,
3760 EL_GATE_4_GRAY_ACTIVE,
3769 EL_EM_GATE_1_GRAY_ACTIVE,
3770 EL_EM_GATE_2_GRAY_ACTIVE,
3771 EL_EM_GATE_3_GRAY_ACTIVE,
3772 EL_EM_GATE_4_GRAY_ACTIVE,
3781 EL_EMC_GATE_5_GRAY_ACTIVE,
3782 EL_EMC_GATE_6_GRAY_ACTIVE,
3783 EL_EMC_GATE_7_GRAY_ACTIVE,
3784 EL_EMC_GATE_8_GRAY_ACTIVE,
3786 EL_DC_GATE_WHITE_GRAY,
3787 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3788 EL_DC_GATE_FAKE_GRAY,
3791 EL_INVISIBLE_STEELWALL,
3799 EL_WALL_EMERALD_YELLOW,
3800 EL_DYNABOMB_INCREASE_NUMBER,
3801 EL_DYNABOMB_INCREASE_SIZE,
3802 EL_DYNABOMB_INCREASE_POWER,
3806 EL_SOKOBAN_FIELD_EMPTY,
3807 EL_SOKOBAN_FIELD_FULL,
3808 EL_WALL_EMERALD_RED,
3809 EL_WALL_EMERALD_PURPLE,
3810 EL_ACID_POOL_TOPLEFT,
3811 EL_ACID_POOL_TOPRIGHT,
3812 EL_ACID_POOL_BOTTOMLEFT,
3813 EL_ACID_POOL_BOTTOM,
3814 EL_ACID_POOL_BOTTOMRIGHT,
3818 EL_BD_MAGIC_WALL_DEAD,
3820 EL_DC_MAGIC_WALL_DEAD,
3821 EL_AMOEBA_TO_DIAMOND,
3829 EL_SP_GRAVITY_PORT_RIGHT,
3830 EL_SP_GRAVITY_PORT_DOWN,
3831 EL_SP_GRAVITY_PORT_LEFT,
3832 EL_SP_GRAVITY_PORT_UP,
3833 EL_SP_PORT_HORIZONTAL,
3834 EL_SP_PORT_VERTICAL,
3845 EL_SP_HARDWARE_GRAY,
3846 EL_SP_HARDWARE_GREEN,
3847 EL_SP_HARDWARE_BLUE,
3849 EL_SP_HARDWARE_YELLOW,
3850 EL_SP_HARDWARE_BASE_1,
3851 EL_SP_HARDWARE_BASE_2,
3852 EL_SP_HARDWARE_BASE_3,
3853 EL_SP_HARDWARE_BASE_4,
3854 EL_SP_HARDWARE_BASE_5,
3855 EL_SP_HARDWARE_BASE_6,
3856 EL_SP_GRAVITY_ON_PORT_LEFT,
3857 EL_SP_GRAVITY_ON_PORT_RIGHT,
3858 EL_SP_GRAVITY_ON_PORT_UP,
3859 EL_SP_GRAVITY_ON_PORT_DOWN,
3860 EL_SP_GRAVITY_OFF_PORT_LEFT,
3861 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3862 EL_SP_GRAVITY_OFF_PORT_UP,
3863 EL_SP_GRAVITY_OFF_PORT_DOWN,
3864 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3865 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3866 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3867 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3868 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3869 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3870 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3871 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3872 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3873 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3874 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3875 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3876 EL_SIGN_EXCLAMATION,
3877 EL_SIGN_RADIOACTIVITY,
3884 EL_SIGN_ENTRY_FORBIDDEN,
3885 EL_SIGN_EMERGENCY_EXIT,
3893 EL_DC_STEELWALL_1_LEFT,
3894 EL_DC_STEELWALL_1_RIGHT,
3895 EL_DC_STEELWALL_1_TOP,
3896 EL_DC_STEELWALL_1_BOTTOM,
3897 EL_DC_STEELWALL_1_HORIZONTAL,
3898 EL_DC_STEELWALL_1_VERTICAL,
3899 EL_DC_STEELWALL_1_TOPLEFT,
3900 EL_DC_STEELWALL_1_TOPRIGHT,
3901 EL_DC_STEELWALL_1_BOTTOMLEFT,
3902 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3903 EL_DC_STEELWALL_1_TOPLEFT_2,
3904 EL_DC_STEELWALL_1_TOPRIGHT_2,
3905 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3906 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3907 EL_DC_STEELWALL_2_LEFT,
3908 EL_DC_STEELWALL_2_RIGHT,
3909 EL_DC_STEELWALL_2_TOP,
3910 EL_DC_STEELWALL_2_BOTTOM,
3911 EL_DC_STEELWALL_2_HORIZONTAL,
3912 EL_DC_STEELWALL_2_VERTICAL,
3913 EL_DC_STEELWALL_2_MIDDLE,
3914 EL_DC_STEELWALL_2_SINGLE,
3915 EL_STEELWALL_SLIPPERY,
3920 EL_EMC_WALL_SLIPPERY_1,
3921 EL_EMC_WALL_SLIPPERY_2,
3922 EL_EMC_WALL_SLIPPERY_3,
3923 EL_EMC_WALL_SLIPPERY_4,
3944 static int ep_em_slippery_wall[] =
3949 static int ep_gfx_crumbled[] =
3960 static int ep_editor_cascade_active[] =
3962 EL_INTERNAL_CASCADE_BD_ACTIVE,
3963 EL_INTERNAL_CASCADE_EM_ACTIVE,
3964 EL_INTERNAL_CASCADE_EMC_ACTIVE,
3965 EL_INTERNAL_CASCADE_RND_ACTIVE,
3966 EL_INTERNAL_CASCADE_SB_ACTIVE,
3967 EL_INTERNAL_CASCADE_SP_ACTIVE,
3968 EL_INTERNAL_CASCADE_DC_ACTIVE,
3969 EL_INTERNAL_CASCADE_DX_ACTIVE,
3970 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
3971 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
3972 EL_INTERNAL_CASCADE_CE_ACTIVE,
3973 EL_INTERNAL_CASCADE_GE_ACTIVE,
3974 EL_INTERNAL_CASCADE_REF_ACTIVE,
3975 EL_INTERNAL_CASCADE_USER_ACTIVE,
3976 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
3981 static int ep_editor_cascade_inactive[] =
3983 EL_INTERNAL_CASCADE_BD,
3984 EL_INTERNAL_CASCADE_EM,
3985 EL_INTERNAL_CASCADE_EMC,
3986 EL_INTERNAL_CASCADE_RND,
3987 EL_INTERNAL_CASCADE_SB,
3988 EL_INTERNAL_CASCADE_SP,
3989 EL_INTERNAL_CASCADE_DC,
3990 EL_INTERNAL_CASCADE_DX,
3991 EL_INTERNAL_CASCADE_CHARS,
3992 EL_INTERNAL_CASCADE_STEEL_CHARS,
3993 EL_INTERNAL_CASCADE_CE,
3994 EL_INTERNAL_CASCADE_GE,
3995 EL_INTERNAL_CASCADE_REF,
3996 EL_INTERNAL_CASCADE_USER,
3997 EL_INTERNAL_CASCADE_DYNAMIC,
4002 static int ep_obsolete[] =
4006 EL_EM_KEY_1_FILE_OBSOLETE,
4007 EL_EM_KEY_2_FILE_OBSOLETE,
4008 EL_EM_KEY_3_FILE_OBSOLETE,
4009 EL_EM_KEY_4_FILE_OBSOLETE,
4010 EL_ENVELOPE_OBSOLETE,
4019 } element_properties[] =
4021 { ep_diggable, EP_DIGGABLE },
4022 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4023 { ep_dont_run_into, EP_DONT_RUN_INTO },
4024 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4025 { ep_dont_touch, EP_DONT_TOUCH },
4026 { ep_indestructible, EP_INDESTRUCTIBLE },
4027 { ep_slippery, EP_SLIPPERY },
4028 { ep_can_change, EP_CAN_CHANGE },
4029 { ep_can_move, EP_CAN_MOVE },
4030 { ep_can_fall, EP_CAN_FALL },
4031 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4032 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4033 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4034 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4035 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4036 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4037 { ep_walkable_over, EP_WALKABLE_OVER },
4038 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4039 { ep_walkable_under, EP_WALKABLE_UNDER },
4040 { ep_passable_over, EP_PASSABLE_OVER },
4041 { ep_passable_inside, EP_PASSABLE_INSIDE },
4042 { ep_passable_under, EP_PASSABLE_UNDER },
4043 { ep_droppable, EP_DROPPABLE },
4044 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4045 { ep_pushable, EP_PUSHABLE },
4046 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4047 { ep_protected, EP_PROTECTED },
4048 { ep_throwable, EP_THROWABLE },
4049 { ep_can_explode, EP_CAN_EXPLODE },
4050 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4052 { ep_player, EP_PLAYER },
4053 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4054 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4055 { ep_switchable, EP_SWITCHABLE },
4056 { ep_bd_element, EP_BD_ELEMENT },
4057 { ep_sp_element, EP_SP_ELEMENT },
4058 { ep_sb_element, EP_SB_ELEMENT },
4060 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4061 { ep_food_penguin, EP_FOOD_PENGUIN },
4062 { ep_food_pig, EP_FOOD_PIG },
4063 { ep_historic_wall, EP_HISTORIC_WALL },
4064 { ep_historic_solid, EP_HISTORIC_SOLID },
4065 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4066 { ep_belt, EP_BELT },
4067 { ep_belt_active, EP_BELT_ACTIVE },
4068 { ep_belt_switch, EP_BELT_SWITCH },
4069 { ep_tube, EP_TUBE },
4070 { ep_acid_pool, EP_ACID_POOL },
4071 { ep_keygate, EP_KEYGATE },
4072 { ep_amoeboid, EP_AMOEBOID },
4073 { ep_amoebalive, EP_AMOEBALIVE },
4074 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4075 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4076 { ep_can_grow, EP_CAN_GROW },
4077 { ep_active_bomb, EP_ACTIVE_BOMB },
4078 { ep_inactive, EP_INACTIVE },
4080 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4082 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4084 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4085 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4087 { ep_obsolete, EP_OBSOLETE },
4094 /* always start with reliable default values (element has no properties) */
4095 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4096 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4097 SET_PROPERTY(i, j, FALSE);
4099 /* set all base element properties from above array definitions */
4100 for (i = 0; element_properties[i].elements != NULL; i++)
4101 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4102 SET_PROPERTY((element_properties[i].elements)[j],
4103 element_properties[i].property, TRUE);
4105 /* copy properties to some elements that are only stored in level file */
4106 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4107 for (j = 0; copy_properties[j][0] != -1; j++)
4108 if (HAS_PROPERTY(copy_properties[j][0], i))
4109 for (k = 1; k <= 4; k++)
4110 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4112 /* set static element properties that are not listed in array definitions */
4113 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4114 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4117 void InitElementPropertiesEngine(int engine_version)
4119 static int no_wall_properties[] =
4122 EP_COLLECTIBLE_ONLY,
4124 EP_DONT_COLLIDE_WITH,
4127 EP_CAN_SMASH_PLAYER,
4128 EP_CAN_SMASH_ENEMIES,
4129 EP_CAN_SMASH_EVERYTHING,
4134 EP_FOOD_DARK_YAMYAM,
4150 /* important: after initialization in InitElementPropertiesStatic(), the
4151 elements are not again initialized to a default value; therefore all
4152 changes have to make sure that they leave the element with a defined
4153 property (which means that conditional property changes must be set to
4154 a reliable default value before) */
4156 /* resolve group elements */
4157 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4158 ResolveGroupElement(EL_GROUP_START + i);
4160 /* set all special, combined or engine dependent element properties */
4161 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4163 /* ---------- INACTIVE ------------------------------------------------- */
4164 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4165 i <= EL_CHAR_END) ||
4166 (i >= EL_STEEL_CHAR_START &&
4167 i <= EL_STEEL_CHAR_END)));
4169 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4170 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4171 IS_WALKABLE_INSIDE(i) ||
4172 IS_WALKABLE_UNDER(i)));
4174 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4175 IS_PASSABLE_INSIDE(i) ||
4176 IS_PASSABLE_UNDER(i)));
4178 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4179 IS_PASSABLE_OVER(i)));
4181 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4182 IS_PASSABLE_INSIDE(i)));
4184 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4185 IS_PASSABLE_UNDER(i)));
4187 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4190 /* ---------- COLLECTIBLE ---------------------------------------------- */
4191 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4195 /* ---------- SNAPPABLE ------------------------------------------------ */
4196 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4197 IS_COLLECTIBLE(i) ||
4201 /* ---------- WALL ----------------------------------------------------- */
4202 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4204 for (j = 0; no_wall_properties[j] != -1; j++)
4205 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4206 i >= EL_FIRST_RUNTIME_UNREAL)
4207 SET_PROPERTY(i, EP_WALL, FALSE);
4209 if (IS_HISTORIC_WALL(i))
4210 SET_PROPERTY(i, EP_WALL, TRUE);
4212 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4213 if (engine_version < VERSION_IDENT(2,2,0,0))
4214 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4216 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4218 !IS_COLLECTIBLE(i)));
4220 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4221 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4222 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4224 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4225 IS_INDESTRUCTIBLE(i)));
4227 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4229 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4230 else if (engine_version < VERSION_IDENT(2,2,0,0))
4231 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4233 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4237 if (IS_CUSTOM_ELEMENT(i))
4239 /* these are additional properties which are initially false when set */
4241 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4243 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4244 if (DONT_COLLIDE_WITH(i))
4245 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4247 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4248 if (CAN_SMASH_EVERYTHING(i))
4249 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4250 if (CAN_SMASH_ENEMIES(i))
4251 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4254 /* ---------- CAN_SMASH ------------------------------------------------ */
4255 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4256 CAN_SMASH_ENEMIES(i) ||
4257 CAN_SMASH_EVERYTHING(i)));
4259 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4260 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4261 EXPLODES_BY_FIRE(i)));
4263 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4264 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4265 EXPLODES_SMASHED(i)));
4267 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4268 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4269 EXPLODES_IMPACT(i)));
4271 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4272 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4274 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4275 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4276 i == EL_BLACK_ORB));
4278 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4279 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4281 IS_CUSTOM_ELEMENT(i)));
4283 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4284 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4285 i == EL_SP_ELECTRON));
4287 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4288 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4289 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4290 getMoveIntoAcidProperty(&level, i));
4292 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4293 if (MAYBE_DONT_COLLIDE_WITH(i))
4294 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4295 getDontCollideWithProperty(&level, i));
4297 /* ---------- SP_PORT -------------------------------------------------- */
4298 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4299 IS_PASSABLE_INSIDE(i)));
4301 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4302 for (j = 0; j < level.num_android_clone_elements; j++)
4303 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4305 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4307 /* ---------- CAN_CHANGE ----------------------------------------------- */
4308 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4309 for (j = 0; j < element_info[i].num_change_pages; j++)
4310 if (element_info[i].change_page[j].can_change)
4311 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4313 /* ---------- HAS_ACTION ----------------------------------------------- */
4314 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4315 for (j = 0; j < element_info[i].num_change_pages; j++)
4316 if (element_info[i].change_page[j].has_action)
4317 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4319 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4320 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4323 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4325 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4326 element_info[i].crumbled[ACTION_DEFAULT] !=
4327 element_info[i].graphic[ACTION_DEFAULT]);
4329 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
4330 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4331 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
4334 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4335 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4336 IS_EDITOR_CASCADE_INACTIVE(i)));
4339 /* dynamically adjust element properties according to game engine version */
4341 static int ep_em_slippery_wall[] =
4346 EL_EXPANDABLE_WALL_HORIZONTAL,
4347 EL_EXPANDABLE_WALL_VERTICAL,
4348 EL_EXPANDABLE_WALL_ANY,
4349 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4350 EL_EXPANDABLE_STEELWALL_VERTICAL,
4351 EL_EXPANDABLE_STEELWALL_ANY,
4352 EL_EXPANDABLE_STEELWALL_GROWING,
4356 /* special EM style gems behaviour */
4357 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4358 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4359 level.em_slippery_gems);
4361 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4362 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4363 (level.em_slippery_gems &&
4364 engine_version > VERSION_IDENT(2,0,1,0)));
4367 /* this is needed because some graphics depend on element properties */
4368 if (game_status == GAME_MODE_PLAYING)
4369 InitElementGraphicInfo();
4372 void InitElementPropertiesAfterLoading(int engine_version)
4376 /* set some other uninitialized values of custom elements in older levels */
4377 if (engine_version < VERSION_IDENT(3,1,0,0))
4379 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4381 int element = EL_CUSTOM_START + i;
4383 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4385 element_info[element].explosion_delay = 17;
4386 element_info[element].ignition_delay = 8;
4391 static void InitGlobal()
4395 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4397 /* check if element_name_info entry defined for each element in "main.h" */
4398 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4399 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4401 element_info[i].token_name = element_name_info[i].token_name;
4402 element_info[i].class_name = element_name_info[i].class_name;
4403 element_info[i].editor_description=element_name_info[i].editor_description;
4406 printf("%04d: %s\n", i, element_name_info[i].token_name);
4410 global.autoplay_leveldir = NULL;
4411 global.convert_leveldir = NULL;
4413 global.frames_per_second = 0;
4414 global.fps_slowdown = FALSE;
4415 global.fps_slowdown_factor = 1;
4418 void Execute_Command(char *command)
4422 if (strEqual(command, "print graphicsinfo.conf"))
4424 printf("# You can configure additional/alternative image files here.\n");
4425 printf("# (The entries below are default and therefore commented out.)\n");
4427 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4429 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4432 for (i = 0; image_config[i].token != NULL; i++)
4433 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
4434 image_config[i].value));
4438 else if (strEqual(command, "print soundsinfo.conf"))
4440 printf("# You can configure additional/alternative sound files here.\n");
4441 printf("# (The entries below are default and therefore commented out.)\n");
4443 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4445 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4448 for (i = 0; sound_config[i].token != NULL; i++)
4449 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4450 sound_config[i].value));
4454 else if (strEqual(command, "print musicinfo.conf"))
4456 printf("# You can configure additional/alternative music files here.\n");
4457 printf("# (The entries below are default and therefore commented out.)\n");
4459 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4461 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4464 for (i = 0; music_config[i].token != NULL; i++)
4465 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
4466 music_config[i].value));
4470 else if (strEqual(command, "print editorsetup.conf"))
4472 printf("# You can configure your personal editor element list here.\n");
4473 printf("# (The entries below are default and therefore commented out.)\n");
4476 /* this is needed to be able to check element list for cascade elements */
4477 InitElementPropertiesStatic();
4478 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4480 PrintEditorElementList();
4484 else if (strEqual(command, "print helpanim.conf"))
4486 printf("# You can configure different element help animations here.\n");
4487 printf("# (The entries below are default and therefore commented out.)\n");
4490 for (i = 0; helpanim_config[i].token != NULL; i++)
4492 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4493 helpanim_config[i].value));
4495 if (strEqual(helpanim_config[i].token, "end"))
4501 else if (strEqual(command, "print helptext.conf"))
4503 printf("# You can configure different element help text here.\n");
4504 printf("# (The entries below are default and therefore commented out.)\n");
4507 for (i = 0; helptext_config[i].token != NULL; i++)
4508 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4509 helptext_config[i].value));
4513 else if (strncmp(command, "dump level ", 11) == 0)
4515 char *filename = &command[11];
4517 if (!fileExists(filename))
4518 Error(ERR_EXIT, "cannot open file '%s'", filename);
4520 LoadLevelFromFilename(&level, filename);
4525 else if (strncmp(command, "dump tape ", 10) == 0)
4527 char *filename = &command[10];
4529 if (!fileExists(filename))
4530 Error(ERR_EXIT, "cannot open file '%s'", filename);
4532 LoadTapeFromFilename(filename);
4537 else if (strncmp(command, "autoplay ", 9) == 0)
4539 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
4541 while (*str_ptr != '\0') /* continue parsing string */
4543 /* cut leading whitespace from string, replace it by string terminator */
4544 while (*str_ptr == ' ' || *str_ptr == '\t')
4547 if (*str_ptr == '\0') /* end of string reached */
4550 if (global.autoplay_leveldir == NULL) /* read level set string */
4552 global.autoplay_leveldir = str_ptr;
4553 global.autoplay_all = TRUE; /* default: play all tapes */
4555 for (i = 0; i < MAX_TAPES_PER_SET; i++)
4556 global.autoplay_level[i] = FALSE;
4558 else /* read level number string */
4560 int level_nr = atoi(str_ptr); /* get level_nr value */
4562 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
4563 global.autoplay_level[level_nr] = TRUE;
4565 global.autoplay_all = FALSE;
4568 /* advance string pointer to the next whitespace (or end of string) */
4569 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
4573 else if (strncmp(command, "convert ", 8) == 0)
4575 char *str_copy = getStringCopy(&command[8]);
4576 char *str_ptr = strchr(str_copy, ' ');
4578 global.convert_leveldir = str_copy;
4579 global.convert_level_nr = -1;
4581 if (str_ptr != NULL) /* level number follows */
4583 *str_ptr++ = '\0'; /* terminate leveldir string */
4584 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
4589 #if defined(TARGET_SDL)
4590 else if (strEqual(command, "SDL_ListModes"))
4595 SDL_Init(SDL_INIT_VIDEO);
4597 /* get available fullscreen/hardware modes */
4598 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
4600 /* check if there are any modes available */
4603 printf("No modes available!\n");
4608 /* check if our resolution is restricted */
4609 if (modes == (SDL_Rect **)-1)
4611 printf("All resolutions available.\n");
4615 printf("Available Modes:\n");
4617 for(i = 0; modes[i]; i++)
4618 printf(" %d x %d\n", modes[i]->w, modes[i]->h);
4628 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4632 static void InitSetup()
4634 LoadSetup(); /* global setup info */
4636 /* set some options from setup file */
4638 if (setup.options.verbose)
4639 options.verbose = TRUE;
4642 static void InitGameInfo()
4644 game.restart_level = FALSE;
4647 static void InitPlayerInfo()
4651 /* choose default local player */
4652 local_player = &stored_player[0];
4654 for (i = 0; i < MAX_PLAYERS; i++)
4655 stored_player[i].connected = FALSE;
4657 local_player->connected = TRUE;
4660 static void InitArtworkInfo()
4665 static char *get_string_in_brackets(char *string)
4667 char *string_in_brackets = checked_malloc(strlen(string) + 3);
4669 sprintf(string_in_brackets, "[%s]", string);
4671 return string_in_brackets;
4674 static char *get_level_id_suffix(int id_nr)
4676 char *id_suffix = checked_malloc(1 + 3 + 1);
4678 if (id_nr < 0 || id_nr > 999)
4681 sprintf(id_suffix, ".%03d", id_nr);
4687 static char *get_element_class_token(int element)
4689 char *element_class_name = element_info[element].class_name;
4690 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
4692 sprintf(element_class_token, "[%s]", element_class_name);
4694 return element_class_token;
4697 static char *get_action_class_token(int action)
4699 char *action_class_name = &element_action_info[action].suffix[1];
4700 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
4702 sprintf(action_class_token, "[%s]", action_class_name);
4704 return action_class_token;
4708 static void InitArtworkConfig()
4710 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
4711 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
4712 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
4713 static char *action_id_suffix[NUM_ACTIONS + 1];
4714 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
4715 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
4716 static char *level_id_suffix[MAX_LEVELS + 1];
4717 static char *dummy[1] = { NULL };
4718 static char *ignore_generic_tokens[] =
4724 static char **ignore_image_tokens;
4725 static char **ignore_sound_tokens;
4726 static char **ignore_music_tokens;
4727 int num_ignore_generic_tokens;
4728 int num_ignore_image_tokens;
4729 int num_ignore_sound_tokens;
4730 int num_ignore_music_tokens;
4733 /* dynamically determine list of generic tokens to be ignored */
4734 num_ignore_generic_tokens = 0;
4735 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
4736 num_ignore_generic_tokens++;
4738 /* dynamically determine list of image tokens to be ignored */
4739 num_ignore_image_tokens = num_ignore_generic_tokens;
4740 for (i = 0; image_config_vars[i].token != NULL; i++)
4741 num_ignore_image_tokens++;
4742 ignore_image_tokens =
4743 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
4744 for (i = 0; i < num_ignore_generic_tokens; i++)
4745 ignore_image_tokens[i] = ignore_generic_tokens[i];
4746 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
4747 ignore_image_tokens[num_ignore_generic_tokens + i] =
4748 image_config_vars[i].token;
4749 ignore_image_tokens[num_ignore_image_tokens] = NULL;
4751 /* dynamically determine list of sound tokens to be ignored */
4752 num_ignore_sound_tokens = num_ignore_generic_tokens;
4753 ignore_sound_tokens =
4754 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
4755 for (i = 0; i < num_ignore_generic_tokens; i++)
4756 ignore_sound_tokens[i] = ignore_generic_tokens[i];
4757 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
4759 /* dynamically determine list of music tokens to be ignored */
4760 num_ignore_music_tokens = num_ignore_generic_tokens;
4761 ignore_music_tokens =
4762 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
4763 for (i = 0; i < num_ignore_generic_tokens; i++)
4764 ignore_music_tokens[i] = ignore_generic_tokens[i];
4765 ignore_music_tokens[num_ignore_music_tokens] = NULL;
4767 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4768 image_id_prefix[i] = element_info[i].token_name;
4769 for (i = 0; i < NUM_FONTS; i++)
4770 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
4771 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
4773 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4774 sound_id_prefix[i] = element_info[i].token_name;
4775 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4776 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
4777 get_string_in_brackets(element_info[i].class_name);
4778 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
4780 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
4781 music_id_prefix[i] = music_prefix_info[i].prefix;
4782 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
4784 for (i = 0; i < NUM_ACTIONS; i++)
4785 action_id_suffix[i] = element_action_info[i].suffix;
4786 action_id_suffix[NUM_ACTIONS] = NULL;
4788 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
4789 direction_id_suffix[i] = element_direction_info[i].suffix;
4790 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
4792 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
4793 special_id_suffix[i] = special_suffix_info[i].suffix;
4794 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
4796 for (i = 0; i < MAX_LEVELS; i++)
4797 level_id_suffix[i] = get_level_id_suffix(i);
4798 level_id_suffix[MAX_LEVELS] = NULL;
4800 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
4801 image_id_prefix, action_id_suffix, direction_id_suffix,
4802 special_id_suffix, ignore_image_tokens);
4803 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
4804 sound_id_prefix, action_id_suffix, dummy,
4805 special_id_suffix, ignore_sound_tokens);
4806 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
4807 music_id_prefix, special_id_suffix, level_id_suffix,
4808 dummy, ignore_music_tokens);
4811 static void InitMixer()
4819 char *filename_font_initial = NULL;
4820 Bitmap *bitmap_font_initial = NULL;
4824 /* determine settings for initial font (for displaying startup messages) */
4825 for (i = 0; image_config[i].token != NULL; i++)
4827 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4829 char font_token[128];
4832 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
4833 len_font_token = strlen(font_token);
4835 if (strEqual(image_config[i].token, font_token))
4836 filename_font_initial = image_config[i].value;
4837 else if (strlen(image_config[i].token) > len_font_token &&
4838 strncmp(image_config[i].token, font_token, len_font_token) == 0)
4840 if (strEqual(&image_config[i].token[len_font_token], ".x"))
4841 font_initial[j].src_x = atoi(image_config[i].value);
4842 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
4843 font_initial[j].src_y = atoi(image_config[i].value);
4844 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
4845 font_initial[j].width = atoi(image_config[i].value);
4846 else if (strEqual(&image_config[i].token[len_font_token],".height"))
4847 font_initial[j].height = atoi(image_config[i].value);
4852 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4854 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
4855 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
4858 if (filename_font_initial == NULL) /* should not happen */
4859 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
4861 /* create additional image buffers for double-buffering and cross-fading */
4862 bitmap_db_cross = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
4863 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
4864 bitmap_db_panel = CreateBitmap(DXSIZE, DYSIZE, DEFAULT_DEPTH);
4865 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
4867 /* initialize screen properties */
4868 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
4869 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
4871 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
4872 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
4873 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
4875 bitmap_font_initial = LoadCustomImage(filename_font_initial);
4877 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4878 font_initial[j].bitmap = bitmap_font_initial;
4880 InitFontGraphicInfo();
4882 font_height = getFontHeight(FC_RED);
4885 DrawInitText(getWindowTitleString(), 20, FC_YELLOW);
4887 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
4889 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
4890 DrawInitText(PROGRAM_WEBSITE_STRING, WIN_YSIZE - 20 - font_height, FC_RED);
4892 DrawInitText("Loading graphics", 120, FC_GREEN);
4895 void RedrawBackground()
4897 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
4898 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
4900 redraw_mask = REDRAW_ALL;
4903 void InitGfxBackground()
4907 fieldbuffer = bitmap_db_field;
4908 SetDrawtoField(DRAW_BACKBUFFER);
4912 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
4913 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
4915 for (x = 0; x < MAX_BUF_XSIZE; x++)
4916 for (y = 0; y < MAX_BUF_YSIZE; y++)
4919 redraw_mask = REDRAW_ALL;
4922 static void InitLevelInfo()
4924 LoadLevelInfo(); /* global level info */
4925 LoadLevelSetup_LastSeries(); /* last played series info */
4926 LoadLevelSetup_SeriesInfo(); /* last played level info */
4929 void InitLevelArtworkInfo()
4931 LoadLevelArtworkInfo();
4934 static void InitImages()
4936 setLevelArtworkDir(artwork.gfx_first);
4939 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
4940 leveldir_current->identifier,
4941 artwork.gfx_current_identifier,
4942 artwork.gfx_current->identifier,
4943 leveldir_current->graphics_set,
4944 leveldir_current->graphics_path);
4947 ReloadCustomImages();
4949 LoadCustomElementDescriptions();
4950 LoadSpecialMenuDesignSettings();
4952 ReinitializeGraphics();
4955 static void InitSound(char *identifier)
4957 if (identifier == NULL)
4958 identifier = artwork.snd_current->identifier;
4960 /* set artwork path to send it to the sound server process */
4961 setLevelArtworkDir(artwork.snd_first);
4963 InitReloadCustomSounds(identifier);
4964 ReinitializeSounds();
4967 static void InitMusic(char *identifier)
4969 if (identifier == NULL)
4970 identifier = artwork.mus_current->identifier;
4972 /* set artwork path to send it to the sound server process */
4973 setLevelArtworkDir(artwork.mus_first);
4975 InitReloadCustomMusic(identifier);
4976 ReinitializeMusic();
4979 void InitNetworkServer()
4981 #if defined(NETWORK_AVALIABLE)
4985 if (!options.network)
4988 #if defined(NETWORK_AVALIABLE)
4989 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
4991 if (!ConnectToServer(options.server_host, options.server_port))
4992 Error(ERR_EXIT, "cannot connect to network game server");
4994 SendToServer_PlayerName(setup.player_name);
4995 SendToServer_ProtocolVersion();
4998 SendToServer_NrWanted(nr_wanted);
5002 static char *getNewArtworkIdentifier(int type)
5004 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5005 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5006 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5007 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5008 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5009 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
5010 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5011 char *leveldir_identifier = leveldir_current->identifier;
5013 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
5014 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5016 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
5018 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5019 char *artwork_current_identifier;
5020 char *artwork_new_identifier = NULL; /* default: nothing has changed */
5022 /* leveldir_current may be invalid (level group, parent link) */
5023 if (!validLevelSeries(leveldir_current))
5026 /* 1st step: determine artwork set to be activated in descending order:
5027 --------------------------------------------------------------------
5028 1. setup artwork (when configured to override everything else)
5029 2. artwork set configured in "levelinfo.conf" of current level set
5030 (artwork in level directory will have priority when loading later)
5031 3. artwork in level directory (stored in artwork sub-directory)
5032 4. setup artwork (currently configured in setup menu) */
5034 if (setup_override_artwork)
5035 artwork_current_identifier = setup_artwork_set;
5036 else if (leveldir_artwork_set != NULL)
5037 artwork_current_identifier = leveldir_artwork_set;
5038 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5039 artwork_current_identifier = leveldir_identifier;
5041 artwork_current_identifier = setup_artwork_set;
5044 /* 2nd step: check if it is really needed to reload artwork set
5045 ------------------------------------------------------------ */
5048 if (type == ARTWORK_TYPE_GRAPHICS)
5049 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
5050 artwork_new_identifier,
5051 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5052 artwork_current_identifier,
5053 leveldir_current->graphics_set,
5054 leveldir_current->identifier);
5057 /* ---------- reload if level set and also artwork set has changed ------- */
5058 if (leveldir_current_identifier[type] != leveldir_identifier &&
5059 (last_has_level_artwork_set[type] || has_level_artwork_set))
5060 artwork_new_identifier = artwork_current_identifier;
5062 leveldir_current_identifier[type] = leveldir_identifier;
5063 last_has_level_artwork_set[type] = has_level_artwork_set;
5066 if (type == ARTWORK_TYPE_GRAPHICS)
5067 printf("::: 1: '%s'\n", artwork_new_identifier);
5070 /* ---------- reload if "override artwork" setting has changed ----------- */
5071 if (last_override_level_artwork[type] != setup_override_artwork)
5072 artwork_new_identifier = artwork_current_identifier;
5074 last_override_level_artwork[type] = setup_override_artwork;
5077 if (type == ARTWORK_TYPE_GRAPHICS)
5078 printf("::: 2: '%s'\n", artwork_new_identifier);
5081 /* ---------- reload if current artwork identifier has changed ----------- */
5082 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5083 artwork_current_identifier))
5084 artwork_new_identifier = artwork_current_identifier;
5086 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5089 if (type == ARTWORK_TYPE_GRAPHICS)
5090 printf("::: 3: '%s'\n", artwork_new_identifier);
5093 /* ---------- do not reload directly after starting ---------------------- */
5094 if (!initialized[type])
5095 artwork_new_identifier = NULL;
5097 initialized[type] = TRUE;
5100 if (type == ARTWORK_TYPE_GRAPHICS)
5101 printf("::: 4: '%s'\n", artwork_new_identifier);
5105 if (type == ARTWORK_TYPE_GRAPHICS)
5106 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
5107 artwork.gfx_current_identifier, artwork_current_identifier,
5108 artwork.gfx_current->identifier, leveldir_current->graphics_set,
5109 artwork_new_identifier);
5112 return artwork_new_identifier;
5115 void ReloadCustomArtwork(int force_reload)
5117 char *gfx_new_identifier;
5118 char *snd_new_identifier;
5119 char *mus_new_identifier;
5120 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5121 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5122 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5123 boolean redraw_screen = FALSE;
5125 force_reload_gfx |= AdjustGraphicsForEMC();
5127 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5128 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5129 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5131 if (gfx_new_identifier != NULL || force_reload_gfx)
5134 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5135 artwork.gfx_current_identifier,
5137 artwork.gfx_current->identifier,
5138 leveldir_current->graphics_set);
5141 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
5145 redraw_screen = TRUE;
5148 if (snd_new_identifier != NULL || force_reload_snd)
5150 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
5152 InitSound(snd_new_identifier);
5154 redraw_screen = TRUE;
5157 if (mus_new_identifier != NULL || force_reload_mus)
5159 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
5161 InitMusic(mus_new_identifier);
5163 redraw_screen = TRUE;
5170 /* force redraw of (open or closed) door graphics */
5171 SetDoorState(DOOR_OPEN_ALL);
5172 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5176 void KeyboardAutoRepeatOffUnlessAutoplay()
5178 if (global.autoplay_leveldir == NULL)
5179 KeyboardAutoRepeatOff();
5183 /* ========================================================================= */
5185 /* ========================================================================= */
5189 InitGlobal(); /* initialize some global variables */
5191 if (options.execute_command)
5192 Execute_Command(options.execute_command);
5194 if (options.serveronly)
5196 #if defined(PLATFORM_UNIX)
5197 NetworkServer(options.server_port, options.serveronly);
5199 Error(ERR_WARN, "networking only supported in Unix version");
5202 exit(0); /* never reached, server loops forever */
5209 InitArtworkInfo(); /* needed before loading gfx, sound & music */
5210 InitArtworkConfig(); /* needed before forking sound child process */
5215 InitRND(NEW_RANDOMIZE);
5216 InitSimpleRandom(NEW_RANDOMIZE);
5221 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
5223 InitEventFilter(FilterMouseMotionEvents);
5225 InitElementPropertiesStatic();
5226 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5230 // debug_print_timestamp(0, "INIT");
5232 // debug_print_timestamp(0, "TIME InitLevelInfo: ");
5233 InitLevelArtworkInfo();
5234 // debug_print_timestamp(0, "TIME InitLevelArtworkInfo: ");
5236 InitImages(); /* needs to know current level directory */
5237 InitSound(NULL); /* needs to know current level directory */
5238 InitMusic(NULL); /* needs to know current level directory */
5240 InitGfxBackground();
5246 if (global.autoplay_leveldir)
5251 else if (global.convert_leveldir)
5257 game_status = GAME_MODE_MAIN;
5261 InitNetworkServer();
5264 void CloseAllAndExit(int exit_value)
5269 CloseAudio(); /* called after freeing sounds (needed for SDL) */
5277 #if defined(TARGET_SDL)
5278 if (network_server) /* terminate network server */
5279 SDL_KillThread(server_thread);
5282 CloseVideoDisplay();
5283 ClosePlatformDependentStuff();
5285 if (exit_value != 0)
5286 NotifyUserAboutErrorFile();