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 */
35 #include "conf_act.c" /* include auto-generated data structure definitions */
38 #define CONFIG_TOKEN_FONT_INITIAL "font.initial"
39 #define CONFIG_TOKEN_GLOBAL_BUSY "global.busy"
41 #define DEBUG_PRINT_INIT_TIMESTAMPS TRUE
42 #define DEBUG_PRINT_INIT_TIMESTAMPS_DEPTH 3
45 static struct FontBitmapInfo font_initial[NUM_INITIAL_FONTS];
46 static struct GraphicInfo anim_initial;
48 static int copy_properties[][5] =
52 EL_BUG_LEFT, EL_BUG_RIGHT,
53 EL_BUG_UP, EL_BUG_DOWN
57 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
58 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
62 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
63 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
67 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
68 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
72 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
73 EL_PACMAN_UP, EL_PACMAN_DOWN
77 EL_YAMYAM_LEFT, EL_YAMYAM_RIGHT,
78 EL_YAMYAM_UP, EL_YAMYAM_DOWN
82 EL_MOLE_LEFT, EL_MOLE_RIGHT,
83 EL_MOLE_UP, EL_MOLE_DOWN
92 static void print_init_timestamp(char *message)
95 #if DEBUG_PRINT_INIT_TIMESTAMPS
96 static char *last_message = NULL;
97 static int counter_nr = 0;
98 int max_depth = DEBUG_PRINT_INIT_TIMESTAMPS_DEPTH;
100 if (strPrefix(message, "INIT"))
102 if (counter_nr + 1 < max_depth)
104 debug_print_timestamp(counter_nr, NULL);
105 debug_print_timestamp(counter_nr, message);
110 debug_print_timestamp(counter_nr, NULL);
112 else if (strPrefix(message, "DONE"))
116 if (counter_nr + 1 < max_depth ||
117 (counter_nr == 0 && max_depth == 1))
119 last_message = &message[4];
121 debug_print_timestamp(counter_nr, message);
124 else if (!strPrefix(message, "TIME") ||
125 !strSuffix(message, last_message))
127 if (counter_nr < max_depth)
128 debug_print_timestamp(counter_nr, message);
136 struct GraphicInfo *graphic_info_last = graphic_info;
138 static unsigned long action_delay = 0;
139 unsigned long action_delay_value = GameFrameDelay;
140 int sync_frame = FrameCounter;
143 if (anim_initial.bitmap == NULL || window == NULL)
146 if (!DelayReached(&action_delay, action_delay_value))
151 static unsigned long last_counter = -1;
152 unsigned long current_counter = Counter();
153 unsigned long delay = current_counter - last_counter;
155 if (last_counter != -1 && delay > action_delay_value + 5)
156 printf("::: DrawInitAnim: DELAY TOO LONG: %ld\n", delay);
158 last_counter = current_counter;
163 anim_initial.anim_mode = ANIM_LOOP;
164 anim_initial.anim_start_frame = 0;
165 anim_initial.offset_x = anim_initial.width;
166 anim_initial.offset_y = 0;
170 x = ALIGNED_TEXT_XPOS(&init.busy);
171 y = ALIGNED_TEXT_YPOS(&init.busy);
173 x = WIN_XSIZE / 2 - TILESIZE / 2;
174 y = WIN_YSIZE / 2 - TILESIZE / 2;
179 static boolean done = FALSE;
182 printf("::: %d, %d, %d, %d => %d, %d\n",
183 init.busy.x, init.busy.y,
184 init.busy.align, init.busy.valign,
191 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
193 if (sync_frame % anim_initial.anim_delay == 0)
194 DrawGraphicAnimationExt(window, x, y, graphic, sync_frame, NO_MASKING);
196 graphic_info = graphic_info_last;
203 FreeLevelEditorGadgets();
212 static boolean gadgets_initialized = FALSE;
214 if (gadgets_initialized)
217 CreateLevelEditorGadgets();
221 CreateScreenGadgets();
223 InitGadgetsSoundCallback(PlaySoundActivating, PlaySoundSelecting);
225 gadgets_initialized = TRUE;
228 inline void InitElementSmallImagesScaledUp(int graphic)
231 struct FileInfo *fi = getImageListEntryFromImageID(graphic);
233 printf("::: '%s' -> '%s'\n", fi->token, fi->filename);
236 CreateImageWithSmallImages(graphic, graphic_info[graphic].scale_up_factor);
239 void InitElementSmallImages()
241 static int special_graphics[] =
243 IMG_EDITOR_ELEMENT_BORDER,
244 IMG_EDITOR_ELEMENT_BORDER_INPUT,
245 IMG_EDITOR_CASCADE_LIST,
246 IMG_EDITOR_CASCADE_LIST_ACTIVE,
249 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
250 int num_property_mappings = getImageListPropertyMappingSize();
253 /* initialize normal images from static configuration */
254 for (i = 0; element_to_graphic[i].element > -1; i++)
255 InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
257 /* initialize special images from static configuration */
258 for (i = 0; element_to_special_graphic[i].element > -1; i++)
259 InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
261 /* initialize images from dynamic configuration (may be elements or other) */
262 for (i = 0; i < num_property_mappings; i++)
263 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
265 /* initialize special images from above list (non-element images) */
266 for (i = 0; special_graphics[i] > -1; i++)
267 InitElementSmallImagesScaledUp(special_graphics[i]);
270 void InitScaledImages()
274 /* scale normal images from static configuration, if not already scaled */
275 for (i = 0; i < NUM_IMAGE_FILES; i++)
276 ScaleImage(i, graphic_info[i].scale_up_factor);
280 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
281 void SetBitmaps_EM(Bitmap **em_bitmap)
283 em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
284 em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].bitmap;
288 static int getFontBitmapID(int font_nr)
292 if (game_status >= GAME_MODE_TITLE_INITIAL &&
293 game_status <= GAME_MODE_PSEUDO_PREVIEW)
294 special = game_status;
295 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
296 special = GFX_SPECIAL_ARG_MAIN;
298 else if (game_status == GAME_MODE_PLAYING)
299 special = GFX_SPECIAL_ARG_DOOR;
303 return font_info[font_nr].special_bitmap_id[special];
308 static int getFontFromToken(char *token)
311 char *value = getHashEntry(font_token_hash, token);
318 /* !!! OPTIMIZE THIS BY USING HASH !!! */
319 for (i = 0; i < NUM_FONTS; i++)
320 if (strEqual(token, font_info[i].token_name))
324 /* if font not found, use reliable default value */
325 return FONT_INITIAL_1;
328 void InitFontGraphicInfo()
330 static struct FontBitmapInfo *font_bitmap_info = NULL;
331 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
332 int num_property_mappings = getImageListPropertyMappingSize();
333 int num_font_bitmaps = NUM_FONTS;
336 if (graphic_info == NULL) /* still at startup phase */
338 InitFontInfo(font_initial, NUM_INITIAL_FONTS,
339 getFontBitmapID, getFontFromToken);
344 /* ---------- initialize font graphic definitions ---------- */
346 /* always start with reliable default values (normal font graphics) */
347 for (i = 0; i < NUM_FONTS; i++)
348 font_info[i].graphic = IMG_FONT_INITIAL_1;
350 /* initialize normal font/graphic mapping from static configuration */
351 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
353 int font_nr = font_to_graphic[i].font_nr;
354 int special = font_to_graphic[i].special;
355 int graphic = font_to_graphic[i].graphic;
360 font_info[font_nr].graphic = graphic;
363 /* always start with reliable default values (special font graphics) */
364 for (i = 0; i < NUM_FONTS; i++)
366 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
368 font_info[i].special_graphic[j] = font_info[i].graphic;
369 font_info[i].special_bitmap_id[j] = i;
373 /* initialize special font/graphic mapping from static configuration */
374 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
376 int font_nr = font_to_graphic[i].font_nr;
377 int special = font_to_graphic[i].special;
378 int graphic = font_to_graphic[i].graphic;
379 int base_graphic = font2baseimg(font_nr);
381 if (IS_SPECIAL_GFX_ARG(special))
383 boolean base_redefined =
384 getImageListEntryFromImageID(base_graphic)->redefined;
385 boolean special_redefined =
386 getImageListEntryFromImageID(graphic)->redefined;
387 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
389 /* if the base font ("font.title_1", for example) has been redefined,
390 but not the special font ("font.title_1.LEVELS", for example), do not
391 use an existing (in this case considered obsolete) special font
392 anymore, but use the automatically determined default font */
393 /* special case: cloned special fonts must be explicitly redefined,
394 but are not automatically redefined by redefining base font */
395 if (base_redefined && !special_redefined && !special_cloned)
398 font_info[font_nr].special_graphic[special] = graphic;
399 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
404 /* initialize special font/graphic mapping from dynamic configuration */
405 for (i = 0; i < num_property_mappings; i++)
407 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
408 int special = property_mapping[i].ext3_index;
409 int graphic = property_mapping[i].artwork_index;
414 if (IS_SPECIAL_GFX_ARG(special))
416 font_info[font_nr].special_graphic[special] = graphic;
417 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
422 /* correct special font/graphic mapping for cloned fonts for downwards
423 compatibility of PREVIEW fonts -- this is only needed for implicit
424 redefinition of special font by redefined base font, and only if other
425 fonts are cloned from this special font (like in the "Zelda" level set) */
426 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
428 int font_nr = font_to_graphic[i].font_nr;
429 int special = font_to_graphic[i].special;
430 int graphic = font_to_graphic[i].graphic;
432 if (IS_SPECIAL_GFX_ARG(special))
434 boolean special_redefined =
435 getImageListEntryFromImageID(graphic)->redefined;
436 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
438 if (special_cloned && !special_redefined)
442 for (j = 0; font_to_graphic[j].font_nr > -1; j++)
444 int font_nr2 = font_to_graphic[j].font_nr;
445 int special2 = font_to_graphic[j].special;
446 int graphic2 = font_to_graphic[j].graphic;
448 if (IS_SPECIAL_GFX_ARG(special2) &&
449 graphic2 == graphic_info[graphic].clone_from)
451 font_info[font_nr].special_graphic[special] =
452 font_info[font_nr2].special_graphic[special2];
453 font_info[font_nr].special_bitmap_id[special] =
454 font_info[font_nr2].special_bitmap_id[special2];
461 /* reset non-redefined ".active" font graphics if normal font is redefined */
462 /* (this different treatment is needed because normal and active fonts are
463 independently defined ("active" is not a property of font definitions!) */
464 for (i = 0; i < NUM_FONTS; i++)
466 int font_nr_base = i;
467 int font_nr_active = FONT_ACTIVE(font_nr_base);
469 /* check only those fonts with exist as normal and ".active" variant */
470 if (font_nr_base != font_nr_active)
472 int base_graphic = font_info[font_nr_base].graphic;
473 int active_graphic = font_info[font_nr_active].graphic;
474 boolean base_redefined =
475 getImageListEntryFromImageID(base_graphic)->redefined;
476 boolean active_redefined =
477 getImageListEntryFromImageID(active_graphic)->redefined;
479 /* if the base font ("font.menu_1", for example) has been redefined,
480 but not the active font ("font.menu_1.active", for example), do not
481 use an existing (in this case considered obsolete) active font
482 anymore, but use the automatically determined default font */
483 if (base_redefined && !active_redefined)
484 font_info[font_nr_active].graphic = base_graphic;
486 /* now also check each "special" font (which may be the same as above) */
487 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
489 int base_graphic = font_info[font_nr_base].special_graphic[j];
490 int active_graphic = font_info[font_nr_active].special_graphic[j];
491 boolean base_redefined =
492 getImageListEntryFromImageID(base_graphic)->redefined;
493 boolean active_redefined =
494 getImageListEntryFromImageID(active_graphic)->redefined;
496 /* same as above, but check special graphic definitions, for example:
497 redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN" */
498 if (base_redefined && !active_redefined)
500 font_info[font_nr_active].special_graphic[j] =
501 font_info[font_nr_base].special_graphic[j];
502 font_info[font_nr_active].special_bitmap_id[j] =
503 font_info[font_nr_base].special_bitmap_id[j];
509 /* ---------- initialize font bitmap array ---------- */
511 if (font_bitmap_info != NULL)
512 FreeFontInfo(font_bitmap_info);
515 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
517 /* ---------- initialize font bitmap definitions ---------- */
519 for (i = 0; i < NUM_FONTS; i++)
521 if (i < NUM_INITIAL_FONTS)
523 font_bitmap_info[i] = font_initial[i];
527 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
529 int font_bitmap_id = font_info[i].special_bitmap_id[j];
530 int graphic = font_info[i].special_graphic[j];
532 /* set 'graphic_info' for font entries, if uninitialized (guessed) */
533 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
535 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
536 graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
539 /* copy font relevant information from graphics information */
540 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
541 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
542 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
543 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
544 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
546 font_bitmap_info[font_bitmap_id].draw_xoffset =
547 graphic_info[graphic].draw_xoffset;
548 font_bitmap_info[font_bitmap_id].draw_yoffset =
549 graphic_info[graphic].draw_yoffset;
551 font_bitmap_info[font_bitmap_id].num_chars =
552 graphic_info[graphic].anim_frames;
553 font_bitmap_info[font_bitmap_id].num_chars_per_line =
554 graphic_info[graphic].anim_frames_per_line;
558 InitFontInfo(font_bitmap_info, num_font_bitmaps,
559 getFontBitmapID, getFontFromToken);
562 void InitElementGraphicInfo()
564 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
565 int num_property_mappings = getImageListPropertyMappingSize();
568 if (graphic_info == NULL) /* still at startup phase */
571 /* set values to -1 to identify later as "uninitialized" values */
572 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
574 for (act = 0; act < NUM_ACTIONS; act++)
576 element_info[i].graphic[act] = -1;
577 element_info[i].crumbled[act] = -1;
579 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
581 element_info[i].direction_graphic[act][dir] = -1;
582 element_info[i].direction_crumbled[act][dir] = -1;
589 /* initialize normal element/graphic mapping from static configuration */
590 for (i = 0; element_to_graphic[i].element > -1; i++)
592 int element = element_to_graphic[i].element;
593 int action = element_to_graphic[i].action;
594 int direction = element_to_graphic[i].direction;
595 boolean crumbled = element_to_graphic[i].crumbled;
596 int graphic = element_to_graphic[i].graphic;
597 int base_graphic = el2baseimg(element);
599 if (graphic_info[graphic].bitmap == NULL)
602 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
605 boolean base_redefined =
606 getImageListEntryFromImageID(base_graphic)->redefined;
607 boolean act_dir_redefined =
608 getImageListEntryFromImageID(graphic)->redefined;
610 /* if the base graphic ("emerald", for example) has been redefined,
611 but not the action graphic ("emerald.falling", for example), do not
612 use an existing (in this case considered obsolete) action graphic
613 anymore, but use the automatically determined default graphic */
614 if (base_redefined && !act_dir_redefined)
619 action = ACTION_DEFAULT;
624 element_info[element].direction_crumbled[action][direction] = graphic;
626 element_info[element].crumbled[action] = graphic;
631 element_info[element].direction_graphic[action][direction] = graphic;
633 element_info[element].graphic[action] = graphic;
637 /* initialize normal element/graphic mapping from dynamic configuration */
638 for (i = 0; i < num_property_mappings; i++)
640 int element = property_mapping[i].base_index;
641 int action = property_mapping[i].ext1_index;
642 int direction = property_mapping[i].ext2_index;
643 int special = property_mapping[i].ext3_index;
644 int graphic = property_mapping[i].artwork_index;
645 boolean crumbled = FALSE;
648 if ((element == EL_EM_DYNAMITE ||
649 element == EL_EM_DYNAMITE_ACTIVE) &&
650 action == ACTION_ACTIVE &&
651 (special == GFX_SPECIAL_ARG_EDITOR ||
652 special == GFX_SPECIAL_ARG_PANEL))
653 printf("::: DYNAMIC: %d, %d, %d -> %d\n",
654 element, action, special, graphic);
657 if (special == GFX_SPECIAL_ARG_CRUMBLED)
663 if (graphic_info[graphic].bitmap == NULL)
666 if (element >= MAX_NUM_ELEMENTS || special != -1)
670 action = ACTION_DEFAULT;
675 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
676 element_info[element].direction_crumbled[action][dir] = -1;
679 element_info[element].direction_crumbled[action][direction] = graphic;
681 element_info[element].crumbled[action] = graphic;
686 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
687 element_info[element].direction_graphic[action][dir] = -1;
690 element_info[element].direction_graphic[action][direction] = graphic;
692 element_info[element].graphic[action] = graphic;
696 /* now copy all graphics that are defined to be cloned from other graphics */
697 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
699 int graphic = element_info[i].graphic[ACTION_DEFAULT];
700 int crumbled_like, diggable_like;
705 crumbled_like = graphic_info[graphic].crumbled_like;
706 diggable_like = graphic_info[graphic].diggable_like;
708 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
710 for (act = 0; act < NUM_ACTIONS; act++)
711 element_info[i].crumbled[act] =
712 element_info[crumbled_like].crumbled[act];
713 for (act = 0; act < NUM_ACTIONS; act++)
714 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
715 element_info[i].direction_crumbled[act][dir] =
716 element_info[crumbled_like].direction_crumbled[act][dir];
719 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
721 element_info[i].graphic[ACTION_DIGGING] =
722 element_info[diggable_like].graphic[ACTION_DIGGING];
723 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
724 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
725 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
730 /* set hardcoded definitions for some runtime elements without graphic */
731 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
735 /* set hardcoded definitions for some internal elements without graphic */
736 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
738 if (IS_EDITOR_CASCADE_INACTIVE(i))
739 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
740 else if (IS_EDITOR_CASCADE_ACTIVE(i))
741 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
745 /* now set all undefined/invalid graphics to -1 to set to default after it */
746 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
748 for (act = 0; act < NUM_ACTIONS; act++)
752 graphic = element_info[i].graphic[act];
753 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
754 element_info[i].graphic[act] = -1;
756 graphic = element_info[i].crumbled[act];
757 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
758 element_info[i].crumbled[act] = -1;
760 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
762 graphic = element_info[i].direction_graphic[act][dir];
763 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
764 element_info[i].direction_graphic[act][dir] = -1;
766 graphic = element_info[i].direction_crumbled[act][dir];
767 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
768 element_info[i].direction_crumbled[act][dir] = -1;
775 /* adjust graphics with 2nd tile for movement according to direction
776 (do this before correcting '-1' values to minimize calculations) */
777 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
779 for (act = 0; act < NUM_ACTIONS; act++)
781 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
783 int graphic = element_info[i].direction_graphic[act][dir];
784 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
786 if (act == ACTION_FALLING) /* special case */
787 graphic = element_info[i].graphic[act];
790 graphic_info[graphic].double_movement &&
791 graphic_info[graphic].swap_double_tiles != 0)
793 struct GraphicInfo *g = &graphic_info[graphic];
794 int src_x_front = g->src_x;
795 int src_y_front = g->src_y;
796 int src_x_back = g->src_x + g->offset2_x;
797 int src_y_back = g->src_y + g->offset2_y;
798 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
800 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
801 src_y_front < src_y_back);
802 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
803 boolean swap_movement_tiles_autodetected =
804 (!frames_are_ordered_diagonally &&
805 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
806 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
807 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
808 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
811 /* swap frontside and backside graphic tile coordinates, if needed */
812 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
814 /* get current (wrong) backside tile coordinates */
815 getGraphicSourceExt(graphic, 0, &dummy, &src_x_back, &src_y_back,
818 /* set frontside tile coordinates to backside tile coordinates */
819 g->src_x = src_x_back;
820 g->src_y = src_y_back;
822 /* invert tile offset to point to new backside tile coordinates */
826 /* do not swap front and backside tiles again after correction */
827 g->swap_double_tiles = 0;
836 /* now set all '-1' values to element specific default values */
837 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
839 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
840 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
841 int default_direction_graphic[NUM_DIRECTIONS_FULL];
842 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
844 if (default_graphic == -1)
845 default_graphic = IMG_UNKNOWN;
847 if (default_crumbled == -1)
848 default_crumbled = default_graphic;
850 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
851 if (default_crumbled == -1)
852 default_crumbled = IMG_EMPTY;
855 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
857 default_direction_graphic[dir] =
858 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
859 default_direction_crumbled[dir] =
860 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
862 if (default_direction_graphic[dir] == -1)
863 default_direction_graphic[dir] = default_graphic;
865 if (default_direction_crumbled[dir] == -1)
866 default_direction_crumbled[dir] = default_direction_graphic[dir];
868 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
869 if (default_direction_crumbled[dir] == -1)
870 default_direction_crumbled[dir] = default_crumbled;
874 for (act = 0; act < NUM_ACTIONS; act++)
876 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
877 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
878 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
879 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
880 act == ACTION_TURNING_FROM_RIGHT ||
881 act == ACTION_TURNING_FROM_UP ||
882 act == ACTION_TURNING_FROM_DOWN);
884 /* generic default action graphic (defined by "[default]" directive) */
885 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
886 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
887 int default_remove_graphic = IMG_EMPTY;
889 if (act_remove && default_action_graphic != -1)
890 default_remove_graphic = default_action_graphic;
892 /* look for special default action graphic (classic game specific) */
893 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
894 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
895 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
896 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
897 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
898 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
900 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
901 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
902 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
903 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
904 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
905 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
908 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
909 /* !!! make this better !!! */
910 if (i == EL_EMPTY_SPACE)
912 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
913 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
917 if (default_action_graphic == -1)
918 default_action_graphic = default_graphic;
920 if (default_action_crumbled == -1)
921 default_action_crumbled = default_action_graphic;
923 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
924 if (default_action_crumbled == -1)
925 default_action_crumbled = default_crumbled;
928 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
930 /* use action graphic as the default direction graphic, if undefined */
931 int default_action_direction_graphic = element_info[i].graphic[act];
932 int default_action_direction_crumbled = element_info[i].crumbled[act];
934 /* no graphic for current action -- use default direction graphic */
935 if (default_action_direction_graphic == -1)
936 default_action_direction_graphic =
937 (act_remove ? default_remove_graphic :
939 element_info[i].direction_graphic[ACTION_TURNING][dir] :
940 default_action_graphic != default_graphic ?
941 default_action_graphic :
942 default_direction_graphic[dir]);
944 if (element_info[i].direction_graphic[act][dir] == -1)
945 element_info[i].direction_graphic[act][dir] =
946 default_action_direction_graphic;
949 if (default_action_direction_crumbled == -1)
950 default_action_direction_crumbled =
951 element_info[i].direction_graphic[act][dir];
953 if (default_action_direction_crumbled == -1)
954 default_action_direction_crumbled =
955 (act_remove ? default_remove_graphic :
957 element_info[i].direction_crumbled[ACTION_TURNING][dir] :
958 default_action_crumbled != default_crumbled ?
959 default_action_crumbled :
960 default_direction_crumbled[dir]);
963 if (element_info[i].direction_crumbled[act][dir] == -1)
964 element_info[i].direction_crumbled[act][dir] =
965 default_action_direction_crumbled;
968 /* no graphic for this specific action -- use default action graphic */
969 if (element_info[i].graphic[act] == -1)
970 element_info[i].graphic[act] =
971 (act_remove ? default_remove_graphic :
972 act_turning ? element_info[i].graphic[ACTION_TURNING] :
973 default_action_graphic);
975 if (element_info[i].crumbled[act] == -1)
976 element_info[i].crumbled[act] = element_info[i].graphic[act];
978 if (element_info[i].crumbled[act] == -1)
979 element_info[i].crumbled[act] =
980 (act_remove ? default_remove_graphic :
981 act_turning ? element_info[i].crumbled[ACTION_TURNING] :
982 default_action_crumbled);
990 /* !!! THIS ALSO CLEARS SPECIAL FLAGS (AND IS NOT NEEDED ANYWAY) !!! */
991 /* set animation mode to "none" for each graphic with only 1 frame */
992 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
994 for (act = 0; act < NUM_ACTIONS; act++)
996 int graphic = element_info[i].graphic[act];
997 int crumbled = element_info[i].crumbled[act];
999 if (graphic_info[graphic].anim_frames == 1)
1000 graphic_info[graphic].anim_mode = ANIM_NONE;
1001 if (graphic_info[crumbled].anim_frames == 1)
1002 graphic_info[crumbled].anim_mode = ANIM_NONE;
1004 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1006 graphic = element_info[i].direction_graphic[act][dir];
1007 crumbled = element_info[i].direction_crumbled[act][dir];
1009 if (graphic_info[graphic].anim_frames == 1)
1010 graphic_info[graphic].anim_mode = ANIM_NONE;
1011 if (graphic_info[crumbled].anim_frames == 1)
1012 graphic_info[crumbled].anim_mode = ANIM_NONE;
1020 if (options.verbose)
1022 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1023 if (element_info[i].graphic[ACTION_DEFAULT] == IMG_UNKNOWN &&
1025 Error(ERR_INFO, "warning: no graphic for element '%s' (%d)",
1026 element_info[i].token_name, i);
1032 void InitElementSpecialGraphicInfo()
1034 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
1035 int num_property_mappings = getImageListPropertyMappingSize();
1038 /* always start with reliable default values */
1039 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1040 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1041 element_info[i].special_graphic[j] =
1042 element_info[i].graphic[ACTION_DEFAULT];
1044 /* initialize special element/graphic mapping from static configuration */
1045 for (i = 0; element_to_special_graphic[i].element > -1; i++)
1047 int element = element_to_special_graphic[i].element;
1048 int special = element_to_special_graphic[i].special;
1049 int graphic = element_to_special_graphic[i].graphic;
1050 int base_graphic = el2baseimg(element);
1051 boolean base_redefined =
1052 getImageListEntryFromImageID(base_graphic)->redefined;
1053 boolean special_redefined =
1054 getImageListEntryFromImageID(graphic)->redefined;
1057 if ((element == EL_EM_DYNAMITE ||
1058 element == EL_EM_DYNAMITE_ACTIVE) &&
1059 (special == GFX_SPECIAL_ARG_EDITOR ||
1060 special == GFX_SPECIAL_ARG_PANEL))
1061 printf("::: SPECIAL STATIC: %d, %d -> %d\n",
1062 element, special, graphic);
1065 /* if the base graphic ("emerald", for example) has been redefined,
1066 but not the special graphic ("emerald.EDITOR", for example), do not
1067 use an existing (in this case considered obsolete) special graphic
1068 anymore, but use the automatically created (down-scaled) graphic */
1069 if (base_redefined && !special_redefined)
1072 element_info[element].special_graphic[special] = graphic;
1075 /* initialize special element/graphic mapping from dynamic configuration */
1076 for (i = 0; i < num_property_mappings; i++)
1078 int element = property_mapping[i].base_index;
1079 int action = property_mapping[i].ext1_index;
1080 int direction = property_mapping[i].ext2_index;
1081 int special = property_mapping[i].ext3_index;
1082 int graphic = property_mapping[i].artwork_index;
1085 if ((element == EL_EM_DYNAMITE ||
1086 element == EL_EM_DYNAMITE_ACTIVE ||
1087 element == EL_CONVEYOR_BELT_1_MIDDLE ||
1088 element == EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE) &&
1089 (special == GFX_SPECIAL_ARG_EDITOR ||
1090 special == GFX_SPECIAL_ARG_PANEL))
1091 printf("::: SPECIAL DYNAMIC: %d, %d -> %d [%d]\n",
1092 element, special, graphic, property_mapping[i].ext1_index);
1096 if (element == EL_CONVEYOR_BELT_1_MIDDLE &&
1097 action == ACTION_ACTIVE)
1099 element = EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE;
1105 if (element == EL_MAGIC_WALL &&
1106 action == ACTION_ACTIVE)
1108 element = EL_MAGIC_WALL_ACTIVE;
1114 /* for action ".active", replace element with active element, if exists */
1115 if (action == ACTION_ACTIVE && element != ELEMENT_ACTIVE(element))
1117 element = ELEMENT_ACTIVE(element);
1122 if (element >= MAX_NUM_ELEMENTS)
1125 /* do not change special graphic if action or direction was specified */
1126 if (action != -1 || direction != -1)
1129 if (IS_SPECIAL_GFX_ARG(special))
1130 element_info[element].special_graphic[special] = graphic;
1133 /* now set all undefined/invalid graphics to default */
1134 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1135 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1136 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
1137 element_info[i].special_graphic[j] =
1138 element_info[i].graphic[ACTION_DEFAULT];
1141 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
1143 if (type != TYPE_ELEMENT && type != TYPE_GRAPHIC)
1144 return get_parameter_value(value_raw, suffix, type);
1146 if (strEqual(value_raw, ARG_UNDEFINED))
1147 return ARG_UNDEFINED_VALUE;
1150 if (type == TYPE_ELEMENT)
1152 char *value = getHashEntry(element_token_hash, value_raw);
1154 return (value != NULL ? atoi(value) : EL_UNDEFINED);
1156 else if (type == TYPE_GRAPHIC)
1158 char *value = getHashEntry(graphic_token_hash, value_raw);
1160 return (value != NULL ? atoi(value) : IMG_UNDEFINED);
1168 /* !!! THIS IS BUGGY !!! NOT SURE IF YOU GET ELEMENT ID OR GRAPHIC ID !!! */
1169 /* !!! (possible reason why ".clone_from" with elements doesn't work) !!! */
1171 /* !!! OPTIMIZE THIS BY USING HASH !!! */
1172 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1173 if (strEqual(element_info[i].token_name, value_raw))
1176 /* !!! OPTIMIZE THIS BY USING HASH !!! */
1177 for (i = 0; image_config[i].token != NULL; i++)
1179 int len_config_value = strlen(image_config[i].value);
1181 if (!strEqual(&image_config[i].value[len_config_value - 4], ".pcx") &&
1182 !strEqual(&image_config[i].value[len_config_value - 4], ".wav") &&
1183 !strEqual(image_config[i].value, UNDEFINED_FILENAME))
1186 if (strEqual(image_config[i].token, value_raw))
1196 static int get_scaled_graphic_width(int graphic)
1198 int original_width = getOriginalImageWidthFromImageID(graphic);
1199 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1201 return original_width * scale_up_factor;
1204 static int get_scaled_graphic_height(int graphic)
1206 int original_height = getOriginalImageHeightFromImageID(graphic);
1207 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1209 return original_height * scale_up_factor;
1212 static void set_graphic_parameters_ext(int graphic, struct GraphicInfo *g,
1213 int *parameter, Bitmap *src_bitmap)
1215 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1216 int anim_frames_per_line = 1;
1218 /* always start with reliable default values */
1219 g->src_image_width = 0;
1220 g->src_image_height = 0;
1223 g->width = TILEX; /* default for element graphics */
1224 g->height = TILEY; /* default for element graphics */
1225 g->offset_x = 0; /* one or both of these values ... */
1226 g->offset_y = 0; /* ... will be corrected later */
1227 g->offset2_x = 0; /* one or both of these values ... */
1228 g->offset2_y = 0; /* ... will be corrected later */
1229 g->swap_double_tiles = -1; /* auto-detect tile swapping */
1230 g->crumbled_like = -1; /* do not use clone element */
1231 g->diggable_like = -1; /* do not use clone element */
1232 g->border_size = TILEX / 8; /* "CRUMBLED" border size */
1233 g->scale_up_factor = 1; /* default: no scaling up */
1234 g->clone_from = -1; /* do not use clone graphic */
1235 g->anim_delay_fixed = 0;
1236 g->anim_delay_random = 0;
1237 g->post_delay_fixed = 0;
1238 g->post_delay_random = 0;
1239 g->fade_mode = FADE_MODE_DEFAULT;
1243 g->align = ALIGN_CENTER; /* default for title screens */
1244 g->valign = VALIGN_MIDDLE; /* default for title screens */
1245 g->sort_priority = 0; /* default for title screens */
1247 g->bitmap = src_bitmap;
1250 /* optional zoom factor for scaling up the image to a larger size */
1251 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1252 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1253 if (g->scale_up_factor < 1)
1254 g->scale_up_factor = 1; /* no scaling */
1258 if (g->use_image_size)
1260 /* set new default bitmap size (with scaling, but without small images) */
1261 g->width = get_scaled_graphic_width(graphic);
1262 g->height = get_scaled_graphic_height(graphic);
1266 /* optional x and y tile position of animation frame sequence */
1267 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1268 g->src_x = parameter[GFX_ARG_XPOS] * TILEX;
1269 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1270 g->src_y = parameter[GFX_ARG_YPOS] * TILEY;
1272 /* optional x and y pixel position of animation frame sequence */
1273 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1274 g->src_x = parameter[GFX_ARG_X];
1275 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1276 g->src_y = parameter[GFX_ARG_Y];
1278 /* optional width and height of each animation frame */
1279 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1280 g->width = parameter[GFX_ARG_WIDTH];
1281 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1282 g->height = parameter[GFX_ARG_HEIGHT];
1285 /* optional zoom factor for scaling up the image to a larger size */
1286 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1287 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1288 if (g->scale_up_factor < 1)
1289 g->scale_up_factor = 1; /* no scaling */
1294 /* get final bitmap size (with scaling, but without small images) */
1295 int src_image_width = get_scaled_graphic_width(graphic);
1296 int src_image_height = get_scaled_graphic_height(graphic);
1298 anim_frames_per_row = src_image_width / g->width;
1299 anim_frames_per_col = src_image_height / g->height;
1301 g->src_image_width = src_image_width;
1302 g->src_image_height = src_image_height;
1305 /* correct x or y offset dependent of vertical or horizontal frame order */
1306 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1308 g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1309 parameter[GFX_ARG_OFFSET] : g->height);
1310 anim_frames_per_line = anim_frames_per_col;
1312 else /* frames are ordered horizontally */
1314 g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1315 parameter[GFX_ARG_OFFSET] : g->width);
1316 anim_frames_per_line = anim_frames_per_row;
1319 /* optionally, the x and y offset of frames can be specified directly */
1320 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1321 g->offset_x = parameter[GFX_ARG_XOFFSET];
1322 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1323 g->offset_y = parameter[GFX_ARG_YOFFSET];
1325 /* optionally, moving animations may have separate start and end graphics */
1326 g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1328 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1329 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1331 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1332 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1333 g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1334 parameter[GFX_ARG_2ND_OFFSET] : g->height);
1335 else /* frames are ordered horizontally */
1336 g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1337 parameter[GFX_ARG_2ND_OFFSET] : g->width);
1339 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1340 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1341 g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1342 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1343 g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1345 /* optionally, the second movement tile can be specified as start tile */
1346 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1347 g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1349 /* automatically determine correct number of frames, if not defined */
1350 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1351 g->anim_frames = parameter[GFX_ARG_FRAMES];
1352 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1353 g->anim_frames = anim_frames_per_row;
1354 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1355 g->anim_frames = anim_frames_per_col;
1359 if (g->anim_frames == 0) /* frames must be at least 1 */
1362 g->anim_frames_per_line =
1363 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1364 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1366 g->anim_delay = parameter[GFX_ARG_DELAY];
1367 if (g->anim_delay == 0) /* delay must be at least 1 */
1370 g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1372 if (g->anim_frames == 1)
1373 g->anim_mode = ANIM_NONE;
1376 /* automatically determine correct start frame, if not defined */
1377 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1378 g->anim_start_frame = 0;
1379 else if (g->anim_mode & ANIM_REVERSE)
1380 g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1382 g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1384 /* animation synchronized with global frame counter, not move position */
1385 g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1387 /* optional element for cloning crumble graphics */
1388 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1389 g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1391 /* optional element for cloning digging graphics */
1392 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1393 g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1395 /* optional border size for "crumbling" diggable graphics */
1396 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1397 g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1399 /* this is only used for player "boring" and "sleeping" actions */
1400 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1401 g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1402 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1403 g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1404 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1405 g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1406 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1407 g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1409 /* this is only used for toon animations */
1410 g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1411 g->step_delay = parameter[GFX_ARG_STEP_DELAY];
1413 /* this is only used for drawing font characters */
1414 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1415 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1417 /* this is only used for drawing envelope graphics */
1418 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1420 /* optional graphic for cloning all graphics settings */
1421 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1422 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1424 /* optional settings for drawing title screens and title messages */
1425 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1426 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1427 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1428 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1429 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1430 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1431 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1432 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1433 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1434 g->align = parameter[GFX_ARG_ALIGN];
1435 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1436 g->valign = parameter[GFX_ARG_VALIGN];
1437 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1438 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1441 static void set_graphic_parameters(int graphic)
1444 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1445 char **parameter_raw = image->parameter;
1446 Bitmap *src_bitmap = getBitmapFromImageID(graphic);
1447 int parameter[NUM_GFX_ARGS];
1450 /* if fallback to default artwork is done, also use the default parameters */
1451 if (image->fallback_to_default)
1452 parameter_raw = image->default_parameter;
1454 /* get integer values from string parameters */
1455 for (i = 0; i < NUM_GFX_ARGS; i++)
1456 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1457 image_config_suffix[i].token,
1458 image_config_suffix[i].type);
1460 set_graphic_parameters_ext(graphic, &graphic_info[graphic],
1461 parameter, src_bitmap);
1465 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1466 char **parameter_raw = image->parameter;
1467 Bitmap *src_bitmap = getBitmapFromImageID(graphic);
1468 int parameter[NUM_GFX_ARGS];
1469 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1470 int anim_frames_per_line = 1;
1473 /* if fallback to default artwork is done, also use the default parameters */
1474 if (image->fallback_to_default)
1475 parameter_raw = image->default_parameter;
1477 /* get integer values from string parameters */
1478 for (i = 0; i < NUM_GFX_ARGS; i++)
1479 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1480 image_config_suffix[i].token,
1481 image_config_suffix[i].type);
1483 graphic_info[graphic].bitmap = src_bitmap;
1485 /* always start with reliable default values */
1486 graphic_info[graphic].src_image_width = 0;
1487 graphic_info[graphic].src_image_height = 0;
1488 graphic_info[graphic].src_x = 0;
1489 graphic_info[graphic].src_y = 0;
1490 graphic_info[graphic].width = TILEX; /* default for element graphics */
1491 graphic_info[graphic].height = TILEY; /* default for element graphics */
1492 graphic_info[graphic].offset_x = 0; /* one or both of these values ... */
1493 graphic_info[graphic].offset_y = 0; /* ... will be corrected later */
1494 graphic_info[graphic].offset2_x = 0; /* one or both of these values ... */
1495 graphic_info[graphic].offset2_y = 0; /* ... will be corrected later */
1496 graphic_info[graphic].swap_double_tiles = -1; /* auto-detect tile swapping */
1497 graphic_info[graphic].crumbled_like = -1; /* do not use clone element */
1498 graphic_info[graphic].diggable_like = -1; /* do not use clone element */
1499 graphic_info[graphic].border_size = TILEX / 8; /* "CRUMBLED" border size */
1500 graphic_info[graphic].scale_up_factor = 1; /* default: no scaling up */
1501 graphic_info[graphic].clone_from = -1; /* do not use clone graphic */
1502 graphic_info[graphic].anim_delay_fixed = 0;
1503 graphic_info[graphic].anim_delay_random = 0;
1504 graphic_info[graphic].post_delay_fixed = 0;
1505 graphic_info[graphic].post_delay_random = 0;
1506 graphic_info[graphic].fade_mode = FADE_MODE_DEFAULT;
1507 graphic_info[graphic].fade_delay = -1;
1508 graphic_info[graphic].post_delay = -1;
1509 graphic_info[graphic].auto_delay = -1;
1510 graphic_info[graphic].align = ALIGN_CENTER; /* default for title screens */
1511 graphic_info[graphic].valign = VALIGN_MIDDLE; /* default for title screens */
1512 graphic_info[graphic].sort_priority = 0; /* default for title screens */
1515 /* optional zoom factor for scaling up the image to a larger size */
1516 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1517 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1518 if (graphic_info[graphic].scale_up_factor < 1)
1519 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
1523 if (graphic_info[graphic].use_image_size)
1525 /* set new default bitmap size (with scaling, but without small images) */
1526 graphic_info[graphic].width = get_scaled_graphic_width(graphic);
1527 graphic_info[graphic].height = get_scaled_graphic_height(graphic);
1531 /* optional x and y tile position of animation frame sequence */
1532 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1533 graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
1534 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1535 graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
1537 /* optional x and y pixel position of animation frame sequence */
1538 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1539 graphic_info[graphic].src_x = parameter[GFX_ARG_X];
1540 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1541 graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
1543 /* optional width and height of each animation frame */
1544 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1545 graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
1546 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1547 graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
1550 /* optional zoom factor for scaling up the image to a larger size */
1551 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1552 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1553 if (graphic_info[graphic].scale_up_factor < 1)
1554 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
1559 /* get final bitmap size (with scaling, but without small images) */
1560 int src_image_width = get_scaled_graphic_width(graphic);
1561 int src_image_height = get_scaled_graphic_height(graphic);
1563 anim_frames_per_row = src_image_width / graphic_info[graphic].width;
1564 anim_frames_per_col = src_image_height / graphic_info[graphic].height;
1566 graphic_info[graphic].src_image_width = src_image_width;
1567 graphic_info[graphic].src_image_height = src_image_height;
1570 /* correct x or y offset dependent of vertical or horizontal frame order */
1571 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1573 graphic_info[graphic].offset_y =
1574 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1575 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
1576 anim_frames_per_line = anim_frames_per_col;
1578 else /* frames are ordered horizontally */
1580 graphic_info[graphic].offset_x =
1581 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1582 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
1583 anim_frames_per_line = anim_frames_per_row;
1586 /* optionally, the x and y offset of frames can be specified directly */
1587 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1588 graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
1589 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1590 graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
1592 /* optionally, moving animations may have separate start and end graphics */
1593 graphic_info[graphic].double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1595 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1596 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1598 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1599 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1600 graphic_info[graphic].offset2_y =
1601 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1602 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].height);
1603 else /* frames are ordered horizontally */
1604 graphic_info[graphic].offset2_x =
1605 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1606 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].width);
1608 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1609 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1610 graphic_info[graphic].offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1611 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1612 graphic_info[graphic].offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1614 /* optionally, the second movement tile can be specified as start tile */
1615 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1616 graphic_info[graphic].swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1618 /* automatically determine correct number of frames, if not defined */
1619 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1620 graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
1621 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1622 graphic_info[graphic].anim_frames = anim_frames_per_row;
1623 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1624 graphic_info[graphic].anim_frames = anim_frames_per_col;
1626 graphic_info[graphic].anim_frames = 1;
1628 if (graphic_info[graphic].anim_frames == 0) /* frames must be at least 1 */
1629 graphic_info[graphic].anim_frames = 1;
1631 graphic_info[graphic].anim_frames_per_line =
1632 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1633 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1635 graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
1636 if (graphic_info[graphic].anim_delay == 0) /* delay must be at least 1 */
1637 graphic_info[graphic].anim_delay = 1;
1639 graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
1641 if (graphic_info[graphic].anim_frames == 1)
1642 graphic_info[graphic].anim_mode = ANIM_NONE;
1645 /* automatically determine correct start frame, if not defined */
1646 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1647 graphic_info[graphic].anim_start_frame = 0;
1648 else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
1649 graphic_info[graphic].anim_start_frame =
1650 graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1652 graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
1654 /* animation synchronized with global frame counter, not move position */
1655 graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1657 /* optional element for cloning crumble graphics */
1658 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1659 graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1661 /* optional element for cloning digging graphics */
1662 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1663 graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1665 /* optional border size for "crumbling" diggable graphics */
1666 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1667 graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
1669 /* this is only used for player "boring" and "sleeping" actions */
1670 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1671 graphic_info[graphic].anim_delay_fixed =
1672 parameter[GFX_ARG_ANIM_DELAY_FIXED];
1673 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1674 graphic_info[graphic].anim_delay_random =
1675 parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1676 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1677 graphic_info[graphic].post_delay_fixed =
1678 parameter[GFX_ARG_POST_DELAY_FIXED];
1679 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1680 graphic_info[graphic].post_delay_random =
1681 parameter[GFX_ARG_POST_DELAY_RANDOM];
1683 /* this is only used for toon animations */
1684 graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
1685 graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY];
1687 /* this is only used for drawing font characters */
1688 graphic_info[graphic].draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1689 graphic_info[graphic].draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1691 /* this is only used for drawing envelope graphics */
1692 graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1694 /* optional graphic for cloning all graphics settings */
1695 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1696 graphic_info[graphic].clone_from = parameter[GFX_ARG_CLONE_FROM];
1698 /* optional settings for drawing title screens and title messages */
1699 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1700 graphic_info[graphic].fade_mode = parameter[GFX_ARG_FADE_MODE];
1701 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1702 graphic_info[graphic].fade_delay = parameter[GFX_ARG_FADE_DELAY];
1703 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1704 graphic_info[graphic].post_delay = parameter[GFX_ARG_POST_DELAY];
1705 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1706 graphic_info[graphic].auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1707 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1708 graphic_info[graphic].align = parameter[GFX_ARG_ALIGN];
1709 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1710 graphic_info[graphic].valign = parameter[GFX_ARG_VALIGN];
1711 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1712 graphic_info[graphic].sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1715 UPDATE_BUSY_STATE();
1718 static void set_cloned_graphic_parameters(int graphic)
1720 int fallback_graphic = IMG_CHAR_EXCLAM;
1721 int max_num_images = getImageListSize();
1722 int clone_graphic = graphic_info[graphic].clone_from;
1723 int num_references_followed = 1;
1725 while (graphic_info[clone_graphic].clone_from != -1 &&
1726 num_references_followed < max_num_images)
1728 clone_graphic = graphic_info[clone_graphic].clone_from;
1730 num_references_followed++;
1733 if (num_references_followed >= max_num_images)
1735 Error(ERR_INFO_LINE, "-");
1736 Error(ERR_INFO, "warning: error found in config file:");
1737 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1738 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1739 Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1740 Error(ERR_INFO, "custom graphic rejected for this element/action");
1742 if (graphic == fallback_graphic)
1743 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1745 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1746 Error(ERR_INFO_LINE, "-");
1748 graphic_info[graphic] = graphic_info[fallback_graphic];
1752 graphic_info[graphic] = graphic_info[clone_graphic];
1753 graphic_info[graphic].clone_from = clone_graphic;
1757 static void InitGraphicInfo()
1759 int fallback_graphic = IMG_CHAR_EXCLAM;
1760 int num_images = getImageListSize();
1763 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1764 static boolean clipmasks_initialized = FALSE;
1766 XGCValues clip_gc_values;
1767 unsigned long clip_gc_valuemask;
1768 GC copy_clipmask_gc = None;
1771 /* use image size as default values for width and height for these images */
1772 static int full_size_graphics[] =
1777 IMG_BACKGROUND_ENVELOPE_1,
1778 IMG_BACKGROUND_ENVELOPE_2,
1779 IMG_BACKGROUND_ENVELOPE_3,
1780 IMG_BACKGROUND_ENVELOPE_4,
1783 IMG_BACKGROUND_TITLE_INITIAL,
1784 IMG_BACKGROUND_TITLE,
1785 IMG_BACKGROUND_MAIN,
1786 IMG_BACKGROUND_LEVELS,
1787 IMG_BACKGROUND_SCORES,
1788 IMG_BACKGROUND_EDITOR,
1789 IMG_BACKGROUND_INFO,
1790 IMG_BACKGROUND_INFO_ELEMENTS,
1791 IMG_BACKGROUND_INFO_MUSIC,
1792 IMG_BACKGROUND_INFO_CREDITS,
1793 IMG_BACKGROUND_INFO_PROGRAM,
1794 IMG_BACKGROUND_INFO_LEVELSET,
1795 IMG_BACKGROUND_SETUP,
1796 IMG_BACKGROUND_DOOR,
1798 IMG_TITLESCREEN_INITIAL_1,
1799 IMG_TITLESCREEN_INITIAL_2,
1800 IMG_TITLESCREEN_INITIAL_3,
1801 IMG_TITLESCREEN_INITIAL_4,
1802 IMG_TITLESCREEN_INITIAL_5,
1812 checked_free(graphic_info);
1814 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1817 /* initialize "use_image_size" flag with default value */
1818 for (i = 0; i < num_images; i++)
1819 graphic_info[i].use_image_size = FALSE;
1821 /* initialize "use_image_size" flag from static configuration above */
1822 for (i = 0; full_size_graphics[i] != -1; i++)
1823 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1826 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1827 if (clipmasks_initialized)
1829 for (i = 0; i < num_images; i++)
1831 if (graphic_info[i].clip_mask)
1832 XFreePixmap(display, graphic_info[i].clip_mask);
1833 if (graphic_info[i].clip_gc)
1834 XFreeGC(display, graphic_info[i].clip_gc);
1836 graphic_info[i].clip_mask = None;
1837 graphic_info[i].clip_gc = None;
1842 /* first set all graphic paramaters ... */
1843 for (i = 0; i < num_images; i++)
1844 set_graphic_parameters(i);
1846 /* ... then copy these parameters for cloned graphics */
1847 for (i = 0; i < num_images; i++)
1848 if (graphic_info[i].clone_from != -1)
1849 set_cloned_graphic_parameters(i);
1851 for (i = 0; i < num_images; i++)
1856 int first_frame, last_frame;
1857 int src_bitmap_width, src_bitmap_height;
1859 /* now check if no animation frames are outside of the loaded image */
1861 if (graphic_info[i].bitmap == NULL)
1862 continue; /* skip check for optional images that are undefined */
1864 /* get image size (this can differ from the standard element tile size!) */
1865 width = graphic_info[i].width;
1866 height = graphic_info[i].height;
1868 /* get final bitmap size (with scaling, but without small images) */
1869 src_bitmap_width = graphic_info[i].src_image_width;
1870 src_bitmap_height = graphic_info[i].src_image_height;
1872 /* check if first animation frame is inside specified bitmap */
1875 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1878 /* this avoids calculating wrong start position for out-of-bounds frame */
1879 src_x = graphic_info[i].src_x;
1880 src_y = graphic_info[i].src_y;
1883 if (src_x < 0 || src_y < 0 ||
1884 src_x + width > src_bitmap_width ||
1885 src_y + height > src_bitmap_height)
1887 Error(ERR_INFO_LINE, "-");
1888 Error(ERR_INFO, "warning: error found in config file:");
1889 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1890 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1891 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1893 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1894 src_x, src_y, src_bitmap_width, src_bitmap_height);
1895 Error(ERR_INFO, "custom graphic rejected for this element/action");
1897 if (i == fallback_graphic)
1898 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1900 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1901 Error(ERR_INFO_LINE, "-");
1903 graphic_info[i] = graphic_info[fallback_graphic];
1906 /* check if last animation frame is inside specified bitmap */
1908 last_frame = graphic_info[i].anim_frames - 1;
1909 getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1911 if (src_x < 0 || src_y < 0 ||
1912 src_x + width > src_bitmap_width ||
1913 src_y + height > src_bitmap_height)
1915 Error(ERR_INFO_LINE, "-");
1916 Error(ERR_INFO, "warning: error found in config file:");
1917 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1918 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1919 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1921 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1922 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1923 Error(ERR_INFO, "custom graphic rejected for this element/action");
1925 if (i == fallback_graphic)
1926 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1928 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1929 Error(ERR_INFO_LINE, "-");
1931 graphic_info[i] = graphic_info[fallback_graphic];
1934 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1935 /* currently we only need a tile clip mask from the first frame */
1936 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1938 if (copy_clipmask_gc == None)
1940 clip_gc_values.graphics_exposures = False;
1941 clip_gc_valuemask = GCGraphicsExposures;
1942 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
1943 clip_gc_valuemask, &clip_gc_values);
1946 graphic_info[i].clip_mask =
1947 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
1949 src_pixmap = src_bitmap->clip_mask;
1950 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
1951 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
1953 clip_gc_values.graphics_exposures = False;
1954 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
1955 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
1957 graphic_info[i].clip_gc =
1958 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
1962 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1963 if (copy_clipmask_gc)
1964 XFreeGC(display, copy_clipmask_gc);
1966 clipmasks_initialized = TRUE;
1970 static void InitElementSoundInfo()
1972 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1973 int num_property_mappings = getSoundListPropertyMappingSize();
1976 /* set values to -1 to identify later as "uninitialized" values */
1977 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1978 for (act = 0; act < NUM_ACTIONS; act++)
1979 element_info[i].sound[act] = -1;
1981 /* initialize element/sound mapping from static configuration */
1982 for (i = 0; element_to_sound[i].element > -1; i++)
1984 int element = element_to_sound[i].element;
1985 int action = element_to_sound[i].action;
1986 int sound = element_to_sound[i].sound;
1987 boolean is_class = element_to_sound[i].is_class;
1990 action = ACTION_DEFAULT;
1993 element_info[element].sound[action] = sound;
1995 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1996 if (strEqual(element_info[j].class_name,
1997 element_info[element].class_name))
1998 element_info[j].sound[action] = sound;
2001 /* initialize element class/sound mapping from dynamic configuration */
2002 for (i = 0; i < num_property_mappings; i++)
2004 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
2005 int action = property_mapping[i].ext1_index;
2006 int sound = property_mapping[i].artwork_index;
2008 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
2012 action = ACTION_DEFAULT;
2014 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2015 if (strEqual(element_info[j].class_name,
2016 element_info[element_class].class_name))
2017 element_info[j].sound[action] = sound;
2020 /* initialize element/sound mapping from dynamic configuration */
2021 for (i = 0; i < num_property_mappings; i++)
2023 int element = property_mapping[i].base_index;
2024 int action = property_mapping[i].ext1_index;
2025 int sound = property_mapping[i].artwork_index;
2027 if (element >= MAX_NUM_ELEMENTS)
2031 action = ACTION_DEFAULT;
2033 element_info[element].sound[action] = sound;
2036 /* now set all '-1' values to element specific default values */
2037 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2039 for (act = 0; act < NUM_ACTIONS; act++)
2041 /* generic default action sound (defined by "[default]" directive) */
2042 int default_action_sound = element_info[EL_DEFAULT].sound[act];
2044 /* look for special default action sound (classic game specific) */
2045 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
2046 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
2047 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
2048 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
2049 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
2050 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
2052 /* !!! there's no such thing as a "default action sound" !!! */
2054 /* look for element specific default sound (independent from action) */
2055 if (element_info[i].sound[ACTION_DEFAULT] != -1)
2056 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
2060 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
2061 /* !!! make this better !!! */
2062 if (i == EL_EMPTY_SPACE)
2063 default_action_sound = element_info[EL_DEFAULT].sound[act];
2066 /* no sound for this specific action -- use default action sound */
2067 if (element_info[i].sound[act] == -1)
2068 element_info[i].sound[act] = default_action_sound;
2072 /* copy sound settings to some elements that are only stored in level file
2073 in native R'n'D levels, but are used by game engine in native EM levels */
2074 for (i = 0; copy_properties[i][0] != -1; i++)
2075 for (j = 1; j <= 4; j++)
2076 for (act = 0; act < NUM_ACTIONS; act++)
2077 element_info[copy_properties[i][j]].sound[act] =
2078 element_info[copy_properties[i][0]].sound[act];
2081 static void InitGameModeSoundInfo()
2085 /* set values to -1 to identify later as "uninitialized" values */
2086 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2089 /* initialize gamemode/sound mapping from static configuration */
2090 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
2092 int gamemode = gamemode_to_sound[i].gamemode;
2093 int sound = gamemode_to_sound[i].sound;
2096 gamemode = GAME_MODE_DEFAULT;
2098 menu.sound[gamemode] = sound;
2101 /* now set all '-1' values to levelset specific default values */
2102 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2103 if (menu.sound[i] == -1)
2104 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
2107 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2108 if (menu.sound[i] != -1)
2109 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
2113 static void set_sound_parameters(int sound, char **parameter_raw)
2115 int parameter[NUM_SND_ARGS];
2118 /* get integer values from string parameters */
2119 for (i = 0; i < NUM_SND_ARGS; i++)
2121 get_parameter_value(parameter_raw[i],
2122 sound_config_suffix[i].token,
2123 sound_config_suffix[i].type);
2125 /* explicit loop mode setting in configuration overrides default value */
2126 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2127 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
2129 /* sound volume to change the original volume when loading the sound file */
2130 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
2132 /* sound priority to give certain sounds a higher or lower priority */
2133 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
2136 static void InitSoundInfo()
2138 int *sound_effect_properties;
2139 int num_sounds = getSoundListSize();
2142 checked_free(sound_info);
2144 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
2145 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
2147 /* initialize sound effect for all elements to "no sound" */
2148 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2149 for (j = 0; j < NUM_ACTIONS; j++)
2150 element_info[i].sound[j] = SND_UNDEFINED;
2152 for (i = 0; i < num_sounds; i++)
2154 struct FileInfo *sound = getSoundListEntry(i);
2155 int len_effect_text = strlen(sound->token);
2157 sound_effect_properties[i] = ACTION_OTHER;
2158 sound_info[i].loop = FALSE; /* default: play sound only once */
2161 printf("::: sound %d: '%s'\n", i, sound->token);
2164 /* determine all loop sounds and identify certain sound classes */
2166 for (j = 0; element_action_info[j].suffix; j++)
2168 int len_action_text = strlen(element_action_info[j].suffix);
2170 if (len_action_text < len_effect_text &&
2171 strEqual(&sound->token[len_effect_text - len_action_text],
2172 element_action_info[j].suffix))
2174 sound_effect_properties[i] = element_action_info[j].value;
2175 sound_info[i].loop = element_action_info[j].is_loop_sound;
2181 /* associate elements and some selected sound actions */
2183 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2185 if (element_info[j].class_name)
2187 int len_class_text = strlen(element_info[j].class_name);
2189 if (len_class_text + 1 < len_effect_text &&
2190 strncmp(sound->token,
2191 element_info[j].class_name, len_class_text) == 0 &&
2192 sound->token[len_class_text] == '.')
2194 int sound_action_value = sound_effect_properties[i];
2196 element_info[j].sound[sound_action_value] = i;
2201 set_sound_parameters(i, sound->parameter);
2204 free(sound_effect_properties);
2207 static void InitGameModeMusicInfo()
2209 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
2210 int num_property_mappings = getMusicListPropertyMappingSize();
2211 int default_levelset_music = -1;
2214 /* set values to -1 to identify later as "uninitialized" values */
2215 for (i = 0; i < MAX_LEVELS; i++)
2216 levelset.music[i] = -1;
2217 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2220 /* initialize gamemode/music mapping from static configuration */
2221 for (i = 0; gamemode_to_music[i].music > -1; i++)
2223 int gamemode = gamemode_to_music[i].gamemode;
2224 int music = gamemode_to_music[i].music;
2227 printf("::: gamemode == %d, music == %d\n", gamemode, music);
2231 gamemode = GAME_MODE_DEFAULT;
2233 menu.music[gamemode] = music;
2236 /* initialize gamemode/music mapping from dynamic configuration */
2237 for (i = 0; i < num_property_mappings; i++)
2239 int prefix = property_mapping[i].base_index;
2240 int gamemode = property_mapping[i].ext1_index;
2241 int level = property_mapping[i].ext2_index;
2242 int music = property_mapping[i].artwork_index;
2245 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
2246 prefix, gamemode, level, music);
2249 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
2253 gamemode = GAME_MODE_DEFAULT;
2255 /* level specific music only allowed for in-game music */
2256 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
2257 gamemode = GAME_MODE_PLAYING;
2262 default_levelset_music = music;
2265 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
2266 levelset.music[level] = music;
2267 if (gamemode != GAME_MODE_PLAYING)
2268 menu.music[gamemode] = music;
2271 /* now set all '-1' values to menu specific default values */
2272 /* (undefined values of "levelset.music[]" might stay at "-1" to
2273 allow dynamic selection of music files from music directory!) */
2274 for (i = 0; i < MAX_LEVELS; i++)
2275 if (levelset.music[i] == -1)
2276 levelset.music[i] = default_levelset_music;
2277 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2278 if (menu.music[i] == -1)
2279 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
2282 for (i = 0; i < MAX_LEVELS; i++)
2283 if (levelset.music[i] != -1)
2284 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
2285 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2286 if (menu.music[i] != -1)
2287 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
2291 static void set_music_parameters(int music, char **parameter_raw)
2293 int parameter[NUM_MUS_ARGS];
2296 /* get integer values from string parameters */
2297 for (i = 0; i < NUM_MUS_ARGS; i++)
2299 get_parameter_value(parameter_raw[i],
2300 music_config_suffix[i].token,
2301 music_config_suffix[i].type);
2303 /* explicit loop mode setting in configuration overrides default value */
2304 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2305 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
2308 static void InitMusicInfo()
2310 int num_music = getMusicListSize();
2313 checked_free(music_info);
2315 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
2317 for (i = 0; i < num_music; i++)
2319 struct FileInfo *music = getMusicListEntry(i);
2320 int len_music_text = strlen(music->token);
2322 music_info[i].loop = TRUE; /* default: play music in loop mode */
2324 /* determine all loop music */
2326 for (j = 0; music_prefix_info[j].prefix; j++)
2328 int len_prefix_text = strlen(music_prefix_info[j].prefix);
2330 if (len_prefix_text < len_music_text &&
2331 strncmp(music->token,
2332 music_prefix_info[j].prefix, len_prefix_text) == 0)
2334 music_info[i].loop = music_prefix_info[j].is_loop_music;
2340 set_music_parameters(i, music->parameter);
2344 static void ReinitializeGraphics()
2346 print_init_timestamp("INIT ReinitializeGraphics");
2348 InitGraphicInfo(); /* graphic properties mapping */
2349 print_init_timestamp("TIME InitGraphicInfo");
2350 InitElementGraphicInfo(); /* element game graphic mapping */
2351 print_init_timestamp("TIME InitElementGraphicInfo");
2352 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
2353 print_init_timestamp("TIME InitElementSpecialGraphicInfo");
2355 InitElementSmallImages(); /* scale elements to all needed sizes */
2356 print_init_timestamp("TIME InitElementSmallImages");
2357 InitScaledImages(); /* scale all other images, if needed */
2358 print_init_timestamp("TIME InitScaledImages");
2359 InitFontGraphicInfo(); /* initialize text drawing functions */
2360 print_init_timestamp("TIME InitFontGraphicInfo");
2362 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
2363 print_init_timestamp("TIME InitGraphicInfo_EM");
2365 SetMainBackgroundImage(IMG_BACKGROUND);
2366 print_init_timestamp("TIME SetMainBackgroundImage");
2367 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2368 print_init_timestamp("TIME SetDoorBackgroundImage");
2371 print_init_timestamp("TIME InitGadgets");
2373 print_init_timestamp("TIME InitToons");
2375 print_init_timestamp("DONE ReinitializeGraphics");
2378 static void ReinitializeSounds()
2380 InitSoundInfo(); /* sound properties mapping */
2381 InitElementSoundInfo(); /* element game sound mapping */
2382 InitGameModeSoundInfo(); /* game mode sound mapping */
2384 InitPlayLevelSound(); /* internal game sound settings */
2387 static void ReinitializeMusic()
2389 InitMusicInfo(); /* music properties mapping */
2390 InitGameModeMusicInfo(); /* game mode music mapping */
2393 static int get_special_property_bit(int element, int property_bit_nr)
2395 struct PropertyBitInfo
2401 static struct PropertyBitInfo pb_can_move_into_acid[] =
2403 /* the player may be able fall into acid when gravity is activated */
2408 { EL_SP_MURPHY, 0 },
2409 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2411 /* all elements that can move may be able to also move into acid */
2414 { EL_BUG_RIGHT, 1 },
2417 { EL_SPACESHIP, 2 },
2418 { EL_SPACESHIP_LEFT, 2 },
2419 { EL_SPACESHIP_RIGHT, 2 },
2420 { EL_SPACESHIP_UP, 2 },
2421 { EL_SPACESHIP_DOWN, 2 },
2422 { EL_BD_BUTTERFLY, 3 },
2423 { EL_BD_BUTTERFLY_LEFT, 3 },
2424 { EL_BD_BUTTERFLY_RIGHT, 3 },
2425 { EL_BD_BUTTERFLY_UP, 3 },
2426 { EL_BD_BUTTERFLY_DOWN, 3 },
2427 { EL_BD_FIREFLY, 4 },
2428 { EL_BD_FIREFLY_LEFT, 4 },
2429 { EL_BD_FIREFLY_RIGHT, 4 },
2430 { EL_BD_FIREFLY_UP, 4 },
2431 { EL_BD_FIREFLY_DOWN, 4 },
2433 { EL_YAMYAM_LEFT, 5 },
2434 { EL_YAMYAM_RIGHT, 5 },
2435 { EL_YAMYAM_UP, 5 },
2436 { EL_YAMYAM_DOWN, 5 },
2437 { EL_DARK_YAMYAM, 6 },
2440 { EL_PACMAN_LEFT, 8 },
2441 { EL_PACMAN_RIGHT, 8 },
2442 { EL_PACMAN_UP, 8 },
2443 { EL_PACMAN_DOWN, 8 },
2445 { EL_MOLE_LEFT, 9 },
2446 { EL_MOLE_RIGHT, 9 },
2448 { EL_MOLE_DOWN, 9 },
2452 { EL_SATELLITE, 13 },
2453 { EL_SP_SNIKSNAK, 14 },
2454 { EL_SP_ELECTRON, 15 },
2457 { EL_EMC_ANDROID, 18 },
2462 static struct PropertyBitInfo pb_dont_collide_with[] =
2464 { EL_SP_SNIKSNAK, 0 },
2465 { EL_SP_ELECTRON, 1 },
2473 struct PropertyBitInfo *pb_info;
2476 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2477 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2482 struct PropertyBitInfo *pb_info = NULL;
2485 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2486 if (pb_definition[i].bit_nr == property_bit_nr)
2487 pb_info = pb_definition[i].pb_info;
2489 if (pb_info == NULL)
2492 for (i = 0; pb_info[i].element != -1; i++)
2493 if (pb_info[i].element == element)
2494 return pb_info[i].bit_nr;
2499 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2500 boolean property_value)
2502 int bit_nr = get_special_property_bit(element, property_bit_nr);
2507 *bitfield |= (1 << bit_nr);
2509 *bitfield &= ~(1 << bit_nr);
2513 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2515 int bit_nr = get_special_property_bit(element, property_bit_nr);
2518 return ((*bitfield & (1 << bit_nr)) != 0);
2523 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2525 static int group_nr;
2526 static struct ElementGroupInfo *group;
2527 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2530 if (actual_group == NULL) /* not yet initialized */
2533 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
2535 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2536 group_element - EL_GROUP_START + 1);
2538 /* replace element which caused too deep recursion by question mark */
2539 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2544 if (recursion_depth == 0) /* initialization */
2546 group = actual_group;
2547 group_nr = GROUP_NR(group_element);
2549 group->num_elements_resolved = 0;
2550 group->choice_pos = 0;
2552 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2553 element_info[i].in_group[group_nr] = FALSE;
2556 for (i = 0; i < actual_group->num_elements; i++)
2558 int element = actual_group->element[i];
2560 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2563 if (IS_GROUP_ELEMENT(element))
2564 ResolveGroupElementExt(element, recursion_depth + 1);
2567 group->element_resolved[group->num_elements_resolved++] = element;
2568 element_info[element].in_group[group_nr] = TRUE;
2573 void ResolveGroupElement(int group_element)
2575 ResolveGroupElementExt(group_element, 0);
2578 void InitElementPropertiesStatic()
2580 static int ep_diggable[] =
2585 EL_SP_BUGGY_BASE_ACTIVATING,
2588 EL_INVISIBLE_SAND_ACTIVE,
2591 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2592 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2597 EL_SP_BUGGY_BASE_ACTIVE,
2604 static int ep_collectible_only[] =
2626 EL_DYNABOMB_INCREASE_NUMBER,
2627 EL_DYNABOMB_INCREASE_SIZE,
2628 EL_DYNABOMB_INCREASE_POWER,
2646 /* !!! handle separately !!! */
2647 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2653 static int ep_dont_run_into[] =
2655 /* same elements as in 'ep_dont_touch' */
2661 /* same elements as in 'ep_dont_collide_with' */
2673 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2678 EL_SP_BUGGY_BASE_ACTIVE,
2685 static int ep_dont_collide_with[] =
2687 /* same elements as in 'ep_dont_touch' */
2704 static int ep_dont_touch[] =
2714 static int ep_indestructible[] =
2718 EL_ACID_POOL_TOPLEFT,
2719 EL_ACID_POOL_TOPRIGHT,
2720 EL_ACID_POOL_BOTTOMLEFT,
2721 EL_ACID_POOL_BOTTOM,
2722 EL_ACID_POOL_BOTTOMRIGHT,
2723 EL_SP_HARDWARE_GRAY,
2724 EL_SP_HARDWARE_GREEN,
2725 EL_SP_HARDWARE_BLUE,
2727 EL_SP_HARDWARE_YELLOW,
2728 EL_SP_HARDWARE_BASE_1,
2729 EL_SP_HARDWARE_BASE_2,
2730 EL_SP_HARDWARE_BASE_3,
2731 EL_SP_HARDWARE_BASE_4,
2732 EL_SP_HARDWARE_BASE_5,
2733 EL_SP_HARDWARE_BASE_6,
2734 EL_INVISIBLE_STEELWALL,
2735 EL_INVISIBLE_STEELWALL_ACTIVE,
2736 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2737 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2738 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2739 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2740 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2741 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2742 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2743 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2744 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2745 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2746 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2747 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2749 EL_LIGHT_SWITCH_ACTIVE,
2750 EL_SIGN_EXCLAMATION,
2751 EL_SIGN_RADIOACTIVITY,
2758 EL_SIGN_ENTRY_FORBIDDEN,
2759 EL_SIGN_EMERGENCY_EXIT,
2767 EL_STEEL_EXIT_CLOSED,
2769 EL_EM_STEEL_EXIT_CLOSED,
2770 EL_EM_STEEL_EXIT_OPEN,
2771 EL_DC_STEELWALL_1_LEFT,
2772 EL_DC_STEELWALL_1_RIGHT,
2773 EL_DC_STEELWALL_1_TOP,
2774 EL_DC_STEELWALL_1_BOTTOM,
2775 EL_DC_STEELWALL_1_HORIZONTAL,
2776 EL_DC_STEELWALL_1_VERTICAL,
2777 EL_DC_STEELWALL_1_TOPLEFT,
2778 EL_DC_STEELWALL_1_TOPRIGHT,
2779 EL_DC_STEELWALL_1_BOTTOMLEFT,
2780 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2781 EL_DC_STEELWALL_1_TOPLEFT_2,
2782 EL_DC_STEELWALL_1_TOPRIGHT_2,
2783 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2784 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2785 EL_DC_STEELWALL_2_LEFT,
2786 EL_DC_STEELWALL_2_RIGHT,
2787 EL_DC_STEELWALL_2_TOP,
2788 EL_DC_STEELWALL_2_BOTTOM,
2789 EL_DC_STEELWALL_2_HORIZONTAL,
2790 EL_DC_STEELWALL_2_VERTICAL,
2791 EL_DC_STEELWALL_2_MIDDLE,
2792 EL_DC_STEELWALL_2_SINGLE,
2793 EL_STEELWALL_SLIPPERY,
2807 EL_GATE_1_GRAY_ACTIVE,
2808 EL_GATE_2_GRAY_ACTIVE,
2809 EL_GATE_3_GRAY_ACTIVE,
2810 EL_GATE_4_GRAY_ACTIVE,
2819 EL_EM_GATE_1_GRAY_ACTIVE,
2820 EL_EM_GATE_2_GRAY_ACTIVE,
2821 EL_EM_GATE_3_GRAY_ACTIVE,
2822 EL_EM_GATE_4_GRAY_ACTIVE,
2831 EL_EMC_GATE_5_GRAY_ACTIVE,
2832 EL_EMC_GATE_6_GRAY_ACTIVE,
2833 EL_EMC_GATE_7_GRAY_ACTIVE,
2834 EL_EMC_GATE_8_GRAY_ACTIVE,
2836 EL_DC_GATE_WHITE_GRAY,
2837 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2838 EL_DC_GATE_FAKE_GRAY,
2840 EL_SWITCHGATE_OPENING,
2841 EL_SWITCHGATE_CLOSED,
2842 EL_SWITCHGATE_CLOSING,
2844 EL_DC_SWITCHGATE_SWITCH_UP,
2845 EL_DC_SWITCHGATE_SWITCH_DOWN,
2848 EL_TIMEGATE_OPENING,
2850 EL_TIMEGATE_CLOSING,
2852 EL_DC_TIMEGATE_SWITCH,
2853 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2858 EL_TUBE_VERTICAL_LEFT,
2859 EL_TUBE_VERTICAL_RIGHT,
2860 EL_TUBE_HORIZONTAL_UP,
2861 EL_TUBE_HORIZONTAL_DOWN,
2866 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2867 EL_EXPANDABLE_STEELWALL_VERTICAL,
2868 EL_EXPANDABLE_STEELWALL_ANY,
2873 static int ep_slippery[] =
2887 EL_ROBOT_WHEEL_ACTIVE,
2893 EL_ACID_POOL_TOPLEFT,
2894 EL_ACID_POOL_TOPRIGHT,
2904 EL_STEELWALL_SLIPPERY,
2907 EL_EMC_WALL_SLIPPERY_1,
2908 EL_EMC_WALL_SLIPPERY_2,
2909 EL_EMC_WALL_SLIPPERY_3,
2910 EL_EMC_WALL_SLIPPERY_4,
2912 EL_EMC_MAGIC_BALL_ACTIVE,
2917 static int ep_can_change[] =
2922 static int ep_can_move[] =
2924 /* same elements as in 'pb_can_move_into_acid' */
2947 static int ep_can_fall[] =
2961 EL_QUICKSAND_FAST_FULL,
2963 EL_BD_MAGIC_WALL_FULL,
2964 EL_DC_MAGIC_WALL_FULL,
2978 static int ep_can_smash_player[] =
3004 static int ep_can_smash_enemies[] =
3013 static int ep_can_smash_everything[] =
3022 static int ep_explodes_by_fire[] =
3024 /* same elements as in 'ep_explodes_impact' */
3029 /* same elements as in 'ep_explodes_smashed' */
3039 EL_EM_DYNAMITE_ACTIVE,
3040 EL_DYNABOMB_PLAYER_1_ACTIVE,
3041 EL_DYNABOMB_PLAYER_2_ACTIVE,
3042 EL_DYNABOMB_PLAYER_3_ACTIVE,
3043 EL_DYNABOMB_PLAYER_4_ACTIVE,
3044 EL_DYNABOMB_INCREASE_NUMBER,
3045 EL_DYNABOMB_INCREASE_SIZE,
3046 EL_DYNABOMB_INCREASE_POWER,
3047 EL_SP_DISK_RED_ACTIVE,
3061 static int ep_explodes_smashed[] =
3063 /* same elements as in 'ep_explodes_impact' */
3077 static int ep_explodes_impact[] =
3086 static int ep_walkable_over[] =
3090 EL_SOKOBAN_FIELD_EMPTY,
3096 EL_EM_STEEL_EXIT_OPEN,
3105 EL_GATE_1_GRAY_ACTIVE,
3106 EL_GATE_2_GRAY_ACTIVE,
3107 EL_GATE_3_GRAY_ACTIVE,
3108 EL_GATE_4_GRAY_ACTIVE,
3116 static int ep_walkable_inside[] =
3121 EL_TUBE_VERTICAL_LEFT,
3122 EL_TUBE_VERTICAL_RIGHT,
3123 EL_TUBE_HORIZONTAL_UP,
3124 EL_TUBE_HORIZONTAL_DOWN,
3133 static int ep_walkable_under[] =
3138 static int ep_passable_over[] =
3148 EL_EM_GATE_1_GRAY_ACTIVE,
3149 EL_EM_GATE_2_GRAY_ACTIVE,
3150 EL_EM_GATE_3_GRAY_ACTIVE,
3151 EL_EM_GATE_4_GRAY_ACTIVE,
3160 EL_EMC_GATE_5_GRAY_ACTIVE,
3161 EL_EMC_GATE_6_GRAY_ACTIVE,
3162 EL_EMC_GATE_7_GRAY_ACTIVE,
3163 EL_EMC_GATE_8_GRAY_ACTIVE,
3165 EL_DC_GATE_WHITE_GRAY,
3166 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3173 static int ep_passable_inside[] =
3179 EL_SP_PORT_HORIZONTAL,
3180 EL_SP_PORT_VERTICAL,
3182 EL_SP_GRAVITY_PORT_LEFT,
3183 EL_SP_GRAVITY_PORT_RIGHT,
3184 EL_SP_GRAVITY_PORT_UP,
3185 EL_SP_GRAVITY_PORT_DOWN,
3186 EL_SP_GRAVITY_ON_PORT_LEFT,
3187 EL_SP_GRAVITY_ON_PORT_RIGHT,
3188 EL_SP_GRAVITY_ON_PORT_UP,
3189 EL_SP_GRAVITY_ON_PORT_DOWN,
3190 EL_SP_GRAVITY_OFF_PORT_LEFT,
3191 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3192 EL_SP_GRAVITY_OFF_PORT_UP,
3193 EL_SP_GRAVITY_OFF_PORT_DOWN,
3198 static int ep_passable_under[] =
3203 static int ep_droppable[] =
3208 static int ep_explodes_1x1_old[] =
3213 static int ep_pushable[] =
3225 EL_SOKOBAN_FIELD_FULL,
3234 static int ep_explodes_cross_old[] =
3239 static int ep_protected[] =
3241 /* same elements as in 'ep_walkable_inside' */
3245 EL_TUBE_VERTICAL_LEFT,
3246 EL_TUBE_VERTICAL_RIGHT,
3247 EL_TUBE_HORIZONTAL_UP,
3248 EL_TUBE_HORIZONTAL_DOWN,
3254 /* same elements as in 'ep_passable_over' */
3263 EL_EM_GATE_1_GRAY_ACTIVE,
3264 EL_EM_GATE_2_GRAY_ACTIVE,
3265 EL_EM_GATE_3_GRAY_ACTIVE,
3266 EL_EM_GATE_4_GRAY_ACTIVE,
3275 EL_EMC_GATE_5_GRAY_ACTIVE,
3276 EL_EMC_GATE_6_GRAY_ACTIVE,
3277 EL_EMC_GATE_7_GRAY_ACTIVE,
3278 EL_EMC_GATE_8_GRAY_ACTIVE,
3280 EL_DC_GATE_WHITE_GRAY,
3281 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3285 /* same elements as in 'ep_passable_inside' */
3290 EL_SP_PORT_HORIZONTAL,
3291 EL_SP_PORT_VERTICAL,
3293 EL_SP_GRAVITY_PORT_LEFT,
3294 EL_SP_GRAVITY_PORT_RIGHT,
3295 EL_SP_GRAVITY_PORT_UP,
3296 EL_SP_GRAVITY_PORT_DOWN,
3297 EL_SP_GRAVITY_ON_PORT_LEFT,
3298 EL_SP_GRAVITY_ON_PORT_RIGHT,
3299 EL_SP_GRAVITY_ON_PORT_UP,
3300 EL_SP_GRAVITY_ON_PORT_DOWN,
3301 EL_SP_GRAVITY_OFF_PORT_LEFT,
3302 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3303 EL_SP_GRAVITY_OFF_PORT_UP,
3304 EL_SP_GRAVITY_OFF_PORT_DOWN,
3309 static int ep_throwable[] =
3314 static int ep_can_explode[] =
3316 /* same elements as in 'ep_explodes_impact' */
3321 /* same elements as in 'ep_explodes_smashed' */
3327 /* elements that can explode by explosion or by dragonfire */
3331 EL_EM_DYNAMITE_ACTIVE,
3332 EL_DYNABOMB_PLAYER_1_ACTIVE,
3333 EL_DYNABOMB_PLAYER_2_ACTIVE,
3334 EL_DYNABOMB_PLAYER_3_ACTIVE,
3335 EL_DYNABOMB_PLAYER_4_ACTIVE,
3336 EL_DYNABOMB_INCREASE_NUMBER,
3337 EL_DYNABOMB_INCREASE_SIZE,
3338 EL_DYNABOMB_INCREASE_POWER,
3339 EL_SP_DISK_RED_ACTIVE,
3347 /* elements that can explode only by explosion */
3353 static int ep_gravity_reachable[] =
3359 EL_INVISIBLE_SAND_ACTIVE,
3364 EL_SP_PORT_HORIZONTAL,
3365 EL_SP_PORT_VERTICAL,
3367 EL_SP_GRAVITY_PORT_LEFT,
3368 EL_SP_GRAVITY_PORT_RIGHT,
3369 EL_SP_GRAVITY_PORT_UP,
3370 EL_SP_GRAVITY_PORT_DOWN,
3371 EL_SP_GRAVITY_ON_PORT_LEFT,
3372 EL_SP_GRAVITY_ON_PORT_RIGHT,
3373 EL_SP_GRAVITY_ON_PORT_UP,
3374 EL_SP_GRAVITY_ON_PORT_DOWN,
3375 EL_SP_GRAVITY_OFF_PORT_LEFT,
3376 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3377 EL_SP_GRAVITY_OFF_PORT_UP,
3378 EL_SP_GRAVITY_OFF_PORT_DOWN,
3384 static int ep_player[] =
3391 EL_SOKOBAN_FIELD_PLAYER,
3397 static int ep_can_pass_magic_wall[] =
3411 static int ep_can_pass_dc_magic_wall[] =
3427 static int ep_switchable[] =
3431 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3432 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3433 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3434 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3435 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3436 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3437 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3438 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3439 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3440 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3441 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3442 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3443 EL_SWITCHGATE_SWITCH_UP,
3444 EL_SWITCHGATE_SWITCH_DOWN,
3445 EL_DC_SWITCHGATE_SWITCH_UP,
3446 EL_DC_SWITCHGATE_SWITCH_DOWN,
3448 EL_LIGHT_SWITCH_ACTIVE,
3450 EL_DC_TIMEGATE_SWITCH,
3451 EL_BALLOON_SWITCH_LEFT,
3452 EL_BALLOON_SWITCH_RIGHT,
3453 EL_BALLOON_SWITCH_UP,
3454 EL_BALLOON_SWITCH_DOWN,
3455 EL_BALLOON_SWITCH_ANY,
3456 EL_BALLOON_SWITCH_NONE,
3459 EL_EMC_MAGIC_BALL_SWITCH,
3460 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3465 static int ep_bd_element[] =
3499 static int ep_sp_element[] =
3501 /* should always be valid */
3504 /* standard classic Supaplex elements */
3511 EL_SP_HARDWARE_GRAY,
3519 EL_SP_GRAVITY_PORT_RIGHT,
3520 EL_SP_GRAVITY_PORT_DOWN,
3521 EL_SP_GRAVITY_PORT_LEFT,
3522 EL_SP_GRAVITY_PORT_UP,
3527 EL_SP_PORT_VERTICAL,
3528 EL_SP_PORT_HORIZONTAL,
3534 EL_SP_HARDWARE_BASE_1,
3535 EL_SP_HARDWARE_GREEN,
3536 EL_SP_HARDWARE_BLUE,
3538 EL_SP_HARDWARE_YELLOW,
3539 EL_SP_HARDWARE_BASE_2,
3540 EL_SP_HARDWARE_BASE_3,
3541 EL_SP_HARDWARE_BASE_4,
3542 EL_SP_HARDWARE_BASE_5,
3543 EL_SP_HARDWARE_BASE_6,
3547 /* additional elements that appeared in newer Supaplex levels */
3550 /* additional gravity port elements (not switching, but setting gravity) */
3551 EL_SP_GRAVITY_ON_PORT_LEFT,
3552 EL_SP_GRAVITY_ON_PORT_RIGHT,
3553 EL_SP_GRAVITY_ON_PORT_UP,
3554 EL_SP_GRAVITY_ON_PORT_DOWN,
3555 EL_SP_GRAVITY_OFF_PORT_LEFT,
3556 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3557 EL_SP_GRAVITY_OFF_PORT_UP,
3558 EL_SP_GRAVITY_OFF_PORT_DOWN,
3560 /* more than one Murphy in a level results in an inactive clone */
3563 /* runtime Supaplex elements */
3564 EL_SP_DISK_RED_ACTIVE,
3565 EL_SP_TERMINAL_ACTIVE,
3566 EL_SP_BUGGY_BASE_ACTIVATING,
3567 EL_SP_BUGGY_BASE_ACTIVE,
3574 static int ep_sb_element[] =
3579 EL_SOKOBAN_FIELD_EMPTY,
3580 EL_SOKOBAN_FIELD_FULL,
3581 EL_SOKOBAN_FIELD_PLAYER,
3586 EL_INVISIBLE_STEELWALL,
3591 static int ep_gem[] =
3603 static int ep_food_dark_yamyam[] =
3631 static int ep_food_penguin[] =
3645 static int ep_food_pig[] =
3657 static int ep_historic_wall[] =
3668 EL_GATE_1_GRAY_ACTIVE,
3669 EL_GATE_2_GRAY_ACTIVE,
3670 EL_GATE_3_GRAY_ACTIVE,
3671 EL_GATE_4_GRAY_ACTIVE,
3680 EL_EM_GATE_1_GRAY_ACTIVE,
3681 EL_EM_GATE_2_GRAY_ACTIVE,
3682 EL_EM_GATE_3_GRAY_ACTIVE,
3683 EL_EM_GATE_4_GRAY_ACTIVE,
3690 EL_EXPANDABLE_WALL_HORIZONTAL,
3691 EL_EXPANDABLE_WALL_VERTICAL,
3692 EL_EXPANDABLE_WALL_ANY,
3693 EL_EXPANDABLE_WALL_GROWING,
3694 EL_BD_EXPANDABLE_WALL,
3701 EL_SP_HARDWARE_GRAY,
3702 EL_SP_HARDWARE_GREEN,
3703 EL_SP_HARDWARE_BLUE,
3705 EL_SP_HARDWARE_YELLOW,
3706 EL_SP_HARDWARE_BASE_1,
3707 EL_SP_HARDWARE_BASE_2,
3708 EL_SP_HARDWARE_BASE_3,
3709 EL_SP_HARDWARE_BASE_4,
3710 EL_SP_HARDWARE_BASE_5,
3711 EL_SP_HARDWARE_BASE_6,
3713 EL_SP_TERMINAL_ACTIVE,
3716 EL_INVISIBLE_STEELWALL,
3717 EL_INVISIBLE_STEELWALL_ACTIVE,
3719 EL_INVISIBLE_WALL_ACTIVE,
3720 EL_STEELWALL_SLIPPERY,
3737 static int ep_historic_solid[] =
3741 EL_EXPANDABLE_WALL_HORIZONTAL,
3742 EL_EXPANDABLE_WALL_VERTICAL,
3743 EL_EXPANDABLE_WALL_ANY,
3744 EL_BD_EXPANDABLE_WALL,
3757 EL_QUICKSAND_FILLING,
3758 EL_QUICKSAND_EMPTYING,
3760 EL_MAGIC_WALL_ACTIVE,
3761 EL_MAGIC_WALL_EMPTYING,
3762 EL_MAGIC_WALL_FILLING,
3766 EL_BD_MAGIC_WALL_ACTIVE,
3767 EL_BD_MAGIC_WALL_EMPTYING,
3768 EL_BD_MAGIC_WALL_FULL,
3769 EL_BD_MAGIC_WALL_FILLING,
3770 EL_BD_MAGIC_WALL_DEAD,
3779 EL_SP_TERMINAL_ACTIVE,
3783 EL_INVISIBLE_WALL_ACTIVE,
3784 EL_SWITCHGATE_SWITCH_UP,
3785 EL_SWITCHGATE_SWITCH_DOWN,
3786 EL_DC_SWITCHGATE_SWITCH_UP,
3787 EL_DC_SWITCHGATE_SWITCH_DOWN,
3789 EL_TIMEGATE_SWITCH_ACTIVE,
3790 EL_DC_TIMEGATE_SWITCH,
3791 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3803 /* the following elements are a direct copy of "indestructible" elements,
3804 except "EL_ACID", which is "indestructible", but not "solid"! */
3809 EL_ACID_POOL_TOPLEFT,
3810 EL_ACID_POOL_TOPRIGHT,
3811 EL_ACID_POOL_BOTTOMLEFT,
3812 EL_ACID_POOL_BOTTOM,
3813 EL_ACID_POOL_BOTTOMRIGHT,
3814 EL_SP_HARDWARE_GRAY,
3815 EL_SP_HARDWARE_GREEN,
3816 EL_SP_HARDWARE_BLUE,
3818 EL_SP_HARDWARE_YELLOW,
3819 EL_SP_HARDWARE_BASE_1,
3820 EL_SP_HARDWARE_BASE_2,
3821 EL_SP_HARDWARE_BASE_3,
3822 EL_SP_HARDWARE_BASE_4,
3823 EL_SP_HARDWARE_BASE_5,
3824 EL_SP_HARDWARE_BASE_6,
3825 EL_INVISIBLE_STEELWALL,
3826 EL_INVISIBLE_STEELWALL_ACTIVE,
3827 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3828 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3829 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3830 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3831 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3832 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3833 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3834 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3835 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3836 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3837 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3838 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3840 EL_LIGHT_SWITCH_ACTIVE,
3841 EL_SIGN_EXCLAMATION,
3842 EL_SIGN_RADIOACTIVITY,
3849 EL_SIGN_ENTRY_FORBIDDEN,
3850 EL_SIGN_EMERGENCY_EXIT,
3858 EL_STEEL_EXIT_CLOSED,
3860 EL_DC_STEELWALL_1_LEFT,
3861 EL_DC_STEELWALL_1_RIGHT,
3862 EL_DC_STEELWALL_1_TOP,
3863 EL_DC_STEELWALL_1_BOTTOM,
3864 EL_DC_STEELWALL_1_HORIZONTAL,
3865 EL_DC_STEELWALL_1_VERTICAL,
3866 EL_DC_STEELWALL_1_TOPLEFT,
3867 EL_DC_STEELWALL_1_TOPRIGHT,
3868 EL_DC_STEELWALL_1_BOTTOMLEFT,
3869 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3870 EL_DC_STEELWALL_1_TOPLEFT_2,
3871 EL_DC_STEELWALL_1_TOPRIGHT_2,
3872 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3873 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3874 EL_DC_STEELWALL_2_LEFT,
3875 EL_DC_STEELWALL_2_RIGHT,
3876 EL_DC_STEELWALL_2_TOP,
3877 EL_DC_STEELWALL_2_BOTTOM,
3878 EL_DC_STEELWALL_2_HORIZONTAL,
3879 EL_DC_STEELWALL_2_VERTICAL,
3880 EL_DC_STEELWALL_2_MIDDLE,
3881 EL_DC_STEELWALL_2_SINGLE,
3882 EL_STEELWALL_SLIPPERY,
3896 EL_GATE_1_GRAY_ACTIVE,
3897 EL_GATE_2_GRAY_ACTIVE,
3898 EL_GATE_3_GRAY_ACTIVE,
3899 EL_GATE_4_GRAY_ACTIVE,
3908 EL_EM_GATE_1_GRAY_ACTIVE,
3909 EL_EM_GATE_2_GRAY_ACTIVE,
3910 EL_EM_GATE_3_GRAY_ACTIVE,
3911 EL_EM_GATE_4_GRAY_ACTIVE,
3913 EL_SWITCHGATE_OPENING,
3914 EL_SWITCHGATE_CLOSED,
3915 EL_SWITCHGATE_CLOSING,
3917 EL_TIMEGATE_OPENING,
3919 EL_TIMEGATE_CLOSING,
3923 EL_TUBE_VERTICAL_LEFT,
3924 EL_TUBE_VERTICAL_RIGHT,
3925 EL_TUBE_HORIZONTAL_UP,
3926 EL_TUBE_HORIZONTAL_DOWN,
3935 static int ep_classic_enemy[] =
3952 static int ep_belt[] =
3954 EL_CONVEYOR_BELT_1_LEFT,
3955 EL_CONVEYOR_BELT_1_MIDDLE,
3956 EL_CONVEYOR_BELT_1_RIGHT,
3957 EL_CONVEYOR_BELT_2_LEFT,
3958 EL_CONVEYOR_BELT_2_MIDDLE,
3959 EL_CONVEYOR_BELT_2_RIGHT,
3960 EL_CONVEYOR_BELT_3_LEFT,
3961 EL_CONVEYOR_BELT_3_MIDDLE,
3962 EL_CONVEYOR_BELT_3_RIGHT,
3963 EL_CONVEYOR_BELT_4_LEFT,
3964 EL_CONVEYOR_BELT_4_MIDDLE,
3965 EL_CONVEYOR_BELT_4_RIGHT,
3970 static int ep_belt_active[] =
3972 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3973 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3974 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3975 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3976 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3977 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3978 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3979 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3980 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3981 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3982 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3983 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3988 static int ep_belt_switch[] =
3990 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3991 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3992 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3993 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3994 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3995 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3996 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3997 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3998 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3999 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4000 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4001 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4006 static int ep_tube[] =
4013 EL_TUBE_HORIZONTAL_UP,
4014 EL_TUBE_HORIZONTAL_DOWN,
4016 EL_TUBE_VERTICAL_LEFT,
4017 EL_TUBE_VERTICAL_RIGHT,
4023 static int ep_acid_pool[] =
4025 EL_ACID_POOL_TOPLEFT,
4026 EL_ACID_POOL_TOPRIGHT,
4027 EL_ACID_POOL_BOTTOMLEFT,
4028 EL_ACID_POOL_BOTTOM,
4029 EL_ACID_POOL_BOTTOMRIGHT,
4034 static int ep_keygate[] =
4044 EL_GATE_1_GRAY_ACTIVE,
4045 EL_GATE_2_GRAY_ACTIVE,
4046 EL_GATE_3_GRAY_ACTIVE,
4047 EL_GATE_4_GRAY_ACTIVE,
4056 EL_EM_GATE_1_GRAY_ACTIVE,
4057 EL_EM_GATE_2_GRAY_ACTIVE,
4058 EL_EM_GATE_3_GRAY_ACTIVE,
4059 EL_EM_GATE_4_GRAY_ACTIVE,
4068 EL_EMC_GATE_5_GRAY_ACTIVE,
4069 EL_EMC_GATE_6_GRAY_ACTIVE,
4070 EL_EMC_GATE_7_GRAY_ACTIVE,
4071 EL_EMC_GATE_8_GRAY_ACTIVE,
4073 EL_DC_GATE_WHITE_GRAY,
4074 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4079 static int ep_amoeboid[] =
4091 static int ep_amoebalive[] =
4102 static int ep_has_editor_content[] =
4124 static int ep_can_turn_each_move[] =
4126 /* !!! do something with this one !!! */
4130 static int ep_can_grow[] =
4144 static int ep_active_bomb[] =
4147 EL_EM_DYNAMITE_ACTIVE,
4148 EL_DYNABOMB_PLAYER_1_ACTIVE,
4149 EL_DYNABOMB_PLAYER_2_ACTIVE,
4150 EL_DYNABOMB_PLAYER_3_ACTIVE,
4151 EL_DYNABOMB_PLAYER_4_ACTIVE,
4152 EL_SP_DISK_RED_ACTIVE,
4157 static int ep_inactive[] =
4167 EL_QUICKSAND_FAST_EMPTY,
4190 EL_GATE_1_GRAY_ACTIVE,
4191 EL_GATE_2_GRAY_ACTIVE,
4192 EL_GATE_3_GRAY_ACTIVE,
4193 EL_GATE_4_GRAY_ACTIVE,
4202 EL_EM_GATE_1_GRAY_ACTIVE,
4203 EL_EM_GATE_2_GRAY_ACTIVE,
4204 EL_EM_GATE_3_GRAY_ACTIVE,
4205 EL_EM_GATE_4_GRAY_ACTIVE,
4214 EL_EMC_GATE_5_GRAY_ACTIVE,
4215 EL_EMC_GATE_6_GRAY_ACTIVE,
4216 EL_EMC_GATE_7_GRAY_ACTIVE,
4217 EL_EMC_GATE_8_GRAY_ACTIVE,
4219 EL_DC_GATE_WHITE_GRAY,
4220 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4221 EL_DC_GATE_FAKE_GRAY,
4224 EL_INVISIBLE_STEELWALL,
4232 EL_WALL_EMERALD_YELLOW,
4233 EL_DYNABOMB_INCREASE_NUMBER,
4234 EL_DYNABOMB_INCREASE_SIZE,
4235 EL_DYNABOMB_INCREASE_POWER,
4239 EL_SOKOBAN_FIELD_EMPTY,
4240 EL_SOKOBAN_FIELD_FULL,
4241 EL_WALL_EMERALD_RED,
4242 EL_WALL_EMERALD_PURPLE,
4243 EL_ACID_POOL_TOPLEFT,
4244 EL_ACID_POOL_TOPRIGHT,
4245 EL_ACID_POOL_BOTTOMLEFT,
4246 EL_ACID_POOL_BOTTOM,
4247 EL_ACID_POOL_BOTTOMRIGHT,
4251 EL_BD_MAGIC_WALL_DEAD,
4253 EL_DC_MAGIC_WALL_DEAD,
4254 EL_AMOEBA_TO_DIAMOND,
4262 EL_SP_GRAVITY_PORT_RIGHT,
4263 EL_SP_GRAVITY_PORT_DOWN,
4264 EL_SP_GRAVITY_PORT_LEFT,
4265 EL_SP_GRAVITY_PORT_UP,
4266 EL_SP_PORT_HORIZONTAL,
4267 EL_SP_PORT_VERTICAL,
4278 EL_SP_HARDWARE_GRAY,
4279 EL_SP_HARDWARE_GREEN,
4280 EL_SP_HARDWARE_BLUE,
4282 EL_SP_HARDWARE_YELLOW,
4283 EL_SP_HARDWARE_BASE_1,
4284 EL_SP_HARDWARE_BASE_2,
4285 EL_SP_HARDWARE_BASE_3,
4286 EL_SP_HARDWARE_BASE_4,
4287 EL_SP_HARDWARE_BASE_5,
4288 EL_SP_HARDWARE_BASE_6,
4289 EL_SP_GRAVITY_ON_PORT_LEFT,
4290 EL_SP_GRAVITY_ON_PORT_RIGHT,
4291 EL_SP_GRAVITY_ON_PORT_UP,
4292 EL_SP_GRAVITY_ON_PORT_DOWN,
4293 EL_SP_GRAVITY_OFF_PORT_LEFT,
4294 EL_SP_GRAVITY_OFF_PORT_RIGHT,
4295 EL_SP_GRAVITY_OFF_PORT_UP,
4296 EL_SP_GRAVITY_OFF_PORT_DOWN,
4297 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4298 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4299 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4300 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4301 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4302 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4303 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4304 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4305 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4306 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4307 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4308 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4309 EL_SIGN_EXCLAMATION,
4310 EL_SIGN_RADIOACTIVITY,
4317 EL_SIGN_ENTRY_FORBIDDEN,
4318 EL_SIGN_EMERGENCY_EXIT,
4326 EL_DC_STEELWALL_1_LEFT,
4327 EL_DC_STEELWALL_1_RIGHT,
4328 EL_DC_STEELWALL_1_TOP,
4329 EL_DC_STEELWALL_1_BOTTOM,
4330 EL_DC_STEELWALL_1_HORIZONTAL,
4331 EL_DC_STEELWALL_1_VERTICAL,
4332 EL_DC_STEELWALL_1_TOPLEFT,
4333 EL_DC_STEELWALL_1_TOPRIGHT,
4334 EL_DC_STEELWALL_1_BOTTOMLEFT,
4335 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4336 EL_DC_STEELWALL_1_TOPLEFT_2,
4337 EL_DC_STEELWALL_1_TOPRIGHT_2,
4338 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4339 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4340 EL_DC_STEELWALL_2_LEFT,
4341 EL_DC_STEELWALL_2_RIGHT,
4342 EL_DC_STEELWALL_2_TOP,
4343 EL_DC_STEELWALL_2_BOTTOM,
4344 EL_DC_STEELWALL_2_HORIZONTAL,
4345 EL_DC_STEELWALL_2_VERTICAL,
4346 EL_DC_STEELWALL_2_MIDDLE,
4347 EL_DC_STEELWALL_2_SINGLE,
4348 EL_STEELWALL_SLIPPERY,
4353 EL_EMC_WALL_SLIPPERY_1,
4354 EL_EMC_WALL_SLIPPERY_2,
4355 EL_EMC_WALL_SLIPPERY_3,
4356 EL_EMC_WALL_SLIPPERY_4,
4377 static int ep_em_slippery_wall[] =
4382 static int ep_gfx_crumbled[] =
4393 static int ep_editor_cascade_active[] =
4395 EL_INTERNAL_CASCADE_BD_ACTIVE,
4396 EL_INTERNAL_CASCADE_EM_ACTIVE,
4397 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4398 EL_INTERNAL_CASCADE_RND_ACTIVE,
4399 EL_INTERNAL_CASCADE_SB_ACTIVE,
4400 EL_INTERNAL_CASCADE_SP_ACTIVE,
4401 EL_INTERNAL_CASCADE_DC_ACTIVE,
4402 EL_INTERNAL_CASCADE_DX_ACTIVE,
4403 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4404 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4405 EL_INTERNAL_CASCADE_CE_ACTIVE,
4406 EL_INTERNAL_CASCADE_GE_ACTIVE,
4407 EL_INTERNAL_CASCADE_REF_ACTIVE,
4408 EL_INTERNAL_CASCADE_USER_ACTIVE,
4409 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4414 static int ep_editor_cascade_inactive[] =
4416 EL_INTERNAL_CASCADE_BD,
4417 EL_INTERNAL_CASCADE_EM,
4418 EL_INTERNAL_CASCADE_EMC,
4419 EL_INTERNAL_CASCADE_RND,
4420 EL_INTERNAL_CASCADE_SB,
4421 EL_INTERNAL_CASCADE_SP,
4422 EL_INTERNAL_CASCADE_DC,
4423 EL_INTERNAL_CASCADE_DX,
4424 EL_INTERNAL_CASCADE_CHARS,
4425 EL_INTERNAL_CASCADE_STEEL_CHARS,
4426 EL_INTERNAL_CASCADE_CE,
4427 EL_INTERNAL_CASCADE_GE,
4428 EL_INTERNAL_CASCADE_REF,
4429 EL_INTERNAL_CASCADE_USER,
4430 EL_INTERNAL_CASCADE_DYNAMIC,
4435 static int ep_obsolete[] =
4439 EL_EM_KEY_1_FILE_OBSOLETE,
4440 EL_EM_KEY_2_FILE_OBSOLETE,
4441 EL_EM_KEY_3_FILE_OBSOLETE,
4442 EL_EM_KEY_4_FILE_OBSOLETE,
4443 EL_ENVELOPE_OBSOLETE,
4452 } element_properties[] =
4454 { ep_diggable, EP_DIGGABLE },
4455 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4456 { ep_dont_run_into, EP_DONT_RUN_INTO },
4457 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4458 { ep_dont_touch, EP_DONT_TOUCH },
4459 { ep_indestructible, EP_INDESTRUCTIBLE },
4460 { ep_slippery, EP_SLIPPERY },
4461 { ep_can_change, EP_CAN_CHANGE },
4462 { ep_can_move, EP_CAN_MOVE },
4463 { ep_can_fall, EP_CAN_FALL },
4464 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4465 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4466 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4467 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4468 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4469 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4470 { ep_walkable_over, EP_WALKABLE_OVER },
4471 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4472 { ep_walkable_under, EP_WALKABLE_UNDER },
4473 { ep_passable_over, EP_PASSABLE_OVER },
4474 { ep_passable_inside, EP_PASSABLE_INSIDE },
4475 { ep_passable_under, EP_PASSABLE_UNDER },
4476 { ep_droppable, EP_DROPPABLE },
4477 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4478 { ep_pushable, EP_PUSHABLE },
4479 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4480 { ep_protected, EP_PROTECTED },
4481 { ep_throwable, EP_THROWABLE },
4482 { ep_can_explode, EP_CAN_EXPLODE },
4483 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4485 { ep_player, EP_PLAYER },
4486 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4487 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4488 { ep_switchable, EP_SWITCHABLE },
4489 { ep_bd_element, EP_BD_ELEMENT },
4490 { ep_sp_element, EP_SP_ELEMENT },
4491 { ep_sb_element, EP_SB_ELEMENT },
4493 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4494 { ep_food_penguin, EP_FOOD_PENGUIN },
4495 { ep_food_pig, EP_FOOD_PIG },
4496 { ep_historic_wall, EP_HISTORIC_WALL },
4497 { ep_historic_solid, EP_HISTORIC_SOLID },
4498 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4499 { ep_belt, EP_BELT },
4500 { ep_belt_active, EP_BELT_ACTIVE },
4501 { ep_belt_switch, EP_BELT_SWITCH },
4502 { ep_tube, EP_TUBE },
4503 { ep_acid_pool, EP_ACID_POOL },
4504 { ep_keygate, EP_KEYGATE },
4505 { ep_amoeboid, EP_AMOEBOID },
4506 { ep_amoebalive, EP_AMOEBALIVE },
4507 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4508 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4509 { ep_can_grow, EP_CAN_GROW },
4510 { ep_active_bomb, EP_ACTIVE_BOMB },
4511 { ep_inactive, EP_INACTIVE },
4513 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4515 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4517 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4518 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4520 { ep_obsolete, EP_OBSOLETE },
4527 /* always start with reliable default values (element has no properties) */
4528 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4529 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4530 SET_PROPERTY(i, j, FALSE);
4532 /* set all base element properties from above array definitions */
4533 for (i = 0; element_properties[i].elements != NULL; i++)
4534 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4535 SET_PROPERTY((element_properties[i].elements)[j],
4536 element_properties[i].property, TRUE);
4538 /* copy properties to some elements that are only stored in level file */
4539 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4540 for (j = 0; copy_properties[j][0] != -1; j++)
4541 if (HAS_PROPERTY(copy_properties[j][0], i))
4542 for (k = 1; k <= 4; k++)
4543 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4545 /* set static element properties that are not listed in array definitions */
4546 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4547 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4550 void InitElementPropertiesEngine(int engine_version)
4552 static int no_wall_properties[] =
4555 EP_COLLECTIBLE_ONLY,
4557 EP_DONT_COLLIDE_WITH,
4560 EP_CAN_SMASH_PLAYER,
4561 EP_CAN_SMASH_ENEMIES,
4562 EP_CAN_SMASH_EVERYTHING,
4567 EP_FOOD_DARK_YAMYAM,
4583 /* important: after initialization in InitElementPropertiesStatic(), the
4584 elements are not again initialized to a default value; therefore all
4585 changes have to make sure that they leave the element with a defined
4586 property (which means that conditional property changes must be set to
4587 a reliable default value before) */
4589 /* resolve group elements */
4590 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4591 ResolveGroupElement(EL_GROUP_START + i);
4593 /* set all special, combined or engine dependent element properties */
4594 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4596 /* ---------- INACTIVE ------------------------------------------------- */
4597 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4598 i <= EL_CHAR_END) ||
4599 (i >= EL_STEEL_CHAR_START &&
4600 i <= EL_STEEL_CHAR_END)));
4602 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4603 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4604 IS_WALKABLE_INSIDE(i) ||
4605 IS_WALKABLE_UNDER(i)));
4607 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4608 IS_PASSABLE_INSIDE(i) ||
4609 IS_PASSABLE_UNDER(i)));
4611 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4612 IS_PASSABLE_OVER(i)));
4614 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4615 IS_PASSABLE_INSIDE(i)));
4617 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4618 IS_PASSABLE_UNDER(i)));
4620 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4623 /* ---------- COLLECTIBLE ---------------------------------------------- */
4624 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4628 /* ---------- SNAPPABLE ------------------------------------------------ */
4629 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4630 IS_COLLECTIBLE(i) ||
4634 /* ---------- WALL ----------------------------------------------------- */
4635 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4637 for (j = 0; no_wall_properties[j] != -1; j++)
4638 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4639 i >= EL_FIRST_RUNTIME_UNREAL)
4640 SET_PROPERTY(i, EP_WALL, FALSE);
4642 if (IS_HISTORIC_WALL(i))
4643 SET_PROPERTY(i, EP_WALL, TRUE);
4645 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4646 if (engine_version < VERSION_IDENT(2,2,0,0))
4647 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4649 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4651 !IS_COLLECTIBLE(i)));
4653 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4654 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4655 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4657 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4658 IS_INDESTRUCTIBLE(i)));
4660 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4662 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4663 else if (engine_version < VERSION_IDENT(2,2,0,0))
4664 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4666 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4670 if (IS_CUSTOM_ELEMENT(i))
4672 /* these are additional properties which are initially false when set */
4674 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4676 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4677 if (DONT_COLLIDE_WITH(i))
4678 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4680 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4681 if (CAN_SMASH_EVERYTHING(i))
4682 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4683 if (CAN_SMASH_ENEMIES(i))
4684 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4687 /* ---------- CAN_SMASH ------------------------------------------------ */
4688 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4689 CAN_SMASH_ENEMIES(i) ||
4690 CAN_SMASH_EVERYTHING(i)));
4692 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4693 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4694 EXPLODES_BY_FIRE(i)));
4696 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4697 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4698 EXPLODES_SMASHED(i)));
4700 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4701 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4702 EXPLODES_IMPACT(i)));
4704 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4705 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4707 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4708 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4709 i == EL_BLACK_ORB));
4711 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4712 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4714 IS_CUSTOM_ELEMENT(i)));
4716 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4717 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4718 i == EL_SP_ELECTRON));
4720 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4721 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4722 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4723 getMoveIntoAcidProperty(&level, i));
4725 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4726 if (MAYBE_DONT_COLLIDE_WITH(i))
4727 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4728 getDontCollideWithProperty(&level, i));
4730 /* ---------- SP_PORT -------------------------------------------------- */
4731 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4732 IS_PASSABLE_INSIDE(i)));
4734 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4735 for (j = 0; j < level.num_android_clone_elements; j++)
4736 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4738 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4740 /* ---------- CAN_CHANGE ----------------------------------------------- */
4741 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4742 for (j = 0; j < element_info[i].num_change_pages; j++)
4743 if (element_info[i].change_page[j].can_change)
4744 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4746 /* ---------- HAS_ACTION ----------------------------------------------- */
4747 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4748 for (j = 0; j < element_info[i].num_change_pages; j++)
4749 if (element_info[i].change_page[j].has_action)
4750 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4752 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4753 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4756 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4758 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4759 element_info[i].crumbled[ACTION_DEFAULT] !=
4760 element_info[i].graphic[ACTION_DEFAULT]);
4762 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
4763 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4764 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
4767 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4768 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4769 IS_EDITOR_CASCADE_INACTIVE(i)));
4772 /* dynamically adjust element properties according to game engine version */
4774 static int ep_em_slippery_wall[] =
4779 EL_EXPANDABLE_WALL_HORIZONTAL,
4780 EL_EXPANDABLE_WALL_VERTICAL,
4781 EL_EXPANDABLE_WALL_ANY,
4782 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4783 EL_EXPANDABLE_STEELWALL_VERTICAL,
4784 EL_EXPANDABLE_STEELWALL_ANY,
4785 EL_EXPANDABLE_STEELWALL_GROWING,
4789 /* special EM style gems behaviour */
4790 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4791 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4792 level.em_slippery_gems);
4794 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4795 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4796 (level.em_slippery_gems &&
4797 engine_version > VERSION_IDENT(2,0,1,0)));
4800 /* this is needed because some graphics depend on element properties */
4801 if (game_status == GAME_MODE_PLAYING)
4802 InitElementGraphicInfo();
4805 void InitElementPropertiesAfterLoading(int engine_version)
4809 /* set some other uninitialized values of custom elements in older levels */
4810 if (engine_version < VERSION_IDENT(3,1,0,0))
4812 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4814 int element = EL_CUSTOM_START + i;
4816 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4818 element_info[element].explosion_delay = 17;
4819 element_info[element].ignition_delay = 8;
4824 static void InitGlobal()
4829 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4831 /* check if element_name_info entry defined for each element in "main.h" */
4832 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4833 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4835 element_info[i].token_name = element_name_info[i].token_name;
4836 element_info[i].class_name = element_name_info[i].class_name;
4837 element_info[i].editor_description= element_name_info[i].editor_description;
4840 printf("%04d: %s\n", i, element_name_info[i].token_name);
4844 /* create hash from image config list */
4845 image_config_hash = newSetupFileHash();
4846 for (i = 0; image_config[i].token != NULL; i++)
4847 setHashEntry(image_config_hash,
4848 image_config[i].token,
4849 image_config[i].value);
4851 /* create hash from element token list */
4852 element_token_hash = newSetupFileHash();
4853 for (i = 0; element_name_info[i].token_name != NULL; i++)
4854 setHashEntry(element_token_hash,
4855 element_name_info[i].token_name,
4858 /* create hash from graphic token list */
4859 graphic_token_hash = newSetupFileHash();
4860 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4861 if (strSuffix(image_config[i].value, ".pcx") ||
4862 strSuffix(image_config[i].value, ".wav") ||
4863 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4864 setHashEntry(graphic_token_hash,
4865 image_config[i].token,
4866 int2str(graphic++, 0));
4868 /* create hash from font token list */
4869 font_token_hash = newSetupFileHash();
4870 for (i = 0; font_info[i].token_name != NULL; i++)
4871 setHashEntry(font_token_hash,
4872 font_info[i].token_name,
4875 /* always start with reliable default values (all elements) */
4876 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4877 ActiveElement[i] = i;
4879 /* now add all entries that have an active state (active elements) */
4880 for (i = 0; element_with_active_state[i].element != -1; i++)
4882 int element = element_with_active_state[i].element;
4883 int element_active = element_with_active_state[i].element_active;
4885 ActiveElement[element] = element_active;
4888 /* always start with reliable default values (all buttons) */
4889 for (i = 0; i < NUM_IMAGE_FILES; i++)
4890 ActiveButton[i] = i;
4892 /* now add all entries that have an active state (active buttons) */
4893 for (i = 0; button_with_active_state[i].button != -1; i++)
4895 int button = button_with_active_state[i].button;
4896 int button_active = button_with_active_state[i].button_active;
4898 ActiveButton[button] = button_active;
4901 /* always start with reliable default values (all fonts) */
4902 for (i = 0; i < NUM_FONTS; i++)
4905 /* now add all entries that have an active state (active fonts) */
4906 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4908 int font = font_with_active_state[i].font_nr;
4909 int font_active = font_with_active_state[i].font_nr_active;
4911 ActiveFont[font] = font_active;
4914 global.autoplay_leveldir = NULL;
4915 global.convert_leveldir = NULL;
4917 global.frames_per_second = 0;
4918 global.fps_slowdown = FALSE;
4919 global.fps_slowdown_factor = 1;
4921 global.border_status = GAME_MODE_MAIN;
4923 global.fading_status = GAME_MODE_MAIN;
4924 global.fading_type = TYPE_ENTER_MENU;
4928 void Execute_Command(char *command)
4932 if (strEqual(command, "print graphicsinfo.conf"))
4934 printf("# You can configure additional/alternative image files here.\n");
4935 printf("# (The entries below are default and therefore commented out.)\n");
4937 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4939 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4942 for (i = 0; image_config[i].token != NULL; i++)
4943 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
4944 image_config[i].value));
4948 else if (strEqual(command, "print soundsinfo.conf"))
4950 printf("# You can configure additional/alternative sound files here.\n");
4951 printf("# (The entries below are default and therefore commented out.)\n");
4953 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4955 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4958 for (i = 0; sound_config[i].token != NULL; i++)
4959 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4960 sound_config[i].value));
4964 else if (strEqual(command, "print musicinfo.conf"))
4966 printf("# You can configure additional/alternative music files here.\n");
4967 printf("# (The entries below are default and therefore commented out.)\n");
4969 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4971 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4974 for (i = 0; music_config[i].token != NULL; i++)
4975 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
4976 music_config[i].value));
4980 else if (strEqual(command, "print editorsetup.conf"))
4982 printf("# You can configure your personal editor element list here.\n");
4983 printf("# (The entries below are default and therefore commented out.)\n");
4986 /* this is needed to be able to check element list for cascade elements */
4987 InitElementPropertiesStatic();
4988 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4990 PrintEditorElementList();
4994 else if (strEqual(command, "print helpanim.conf"))
4996 printf("# You can configure different element help animations here.\n");
4997 printf("# (The entries below are default and therefore commented out.)\n");
5000 for (i = 0; helpanim_config[i].token != NULL; i++)
5002 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
5003 helpanim_config[i].value));
5005 if (strEqual(helpanim_config[i].token, "end"))
5011 else if (strEqual(command, "print helptext.conf"))
5013 printf("# You can configure different element help text here.\n");
5014 printf("# (The entries below are default and therefore commented out.)\n");
5017 for (i = 0; helptext_config[i].token != NULL; i++)
5018 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
5019 helptext_config[i].value));
5023 else if (strncmp(command, "dump level ", 11) == 0)
5025 char *filename = &command[11];
5027 if (!fileExists(filename))
5028 Error(ERR_EXIT, "cannot open file '%s'", filename);
5030 LoadLevelFromFilename(&level, filename);
5035 else if (strncmp(command, "dump tape ", 10) == 0)
5037 char *filename = &command[10];
5039 if (!fileExists(filename))
5040 Error(ERR_EXIT, "cannot open file '%s'", filename);
5042 LoadTapeFromFilename(filename);
5047 else if (strncmp(command, "autoplay ", 9) == 0)
5049 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
5051 while (*str_ptr != '\0') /* continue parsing string */
5053 /* cut leading whitespace from string, replace it by string terminator */
5054 while (*str_ptr == ' ' || *str_ptr == '\t')
5057 if (*str_ptr == '\0') /* end of string reached */
5060 if (global.autoplay_leveldir == NULL) /* read level set string */
5062 global.autoplay_leveldir = str_ptr;
5063 global.autoplay_all = TRUE; /* default: play all tapes */
5065 for (i = 0; i < MAX_TAPES_PER_SET; i++)
5066 global.autoplay_level[i] = FALSE;
5068 else /* read level number string */
5070 int level_nr = atoi(str_ptr); /* get level_nr value */
5072 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5073 global.autoplay_level[level_nr] = TRUE;
5075 global.autoplay_all = FALSE;
5078 /* advance string pointer to the next whitespace (or end of string) */
5079 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5083 else if (strncmp(command, "convert ", 8) == 0)
5085 char *str_copy = getStringCopy(&command[8]);
5086 char *str_ptr = strchr(str_copy, ' ');
5088 global.convert_leveldir = str_copy;
5089 global.convert_level_nr = -1;
5091 if (str_ptr != NULL) /* level number follows */
5093 *str_ptr++ = '\0'; /* terminate leveldir string */
5094 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
5099 #if defined(TARGET_SDL)
5100 else if (strEqual(command, "SDL_ListModes"))
5105 SDL_Init(SDL_INIT_VIDEO);
5107 /* get available fullscreen/hardware modes */
5108 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
5110 /* check if there are any modes available */
5113 printf("No modes available!\n");
5118 /* check if our resolution is restricted */
5119 if (modes == (SDL_Rect **)-1)
5121 printf("All resolutions available.\n");
5125 printf("Available Modes:\n");
5127 for(i = 0; modes[i]; i++)
5128 printf(" %d x %d\n", modes[i]->w, modes[i]->h);
5138 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
5142 static void InitSetup()
5144 LoadSetup(); /* global setup info */
5146 /* set some options from setup file */
5148 if (setup.options.verbose)
5149 options.verbose = TRUE;
5152 static void InitGameInfo()
5154 game.restart_level = FALSE;
5157 static void InitPlayerInfo()
5161 /* choose default local player */
5162 local_player = &stored_player[0];
5164 for (i = 0; i < MAX_PLAYERS; i++)
5165 stored_player[i].connected = FALSE;
5167 local_player->connected = TRUE;
5170 static void InitArtworkInfo()
5175 static char *get_string_in_brackets(char *string)
5177 char *string_in_brackets = checked_malloc(strlen(string) + 3);
5179 sprintf(string_in_brackets, "[%s]", string);
5181 return string_in_brackets;
5184 static char *get_level_id_suffix(int id_nr)
5186 char *id_suffix = checked_malloc(1 + 3 + 1);
5188 if (id_nr < 0 || id_nr > 999)
5191 sprintf(id_suffix, ".%03d", id_nr);
5197 static char *get_element_class_token(int element)
5199 char *element_class_name = element_info[element].class_name;
5200 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
5202 sprintf(element_class_token, "[%s]", element_class_name);
5204 return element_class_token;
5207 static char *get_action_class_token(int action)
5209 char *action_class_name = &element_action_info[action].suffix[1];
5210 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
5212 sprintf(action_class_token, "[%s]", action_class_name);
5214 return action_class_token;
5218 static void InitArtworkConfig()
5220 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
5221 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
5222 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
5223 static char *action_id_suffix[NUM_ACTIONS + 1];
5224 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5225 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5226 static char *level_id_suffix[MAX_LEVELS + 1];
5227 static char *dummy[1] = { NULL };
5228 static char *ignore_generic_tokens[] =
5234 static char **ignore_image_tokens;
5235 static char **ignore_sound_tokens;
5236 static char **ignore_music_tokens;
5237 int num_ignore_generic_tokens;
5238 int num_ignore_image_tokens;
5239 int num_ignore_sound_tokens;
5240 int num_ignore_music_tokens;
5243 /* dynamically determine list of generic tokens to be ignored */
5244 num_ignore_generic_tokens = 0;
5245 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5246 num_ignore_generic_tokens++;
5248 /* dynamically determine list of image tokens to be ignored */
5249 num_ignore_image_tokens = num_ignore_generic_tokens;
5250 for (i = 0; image_config_vars[i].token != NULL; i++)
5251 num_ignore_image_tokens++;
5252 ignore_image_tokens =
5253 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5254 for (i = 0; i < num_ignore_generic_tokens; i++)
5255 ignore_image_tokens[i] = ignore_generic_tokens[i];
5256 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5257 ignore_image_tokens[num_ignore_generic_tokens + i] =
5258 image_config_vars[i].token;
5259 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5261 /* dynamically determine list of sound tokens to be ignored */
5262 num_ignore_sound_tokens = num_ignore_generic_tokens;
5263 ignore_sound_tokens =
5264 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5265 for (i = 0; i < num_ignore_generic_tokens; i++)
5266 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5267 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5269 /* dynamically determine list of music tokens to be ignored */
5270 num_ignore_music_tokens = num_ignore_generic_tokens;
5271 ignore_music_tokens =
5272 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5273 for (i = 0; i < num_ignore_generic_tokens; i++)
5274 ignore_music_tokens[i] = ignore_generic_tokens[i];
5275 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5277 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5278 image_id_prefix[i] = element_info[i].token_name;
5279 for (i = 0; i < NUM_FONTS; i++)
5280 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5281 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
5283 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5284 sound_id_prefix[i] = element_info[i].token_name;
5285 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5286 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5287 get_string_in_brackets(element_info[i].class_name);
5288 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
5290 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5291 music_id_prefix[i] = music_prefix_info[i].prefix;
5292 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
5294 for (i = 0; i < NUM_ACTIONS; i++)
5295 action_id_suffix[i] = element_action_info[i].suffix;
5296 action_id_suffix[NUM_ACTIONS] = NULL;
5298 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5299 direction_id_suffix[i] = element_direction_info[i].suffix;
5300 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5302 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5303 special_id_suffix[i] = special_suffix_info[i].suffix;
5304 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5306 for (i = 0; i < MAX_LEVELS; i++)
5307 level_id_suffix[i] = get_level_id_suffix(i);
5308 level_id_suffix[MAX_LEVELS] = NULL;
5310 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5311 image_id_prefix, action_id_suffix, direction_id_suffix,
5312 special_id_suffix, ignore_image_tokens);
5313 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5314 sound_id_prefix, action_id_suffix, dummy,
5315 special_id_suffix, ignore_sound_tokens);
5316 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5317 music_id_prefix, special_id_suffix, level_id_suffix,
5318 dummy, ignore_music_tokens);
5321 static void InitMixer()
5329 char *filename_font_initial = NULL;
5330 char *filename_anim_initial = NULL;
5331 Bitmap *bitmap_font_initial = NULL;
5335 /* determine settings for initial font (for displaying startup messages) */
5336 for (i = 0; image_config[i].token != NULL; i++)
5338 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5340 char font_token[128];
5343 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5344 len_font_token = strlen(font_token);
5346 if (strEqual(image_config[i].token, font_token))
5347 filename_font_initial = image_config[i].value;
5348 else if (strlen(image_config[i].token) > len_font_token &&
5349 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5351 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5352 font_initial[j].src_x = atoi(image_config[i].value);
5353 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5354 font_initial[j].src_y = atoi(image_config[i].value);
5355 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5356 font_initial[j].width = atoi(image_config[i].value);
5357 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5358 font_initial[j].height = atoi(image_config[i].value);
5363 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5365 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5366 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5369 if (filename_font_initial == NULL) /* should not happen */
5370 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5372 /* create additional image buffers for double-buffering and cross-fading */
5373 bitmap_db_cross = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5374 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
5375 bitmap_db_panel = CreateBitmap(DXSIZE, DYSIZE, DEFAULT_DEPTH);
5376 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
5378 /* initialize screen properties */
5379 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5380 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5382 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5383 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5384 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5386 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5388 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5389 font_initial[j].bitmap = bitmap_font_initial;
5391 InitFontGraphicInfo();
5393 font_height = getFontHeight(FC_RED);
5396 DrawInitText(getWindowTitleString(), 20, FC_YELLOW);
5398 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
5400 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
5401 DrawInitText(PROGRAM_WEBSITE_STRING, WIN_YSIZE - 20 - font_height, FC_RED);
5403 DrawInitText("Loading graphics", 120, FC_GREEN);
5407 /* initialize busy animation with default values */
5408 int parameter[NUM_GFX_ARGS];
5409 for (i = 0; i < NUM_GFX_ARGS; i++)
5410 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5411 image_config_suffix[i].token,
5412 image_config_suffix[i].type);
5414 for (i = 0; i < NUM_GFX_ARGS; i++)
5415 printf("::: '%s' => %d\n", image_config_suffix[i].token, parameter[i]);
5419 /* determine settings for busy animation (when displaying startup messages) */
5420 for (i = 0; image_config[i].token != NULL; i++)
5422 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5423 int len_anim_token = strlen(anim_token);
5425 if (strEqual(image_config[i].token, anim_token))
5426 filename_anim_initial = image_config[i].value;
5427 else if (strlen(image_config[i].token) > len_anim_token &&
5428 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5431 for (j = 0; image_config_suffix[j].token != NULL; j++)
5433 if (strEqual(&image_config[i].token[len_anim_token],
5434 image_config_suffix[j].token))
5436 get_graphic_parameter_value(image_config[i].value,
5437 image_config_suffix[j].token,
5438 image_config_suffix[j].type);
5441 if (strEqual(&image_config[i].token[len_anim_token], ".x"))
5442 anim_initial.src_x = atoi(image_config[i].value);
5443 else if (strEqual(&image_config[i].token[len_anim_token], ".y"))
5444 anim_initial.src_y = atoi(image_config[i].value);
5445 else if (strEqual(&image_config[i].token[len_anim_token], ".width"))
5446 anim_initial.width = atoi(image_config[i].value);
5447 else if (strEqual(&image_config[i].token[len_anim_token], ".height"))
5448 anim_initial.height = atoi(image_config[i].value);
5449 else if (strEqual(&image_config[i].token[len_anim_token], ".frames"))
5450 anim_initial.anim_frames = atoi(image_config[i].value);
5451 else if (strEqual(&image_config[i].token[len_anim_token],
5452 ".frames_per_line"))
5453 anim_initial.anim_frames_per_line = atoi(image_config[i].value);
5454 else if (strEqual(&image_config[i].token[len_anim_token], ".delay"))
5455 anim_initial.anim_delay = atoi(image_config[i].value);
5460 set_graphic_parameters_ext(0, &anim_initial, parameter, NULL);
5462 if (filename_anim_initial == NULL) /* should not happen */
5463 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5465 anim_initial.bitmap = LoadCustomImage(filename_anim_initial);
5467 init.busy.width = anim_initial.width;
5468 init.busy.height = anim_initial.height;
5470 InitMenuDesignSettings_Static();
5471 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5475 void RedrawBackground()
5477 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
5478 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
5480 redraw_mask = REDRAW_ALL;
5483 void InitGfxBackground()
5487 fieldbuffer = bitmap_db_field;
5488 SetDrawtoField(DRAW_BACKBUFFER);
5491 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5495 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
5496 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
5499 for (x = 0; x < MAX_BUF_XSIZE; x++)
5500 for (y = 0; y < MAX_BUF_YSIZE; y++)
5503 redraw_mask = REDRAW_ALL;
5506 static void InitLevelInfo()
5508 LoadLevelInfo(); /* global level info */
5509 LoadLevelSetup_LastSeries(); /* last played series info */
5510 LoadLevelSetup_SeriesInfo(); /* last played level info */
5513 void InitLevelArtworkInfo()
5515 LoadLevelArtworkInfo();
5518 static void InitImages()
5520 print_init_timestamp("INIT InitImages");
5522 setLevelArtworkDir(artwork.gfx_first);
5525 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5526 leveldir_current->identifier,
5527 artwork.gfx_current_identifier,
5528 artwork.gfx_current->identifier,
5529 leveldir_current->graphics_set,
5530 leveldir_current->graphics_path);
5533 UPDATE_BUSY_STATE();
5535 ReloadCustomImages();
5536 print_init_timestamp("TIME ReloadCustomImages");
5538 UPDATE_BUSY_STATE();
5540 LoadCustomElementDescriptions();
5541 print_init_timestamp("TIME LoadCustomElementDescriptions");
5543 UPDATE_BUSY_STATE();
5545 LoadMenuDesignSettings();
5546 print_init_timestamp("TIME LoadMenuDesignSettings");
5548 UPDATE_BUSY_STATE();
5550 ReinitializeGraphics();
5551 print_init_timestamp("TIME ReinitializeGraphics");
5553 UPDATE_BUSY_STATE();
5555 print_init_timestamp("DONE InitImages");
5558 static void InitSound(char *identifier)
5560 print_init_timestamp("INIT InitSound");
5562 if (identifier == NULL)
5563 identifier = artwork.snd_current->identifier;
5565 /* set artwork path to send it to the sound server process */
5566 setLevelArtworkDir(artwork.snd_first);
5568 InitReloadCustomSounds(identifier);
5569 print_init_timestamp("TIME InitReloadCustomSounds");
5571 ReinitializeSounds();
5572 print_init_timestamp("TIME ReinitializeSounds");
5574 print_init_timestamp("DONE InitSound");
5577 static void InitMusic(char *identifier)
5579 print_init_timestamp("INIT InitMusic");
5581 if (identifier == NULL)
5582 identifier = artwork.mus_current->identifier;
5584 /* set artwork path to send it to the sound server process */
5585 setLevelArtworkDir(artwork.mus_first);
5587 InitReloadCustomMusic(identifier);
5588 print_init_timestamp("TIME InitReloadCustomMusic");
5590 ReinitializeMusic();
5591 print_init_timestamp("TIME ReinitializeMusic");
5593 print_init_timestamp("DONE InitMusic");
5596 void InitNetworkServer()
5598 #if defined(NETWORK_AVALIABLE)
5602 if (!options.network)
5605 #if defined(NETWORK_AVALIABLE)
5606 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5608 if (!ConnectToServer(options.server_host, options.server_port))
5609 Error(ERR_EXIT, "cannot connect to network game server");
5611 SendToServer_PlayerName(setup.player_name);
5612 SendToServer_ProtocolVersion();
5615 SendToServer_NrWanted(nr_wanted);
5619 static char *getNewArtworkIdentifier(int type)
5621 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5622 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5623 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5624 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5625 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5626 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
5627 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5628 char *leveldir_identifier = leveldir_current->identifier;
5630 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
5631 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5633 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
5635 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5636 char *artwork_current_identifier;
5637 char *artwork_new_identifier = NULL; /* default: nothing has changed */
5639 /* leveldir_current may be invalid (level group, parent link) */
5640 if (!validLevelSeries(leveldir_current))
5643 /* 1st step: determine artwork set to be activated in descending order:
5644 --------------------------------------------------------------------
5645 1. setup artwork (when configured to override everything else)
5646 2. artwork set configured in "levelinfo.conf" of current level set
5647 (artwork in level directory will have priority when loading later)
5648 3. artwork in level directory (stored in artwork sub-directory)
5649 4. setup artwork (currently configured in setup menu) */
5651 if (setup_override_artwork)
5652 artwork_current_identifier = setup_artwork_set;
5653 else if (leveldir_artwork_set != NULL)
5654 artwork_current_identifier = leveldir_artwork_set;
5655 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5656 artwork_current_identifier = leveldir_identifier;
5658 artwork_current_identifier = setup_artwork_set;
5661 /* 2nd step: check if it is really needed to reload artwork set
5662 ------------------------------------------------------------ */
5665 if (type == ARTWORK_TYPE_GRAPHICS)
5666 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
5667 artwork_new_identifier,
5668 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5669 artwork_current_identifier,
5670 leveldir_current->graphics_set,
5671 leveldir_current->identifier);
5674 /* ---------- reload if level set and also artwork set has changed ------- */
5675 if (leveldir_current_identifier[type] != leveldir_identifier &&
5676 (last_has_level_artwork_set[type] || has_level_artwork_set))
5677 artwork_new_identifier = artwork_current_identifier;
5679 leveldir_current_identifier[type] = leveldir_identifier;
5680 last_has_level_artwork_set[type] = has_level_artwork_set;
5683 if (type == ARTWORK_TYPE_GRAPHICS)
5684 printf("::: 1: '%s'\n", artwork_new_identifier);
5687 /* ---------- reload if "override artwork" setting has changed ----------- */
5688 if (last_override_level_artwork[type] != setup_override_artwork)
5689 artwork_new_identifier = artwork_current_identifier;
5691 last_override_level_artwork[type] = setup_override_artwork;
5694 if (type == ARTWORK_TYPE_GRAPHICS)
5695 printf("::: 2: '%s'\n", artwork_new_identifier);
5698 /* ---------- reload if current artwork identifier has changed ----------- */
5699 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5700 artwork_current_identifier))
5701 artwork_new_identifier = artwork_current_identifier;
5703 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5706 if (type == ARTWORK_TYPE_GRAPHICS)
5707 printf("::: 3: '%s'\n", artwork_new_identifier);
5710 /* ---------- do not reload directly after starting ---------------------- */
5711 if (!initialized[type])
5712 artwork_new_identifier = NULL;
5714 initialized[type] = TRUE;
5717 if (type == ARTWORK_TYPE_GRAPHICS)
5718 printf("::: 4: '%s'\n", artwork_new_identifier);
5722 if (type == ARTWORK_TYPE_GRAPHICS)
5723 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
5724 artwork.gfx_current_identifier, artwork_current_identifier,
5725 artwork.gfx_current->identifier, leveldir_current->graphics_set,
5726 artwork_new_identifier);
5729 return artwork_new_identifier;
5732 void ReloadCustomArtwork(int force_reload)
5734 char *gfx_new_identifier;
5735 char *snd_new_identifier;
5736 char *mus_new_identifier;
5737 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5738 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5739 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5740 boolean reload_needed;
5742 force_reload_gfx |= AdjustGraphicsForEMC();
5744 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5745 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5746 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5748 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
5749 snd_new_identifier != NULL || force_reload_snd ||
5750 mus_new_identifier != NULL || force_reload_mus);
5755 print_init_timestamp("INIT ReloadCustomArtwork");
5757 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
5758 print_init_timestamp("TIME ClearRectangle");
5760 if (gfx_new_identifier != NULL || force_reload_gfx)
5763 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5764 artwork.gfx_current_identifier,
5766 artwork.gfx_current->identifier,
5767 leveldir_current->graphics_set);
5771 print_init_timestamp("TIME InitImages");
5774 if (snd_new_identifier != NULL || force_reload_snd)
5776 InitSound(snd_new_identifier);
5777 print_init_timestamp("TIME InitSound");
5780 if (mus_new_identifier != NULL || force_reload_mus)
5782 InitMusic(mus_new_identifier);
5783 print_init_timestamp("TIME InitMusic");
5788 /* force redraw of (open or closed) door graphics */
5789 SetDoorState(DOOR_OPEN_ALL);
5790 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5794 FadeSetEnterScreen();
5795 // FadeSkipNextFadeOut();
5796 // FadeSetDisabled();
5801 fading = fading_none;
5804 print_init_timestamp("DONE ReloadCustomArtwork");
5807 void KeyboardAutoRepeatOffUnlessAutoplay()
5809 if (global.autoplay_leveldir == NULL)
5810 KeyboardAutoRepeatOff();
5814 /* ========================================================================= */
5816 /* ========================================================================= */
5820 print_init_timestamp("INIT OpenAll");
5822 InitGlobal(); /* initialize some global variables */
5824 if (options.execute_command)
5825 Execute_Command(options.execute_command);
5827 if (options.serveronly)
5829 #if defined(PLATFORM_UNIX)
5830 NetworkServer(options.server_port, options.serveronly);
5832 Error(ERR_WARN, "networking only supported in Unix version");
5835 exit(0); /* never reached, server loops forever */
5842 InitArtworkInfo(); /* needed before loading gfx, sound & music */
5843 InitArtworkConfig(); /* needed before forking sound child process */
5848 InitRND(NEW_RANDOMIZE);
5849 InitSimpleRandom(NEW_RANDOMIZE);
5853 print_init_timestamp("TIME [pre-video]");
5856 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
5858 InitEventFilter(FilterMouseMotionEvents);
5860 InitElementPropertiesStatic();
5861 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5863 print_init_timestamp("TIME [post-video]");
5867 print_init_timestamp("TIME InitGfx");
5870 print_init_timestamp("TIME InitLevelInfo");
5872 InitLevelArtworkInfo();
5873 print_init_timestamp("TIME InitLevelArtworkInfo");
5875 InitImages(); /* needs to know current level directory */
5876 print_init_timestamp("TIME InitImages");
5878 InitSound(NULL); /* needs to know current level directory */
5879 print_init_timestamp("TIME InitSound");
5881 InitMusic(NULL); /* needs to know current level directory */
5882 print_init_timestamp("TIME InitMusic");
5884 InitGfxBackground();
5890 if (global.autoplay_leveldir)
5895 else if (global.convert_leveldir)
5901 game_status = GAME_MODE_MAIN;
5904 FadeSetEnterScreen();
5905 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
5906 FadeSkipNextFadeOut();
5907 // FadeSetDisabled();
5909 fading = fading_none;
5912 print_init_timestamp("TIME [post-artwork]");
5914 print_init_timestamp("DONE OpenAll");
5918 InitNetworkServer();
5921 void CloseAllAndExit(int exit_value)
5926 CloseAudio(); /* called after freeing sounds (needed for SDL) */
5934 #if defined(TARGET_SDL)
5935 if (network_server) /* terminate network server */
5936 SDL_KillThread(server_thread);
5939 CloseVideoDisplay();
5940 ClosePlatformDependentStuff();
5942 if (exit_value != 0)
5943 NotifyUserAboutErrorFile();