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 1
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_timestamp_ext(char *message, char *mode)
95 #if DEBUG_PRINT_INIT_TIMESTAMPS
96 static char *debug_message = NULL;
97 static char *last_message = NULL;
98 static int counter_nr = 0;
99 int max_depth = DEBUG_PRINT_INIT_TIMESTAMPS_DEPTH;
101 checked_free(debug_message);
102 debug_message = getStringCat3(mode, " ", message);
104 if (strEqual(mode, "INIT"))
106 debug_print_timestamp(counter_nr, NULL);
108 if (counter_nr + 1 < max_depth)
109 debug_print_timestamp(counter_nr, debug_message);
113 debug_print_timestamp(counter_nr, NULL);
115 else if (strEqual(mode, "DONE"))
119 if (counter_nr + 1 < max_depth ||
120 (counter_nr == 0 && max_depth == 1))
122 last_message = message;
124 if (counter_nr == 0 && max_depth == 1)
126 checked_free(debug_message);
127 debug_message = getStringCat3("TIME", " ", message);
130 debug_print_timestamp(counter_nr, debug_message);
133 else if (!strEqual(mode, "TIME") ||
134 !strEqual(message, last_message))
136 if (counter_nr < max_depth)
137 debug_print_timestamp(counter_nr, debug_message);
143 static void print_timestamp_init(char *message)
145 print_timestamp_ext(message, "INIT");
148 static void print_timestamp_time(char *message)
150 print_timestamp_ext(message, "TIME");
153 static void print_timestamp_done(char *message)
155 print_timestamp_ext(message, "DONE");
160 struct GraphicInfo *graphic_info_last = graphic_info;
162 static unsigned long action_delay = 0;
163 unsigned long action_delay_value = GameFrameDelay;
164 int sync_frame = FrameCounter;
167 if (game_status != GAME_MODE_LOADING)
170 if (anim_initial.bitmap == NULL || window == NULL)
173 if (!DelayReached(&action_delay, action_delay_value))
178 static unsigned long last_counter = -1;
179 unsigned long current_counter = Counter();
180 unsigned long delay = current_counter - last_counter;
182 if (last_counter != -1 && delay > action_delay_value + 5)
183 printf("::: DrawInitAnim: DELAY TOO LONG: %ld\n", delay);
185 last_counter = current_counter;
190 anim_initial.anim_mode = ANIM_LOOP;
191 anim_initial.anim_start_frame = 0;
192 anim_initial.offset_x = anim_initial.width;
193 anim_initial.offset_y = 0;
197 x = ALIGNED_TEXT_XPOS(&init.busy);
198 y = ALIGNED_TEXT_YPOS(&init.busy);
200 x = WIN_XSIZE / 2 - TILESIZE / 2;
201 y = WIN_YSIZE / 2 - TILESIZE / 2;
206 static boolean done = FALSE;
209 printf("::: %d, %d, %d, %d => %d, %d\n",
210 init.busy.x, init.busy.y,
211 init.busy.align, init.busy.valign,
218 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
220 if (sync_frame % anim_initial.anim_delay == 0)
221 DrawGraphicAnimationExt(window, x, y, graphic, sync_frame, NO_MASKING);
223 graphic_info = graphic_info_last;
230 FreeLevelEditorGadgets();
239 static boolean gadgets_initialized = FALSE;
241 if (gadgets_initialized)
244 CreateLevelEditorGadgets();
248 CreateScreenGadgets();
250 InitGadgetsSoundCallback(PlaySoundActivating, PlaySoundSelecting);
252 gadgets_initialized = TRUE;
255 inline void InitElementSmallImagesScaledUp(int graphic)
258 struct FileInfo *fi = getImageListEntryFromImageID(graphic);
260 printf("::: '%s' -> '%s'\n", fi->token, fi->filename);
263 CreateImageWithSmallImages(graphic, graphic_info[graphic].scale_up_factor);
266 void InitElementSmallImages()
268 static int special_graphics[] =
270 IMG_EDITOR_ELEMENT_BORDER,
271 IMG_EDITOR_ELEMENT_BORDER_INPUT,
272 IMG_EDITOR_CASCADE_LIST,
273 IMG_EDITOR_CASCADE_LIST_ACTIVE,
276 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
277 int num_property_mappings = getImageListPropertyMappingSize();
280 /* initialize normal images from static configuration */
281 for (i = 0; element_to_graphic[i].element > -1; i++)
282 InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
284 /* initialize special images from static configuration */
285 for (i = 0; element_to_special_graphic[i].element > -1; i++)
286 InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
288 /* initialize images from dynamic configuration (may be elements or other) */
289 for (i = 0; i < num_property_mappings; i++)
290 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
292 /* initialize special images from above list (non-element images) */
293 for (i = 0; special_graphics[i] > -1; i++)
294 InitElementSmallImagesScaledUp(special_graphics[i]);
297 void InitScaledImages()
301 /* scale normal images from static configuration, if not already scaled */
302 for (i = 0; i < NUM_IMAGE_FILES; i++)
303 ScaleImage(i, graphic_info[i].scale_up_factor);
307 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
308 void SetBitmaps_EM(Bitmap **em_bitmap)
310 em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
311 em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].bitmap;
315 static int getFontBitmapID(int font_nr)
319 /* (special case: do not use special font for GAME_MODE_LOADING) */
320 if (game_status >= GAME_MODE_TITLE_INITIAL &&
321 game_status <= GAME_MODE_PSEUDO_PREVIEW)
322 special = game_status;
323 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
324 special = GFX_SPECIAL_ARG_MAIN;
326 else if (game_status == GAME_MODE_PLAYING)
327 special = GFX_SPECIAL_ARG_DOOR;
331 return font_info[font_nr].special_bitmap_id[special];
336 static int getFontFromToken(char *token)
339 char *value = getHashEntry(font_token_hash, token);
346 /* !!! OPTIMIZE THIS BY USING HASH !!! */
347 for (i = 0; i < NUM_FONTS; i++)
348 if (strEqual(token, font_info[i].token_name))
352 /* if font not found, use reliable default value */
353 return FONT_INITIAL_1;
356 void InitFontGraphicInfo()
358 static struct FontBitmapInfo *font_bitmap_info = NULL;
359 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
360 int num_property_mappings = getImageListPropertyMappingSize();
361 int num_font_bitmaps = NUM_FONTS;
364 if (graphic_info == NULL) /* still at startup phase */
366 InitFontInfo(font_initial, NUM_INITIAL_FONTS,
367 getFontBitmapID, getFontFromToken);
372 /* ---------- initialize font graphic definitions ---------- */
374 /* always start with reliable default values (normal font graphics) */
375 for (i = 0; i < NUM_FONTS; i++)
376 font_info[i].graphic = IMG_FONT_INITIAL_1;
378 /* initialize normal font/graphic mapping from static configuration */
379 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
381 int font_nr = font_to_graphic[i].font_nr;
382 int special = font_to_graphic[i].special;
383 int graphic = font_to_graphic[i].graphic;
388 font_info[font_nr].graphic = graphic;
391 /* always start with reliable default values (special font graphics) */
392 for (i = 0; i < NUM_FONTS; i++)
394 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
396 font_info[i].special_graphic[j] = font_info[i].graphic;
397 font_info[i].special_bitmap_id[j] = i;
401 /* initialize special font/graphic mapping from static configuration */
402 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
404 int font_nr = font_to_graphic[i].font_nr;
405 int special = font_to_graphic[i].special;
406 int graphic = font_to_graphic[i].graphic;
407 int base_graphic = font2baseimg(font_nr);
409 if (IS_SPECIAL_GFX_ARG(special))
411 boolean base_redefined =
412 getImageListEntryFromImageID(base_graphic)->redefined;
413 boolean special_redefined =
414 getImageListEntryFromImageID(graphic)->redefined;
415 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
417 /* if the base font ("font.title_1", for example) has been redefined,
418 but not the special font ("font.title_1.LEVELS", for example), do not
419 use an existing (in this case considered obsolete) special font
420 anymore, but use the automatically determined default font */
421 /* special case: cloned special fonts must be explicitly redefined,
422 but are not automatically redefined by redefining base font */
423 if (base_redefined && !special_redefined && !special_cloned)
426 font_info[font_nr].special_graphic[special] = graphic;
427 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
432 /* initialize special font/graphic mapping from dynamic configuration */
433 for (i = 0; i < num_property_mappings; i++)
435 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
436 int special = property_mapping[i].ext3_index;
437 int graphic = property_mapping[i].artwork_index;
442 if (IS_SPECIAL_GFX_ARG(special))
444 font_info[font_nr].special_graphic[special] = graphic;
445 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
450 /* correct special font/graphic mapping for cloned fonts for downwards
451 compatibility of PREVIEW fonts -- this is only needed for implicit
452 redefinition of special font by redefined base font, and only if other
453 fonts are cloned from this special font (like in the "Zelda" level set) */
454 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
456 int font_nr = font_to_graphic[i].font_nr;
457 int special = font_to_graphic[i].special;
458 int graphic = font_to_graphic[i].graphic;
460 if (IS_SPECIAL_GFX_ARG(special))
462 boolean special_redefined =
463 getImageListEntryFromImageID(graphic)->redefined;
464 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
466 if (special_cloned && !special_redefined)
470 for (j = 0; font_to_graphic[j].font_nr > -1; j++)
472 int font_nr2 = font_to_graphic[j].font_nr;
473 int special2 = font_to_graphic[j].special;
474 int graphic2 = font_to_graphic[j].graphic;
476 if (IS_SPECIAL_GFX_ARG(special2) &&
477 graphic2 == graphic_info[graphic].clone_from)
479 font_info[font_nr].special_graphic[special] =
480 font_info[font_nr2].special_graphic[special2];
481 font_info[font_nr].special_bitmap_id[special] =
482 font_info[font_nr2].special_bitmap_id[special2];
489 /* reset non-redefined ".active" font graphics if normal font is redefined */
490 /* (this different treatment is needed because normal and active fonts are
491 independently defined ("active" is not a property of font definitions!) */
492 for (i = 0; i < NUM_FONTS; i++)
494 int font_nr_base = i;
495 int font_nr_active = FONT_ACTIVE(font_nr_base);
497 /* check only those fonts with exist as normal and ".active" variant */
498 if (font_nr_base != font_nr_active)
500 int base_graphic = font_info[font_nr_base].graphic;
501 int active_graphic = font_info[font_nr_active].graphic;
502 boolean base_redefined =
503 getImageListEntryFromImageID(base_graphic)->redefined;
504 boolean active_redefined =
505 getImageListEntryFromImageID(active_graphic)->redefined;
507 /* if the base font ("font.menu_1", for example) has been redefined,
508 but not the active font ("font.menu_1.active", for example), do not
509 use an existing (in this case considered obsolete) active font
510 anymore, but use the automatically determined default font */
511 if (base_redefined && !active_redefined)
512 font_info[font_nr_active].graphic = base_graphic;
514 /* now also check each "special" font (which may be the same as above) */
515 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
517 int base_graphic = font_info[font_nr_base].special_graphic[j];
518 int active_graphic = font_info[font_nr_active].special_graphic[j];
519 boolean base_redefined =
520 getImageListEntryFromImageID(base_graphic)->redefined;
521 boolean active_redefined =
522 getImageListEntryFromImageID(active_graphic)->redefined;
524 /* same as above, but check special graphic definitions, for example:
525 redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN" */
526 if (base_redefined && !active_redefined)
528 font_info[font_nr_active].special_graphic[j] =
529 font_info[font_nr_base].special_graphic[j];
530 font_info[font_nr_active].special_bitmap_id[j] =
531 font_info[font_nr_base].special_bitmap_id[j];
537 /* ---------- initialize font bitmap array ---------- */
539 if (font_bitmap_info != NULL)
540 FreeFontInfo(font_bitmap_info);
543 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
545 /* ---------- initialize font bitmap definitions ---------- */
547 for (i = 0; i < NUM_FONTS; i++)
549 if (i < NUM_INITIAL_FONTS)
551 font_bitmap_info[i] = font_initial[i];
555 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
557 int font_bitmap_id = font_info[i].special_bitmap_id[j];
558 int graphic = font_info[i].special_graphic[j];
560 /* set 'graphic_info' for font entries, if uninitialized (guessed) */
561 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
563 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
564 graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
567 /* copy font relevant information from graphics information */
568 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
569 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
570 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
571 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
572 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
574 font_bitmap_info[font_bitmap_id].draw_xoffset =
575 graphic_info[graphic].draw_xoffset;
576 font_bitmap_info[font_bitmap_id].draw_yoffset =
577 graphic_info[graphic].draw_yoffset;
579 font_bitmap_info[font_bitmap_id].num_chars =
580 graphic_info[graphic].anim_frames;
581 font_bitmap_info[font_bitmap_id].num_chars_per_line =
582 graphic_info[graphic].anim_frames_per_line;
586 InitFontInfo(font_bitmap_info, num_font_bitmaps,
587 getFontBitmapID, getFontFromToken);
590 void InitElementGraphicInfo()
592 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
593 int num_property_mappings = getImageListPropertyMappingSize();
596 if (graphic_info == NULL) /* still at startup phase */
599 /* set values to -1 to identify later as "uninitialized" values */
600 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
602 for (act = 0; act < NUM_ACTIONS; act++)
604 element_info[i].graphic[act] = -1;
605 element_info[i].crumbled[act] = -1;
607 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
609 element_info[i].direction_graphic[act][dir] = -1;
610 element_info[i].direction_crumbled[act][dir] = -1;
617 /* initialize normal element/graphic mapping from static configuration */
618 for (i = 0; element_to_graphic[i].element > -1; i++)
620 int element = element_to_graphic[i].element;
621 int action = element_to_graphic[i].action;
622 int direction = element_to_graphic[i].direction;
623 boolean crumbled = element_to_graphic[i].crumbled;
624 int graphic = element_to_graphic[i].graphic;
625 int base_graphic = el2baseimg(element);
627 if (graphic_info[graphic].bitmap == NULL)
630 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
633 boolean base_redefined =
634 getImageListEntryFromImageID(base_graphic)->redefined;
635 boolean act_dir_redefined =
636 getImageListEntryFromImageID(graphic)->redefined;
638 /* if the base graphic ("emerald", for example) has been redefined,
639 but not the action graphic ("emerald.falling", for example), do not
640 use an existing (in this case considered obsolete) action graphic
641 anymore, but use the automatically determined default graphic */
642 if (base_redefined && !act_dir_redefined)
647 action = ACTION_DEFAULT;
652 element_info[element].direction_crumbled[action][direction] = graphic;
654 element_info[element].crumbled[action] = graphic;
659 element_info[element].direction_graphic[action][direction] = graphic;
661 element_info[element].graphic[action] = graphic;
665 /* initialize normal element/graphic mapping from dynamic configuration */
666 for (i = 0; i < num_property_mappings; i++)
668 int element = property_mapping[i].base_index;
669 int action = property_mapping[i].ext1_index;
670 int direction = property_mapping[i].ext2_index;
671 int special = property_mapping[i].ext3_index;
672 int graphic = property_mapping[i].artwork_index;
673 boolean crumbled = FALSE;
676 if ((element == EL_EM_DYNAMITE ||
677 element == EL_EM_DYNAMITE_ACTIVE) &&
678 action == ACTION_ACTIVE &&
679 (special == GFX_SPECIAL_ARG_EDITOR ||
680 special == GFX_SPECIAL_ARG_PANEL))
681 printf("::: DYNAMIC: %d, %d, %d -> %d\n",
682 element, action, special, graphic);
685 if (special == GFX_SPECIAL_ARG_CRUMBLED)
691 if (graphic_info[graphic].bitmap == NULL)
694 if (element >= MAX_NUM_ELEMENTS || special != -1)
698 action = ACTION_DEFAULT;
703 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
704 element_info[element].direction_crumbled[action][dir] = -1;
707 element_info[element].direction_crumbled[action][direction] = graphic;
709 element_info[element].crumbled[action] = graphic;
714 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
715 element_info[element].direction_graphic[action][dir] = -1;
718 element_info[element].direction_graphic[action][direction] = graphic;
720 element_info[element].graphic[action] = graphic;
724 /* now copy all graphics that are defined to be cloned from other graphics */
725 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
727 int graphic = element_info[i].graphic[ACTION_DEFAULT];
728 int crumbled_like, diggable_like;
733 crumbled_like = graphic_info[graphic].crumbled_like;
734 diggable_like = graphic_info[graphic].diggable_like;
736 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
738 for (act = 0; act < NUM_ACTIONS; act++)
739 element_info[i].crumbled[act] =
740 element_info[crumbled_like].crumbled[act];
741 for (act = 0; act < NUM_ACTIONS; act++)
742 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
743 element_info[i].direction_crumbled[act][dir] =
744 element_info[crumbled_like].direction_crumbled[act][dir];
747 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
749 element_info[i].graphic[ACTION_DIGGING] =
750 element_info[diggable_like].graphic[ACTION_DIGGING];
751 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
752 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
753 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
758 /* set hardcoded definitions for some runtime elements without graphic */
759 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
763 /* set hardcoded definitions for some internal elements without graphic */
764 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
766 if (IS_EDITOR_CASCADE_INACTIVE(i))
767 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
768 else if (IS_EDITOR_CASCADE_ACTIVE(i))
769 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
773 /* now set all undefined/invalid graphics to -1 to set to default after it */
774 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
776 for (act = 0; act < NUM_ACTIONS; act++)
780 graphic = element_info[i].graphic[act];
781 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
782 element_info[i].graphic[act] = -1;
784 graphic = element_info[i].crumbled[act];
785 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
786 element_info[i].crumbled[act] = -1;
788 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
790 graphic = element_info[i].direction_graphic[act][dir];
791 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
792 element_info[i].direction_graphic[act][dir] = -1;
794 graphic = element_info[i].direction_crumbled[act][dir];
795 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
796 element_info[i].direction_crumbled[act][dir] = -1;
803 /* adjust graphics with 2nd tile for movement according to direction
804 (do this before correcting '-1' values to minimize calculations) */
805 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
807 for (act = 0; act < NUM_ACTIONS; act++)
809 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
811 int graphic = element_info[i].direction_graphic[act][dir];
812 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
814 if (act == ACTION_FALLING) /* special case */
815 graphic = element_info[i].graphic[act];
818 graphic_info[graphic].double_movement &&
819 graphic_info[graphic].swap_double_tiles != 0)
821 struct GraphicInfo *g = &graphic_info[graphic];
822 int src_x_front = g->src_x;
823 int src_y_front = g->src_y;
824 int src_x_back = g->src_x + g->offset2_x;
825 int src_y_back = g->src_y + g->offset2_y;
826 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
828 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
829 src_y_front < src_y_back);
830 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
831 boolean swap_movement_tiles_autodetected =
832 (!frames_are_ordered_diagonally &&
833 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
834 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
835 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
836 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
839 /* swap frontside and backside graphic tile coordinates, if needed */
840 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
842 /* get current (wrong) backside tile coordinates */
843 getGraphicSourceExt(graphic, 0, &dummy, &src_x_back, &src_y_back,
846 /* set frontside tile coordinates to backside tile coordinates */
847 g->src_x = src_x_back;
848 g->src_y = src_y_back;
850 /* invert tile offset to point to new backside tile coordinates */
854 /* do not swap front and backside tiles again after correction */
855 g->swap_double_tiles = 0;
864 /* now set all '-1' values to element specific default values */
865 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
867 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
868 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
869 int default_direction_graphic[NUM_DIRECTIONS_FULL];
870 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
872 if (default_graphic == -1)
873 default_graphic = IMG_UNKNOWN;
875 if (default_crumbled == -1)
876 default_crumbled = default_graphic;
878 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
879 if (default_crumbled == -1)
880 default_crumbled = IMG_EMPTY;
883 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
885 default_direction_graphic[dir] =
886 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
887 default_direction_crumbled[dir] =
888 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
890 if (default_direction_graphic[dir] == -1)
891 default_direction_graphic[dir] = default_graphic;
893 if (default_direction_crumbled[dir] == -1)
894 default_direction_crumbled[dir] = default_direction_graphic[dir];
896 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
897 if (default_direction_crumbled[dir] == -1)
898 default_direction_crumbled[dir] = default_crumbled;
902 for (act = 0; act < NUM_ACTIONS; act++)
904 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
905 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
906 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
907 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
908 act == ACTION_TURNING_FROM_RIGHT ||
909 act == ACTION_TURNING_FROM_UP ||
910 act == ACTION_TURNING_FROM_DOWN);
912 /* generic default action graphic (defined by "[default]" directive) */
913 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
914 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
915 int default_remove_graphic = IMG_EMPTY;
917 if (act_remove && default_action_graphic != -1)
918 default_remove_graphic = default_action_graphic;
920 /* look for special default action graphic (classic game specific) */
921 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
922 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
923 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
924 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
925 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
926 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
928 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
929 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
930 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
931 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
932 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
933 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
936 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
937 /* !!! make this better !!! */
938 if (i == EL_EMPTY_SPACE)
940 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
941 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
945 if (default_action_graphic == -1)
946 default_action_graphic = default_graphic;
948 if (default_action_crumbled == -1)
949 default_action_crumbled = default_action_graphic;
951 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
952 if (default_action_crumbled == -1)
953 default_action_crumbled = default_crumbled;
956 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
958 /* use action graphic as the default direction graphic, if undefined */
959 int default_action_direction_graphic = element_info[i].graphic[act];
960 int default_action_direction_crumbled = element_info[i].crumbled[act];
962 /* no graphic for current action -- use default direction graphic */
963 if (default_action_direction_graphic == -1)
964 default_action_direction_graphic =
965 (act_remove ? default_remove_graphic :
967 element_info[i].direction_graphic[ACTION_TURNING][dir] :
968 default_action_graphic != default_graphic ?
969 default_action_graphic :
970 default_direction_graphic[dir]);
972 if (element_info[i].direction_graphic[act][dir] == -1)
973 element_info[i].direction_graphic[act][dir] =
974 default_action_direction_graphic;
977 if (default_action_direction_crumbled == -1)
978 default_action_direction_crumbled =
979 element_info[i].direction_graphic[act][dir];
981 if (default_action_direction_crumbled == -1)
982 default_action_direction_crumbled =
983 (act_remove ? default_remove_graphic :
985 element_info[i].direction_crumbled[ACTION_TURNING][dir] :
986 default_action_crumbled != default_crumbled ?
987 default_action_crumbled :
988 default_direction_crumbled[dir]);
991 if (element_info[i].direction_crumbled[act][dir] == -1)
992 element_info[i].direction_crumbled[act][dir] =
993 default_action_direction_crumbled;
996 /* no graphic for this specific action -- use default action graphic */
997 if (element_info[i].graphic[act] == -1)
998 element_info[i].graphic[act] =
999 (act_remove ? default_remove_graphic :
1000 act_turning ? element_info[i].graphic[ACTION_TURNING] :
1001 default_action_graphic);
1003 if (element_info[i].crumbled[act] == -1)
1004 element_info[i].crumbled[act] = element_info[i].graphic[act];
1006 if (element_info[i].crumbled[act] == -1)
1007 element_info[i].crumbled[act] =
1008 (act_remove ? default_remove_graphic :
1009 act_turning ? element_info[i].crumbled[ACTION_TURNING] :
1010 default_action_crumbled);
1015 UPDATE_BUSY_STATE();
1018 /* !!! THIS ALSO CLEARS SPECIAL FLAGS (AND IS NOT NEEDED ANYWAY) !!! */
1019 /* set animation mode to "none" for each graphic with only 1 frame */
1020 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1022 for (act = 0; act < NUM_ACTIONS; act++)
1024 int graphic = element_info[i].graphic[act];
1025 int crumbled = element_info[i].crumbled[act];
1027 if (graphic_info[graphic].anim_frames == 1)
1028 graphic_info[graphic].anim_mode = ANIM_NONE;
1029 if (graphic_info[crumbled].anim_frames == 1)
1030 graphic_info[crumbled].anim_mode = ANIM_NONE;
1032 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1034 graphic = element_info[i].direction_graphic[act][dir];
1035 crumbled = element_info[i].direction_crumbled[act][dir];
1037 if (graphic_info[graphic].anim_frames == 1)
1038 graphic_info[graphic].anim_mode = ANIM_NONE;
1039 if (graphic_info[crumbled].anim_frames == 1)
1040 graphic_info[crumbled].anim_mode = ANIM_NONE;
1048 if (options.verbose)
1050 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1051 if (element_info[i].graphic[ACTION_DEFAULT] == IMG_UNKNOWN &&
1053 Error(ERR_INFO, "warning: no graphic for element '%s' (%d)",
1054 element_info[i].token_name, i);
1060 void InitElementSpecialGraphicInfo()
1062 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
1063 int num_property_mappings = getImageListPropertyMappingSize();
1066 /* always start with reliable default values */
1067 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1068 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1069 element_info[i].special_graphic[j] =
1070 element_info[i].graphic[ACTION_DEFAULT];
1072 /* initialize special element/graphic mapping from static configuration */
1073 for (i = 0; element_to_special_graphic[i].element > -1; i++)
1075 int element = element_to_special_graphic[i].element;
1076 int special = element_to_special_graphic[i].special;
1077 int graphic = element_to_special_graphic[i].graphic;
1078 int base_graphic = el2baseimg(element);
1079 boolean base_redefined =
1080 getImageListEntryFromImageID(base_graphic)->redefined;
1081 boolean special_redefined =
1082 getImageListEntryFromImageID(graphic)->redefined;
1085 if ((element == EL_EM_DYNAMITE ||
1086 element == EL_EM_DYNAMITE_ACTIVE) &&
1087 (special == GFX_SPECIAL_ARG_EDITOR ||
1088 special == GFX_SPECIAL_ARG_PANEL))
1089 printf("::: SPECIAL STATIC: %d, %d -> %d\n",
1090 element, special, graphic);
1093 /* if the base graphic ("emerald", for example) has been redefined,
1094 but not the special graphic ("emerald.EDITOR", for example), do not
1095 use an existing (in this case considered obsolete) special graphic
1096 anymore, but use the automatically created (down-scaled) graphic */
1097 if (base_redefined && !special_redefined)
1100 element_info[element].special_graphic[special] = graphic;
1103 /* initialize special element/graphic mapping from dynamic configuration */
1104 for (i = 0; i < num_property_mappings; i++)
1106 int element = property_mapping[i].base_index;
1107 int action = property_mapping[i].ext1_index;
1108 int direction = property_mapping[i].ext2_index;
1109 int special = property_mapping[i].ext3_index;
1110 int graphic = property_mapping[i].artwork_index;
1113 if ((element == EL_EM_DYNAMITE ||
1114 element == EL_EM_DYNAMITE_ACTIVE ||
1115 element == EL_CONVEYOR_BELT_1_MIDDLE ||
1116 element == EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE) &&
1117 (special == GFX_SPECIAL_ARG_EDITOR ||
1118 special == GFX_SPECIAL_ARG_PANEL))
1119 printf("::: SPECIAL DYNAMIC: %d, %d -> %d [%d]\n",
1120 element, special, graphic, property_mapping[i].ext1_index);
1124 if (element == EL_CONVEYOR_BELT_1_MIDDLE &&
1125 action == ACTION_ACTIVE)
1127 element = EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE;
1133 if (element == EL_MAGIC_WALL &&
1134 action == ACTION_ACTIVE)
1136 element = EL_MAGIC_WALL_ACTIVE;
1142 /* for action ".active", replace element with active element, if exists */
1143 if (action == ACTION_ACTIVE && element != ELEMENT_ACTIVE(element))
1145 element = ELEMENT_ACTIVE(element);
1150 if (element >= MAX_NUM_ELEMENTS)
1153 /* do not change special graphic if action or direction was specified */
1154 if (action != -1 || direction != -1)
1157 if (IS_SPECIAL_GFX_ARG(special))
1158 element_info[element].special_graphic[special] = graphic;
1161 /* now set all undefined/invalid graphics to default */
1162 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1163 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1164 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
1165 element_info[i].special_graphic[j] =
1166 element_info[i].graphic[ACTION_DEFAULT];
1169 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
1171 if (type != TYPE_ELEMENT && type != TYPE_GRAPHIC)
1172 return get_parameter_value(value_raw, suffix, type);
1174 if (strEqual(value_raw, ARG_UNDEFINED))
1175 return ARG_UNDEFINED_VALUE;
1178 if (type == TYPE_ELEMENT)
1180 char *value = getHashEntry(element_token_hash, value_raw);
1182 return (value != NULL ? atoi(value) : EL_UNDEFINED);
1184 else if (type == TYPE_GRAPHIC)
1186 char *value = getHashEntry(graphic_token_hash, value_raw);
1188 return (value != NULL ? atoi(value) : IMG_UNDEFINED);
1196 /* !!! THIS IS BUGGY !!! NOT SURE IF YOU GET ELEMENT ID OR GRAPHIC ID !!! */
1197 /* !!! (possible reason why ".clone_from" with elements doesn't work) !!! */
1199 /* !!! OPTIMIZE THIS BY USING HASH !!! */
1200 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1201 if (strEqual(element_info[i].token_name, value_raw))
1204 /* !!! OPTIMIZE THIS BY USING HASH !!! */
1205 for (i = 0; image_config[i].token != NULL; i++)
1207 int len_config_value = strlen(image_config[i].value);
1209 if (!strEqual(&image_config[i].value[len_config_value - 4], ".pcx") &&
1210 !strEqual(&image_config[i].value[len_config_value - 4], ".wav") &&
1211 !strEqual(image_config[i].value, UNDEFINED_FILENAME))
1214 if (strEqual(image_config[i].token, value_raw))
1224 static int get_scaled_graphic_width(int graphic)
1226 int original_width = getOriginalImageWidthFromImageID(graphic);
1227 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1229 return original_width * scale_up_factor;
1232 static int get_scaled_graphic_height(int graphic)
1234 int original_height = getOriginalImageHeightFromImageID(graphic);
1235 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1237 return original_height * scale_up_factor;
1240 static void set_graphic_parameters_ext(int graphic, struct GraphicInfo *g,
1241 int *parameter, Bitmap *src_bitmap)
1243 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1244 int anim_frames_per_line = 1;
1246 /* always start with reliable default values */
1247 g->src_image_width = 0;
1248 g->src_image_height = 0;
1251 g->width = TILEX; /* default for element graphics */
1252 g->height = TILEY; /* default for element graphics */
1253 g->offset_x = 0; /* one or both of these values ... */
1254 g->offset_y = 0; /* ... will be corrected later */
1255 g->offset2_x = 0; /* one or both of these values ... */
1256 g->offset2_y = 0; /* ... will be corrected later */
1257 g->swap_double_tiles = -1; /* auto-detect tile swapping */
1258 g->crumbled_like = -1; /* do not use clone element */
1259 g->diggable_like = -1; /* do not use clone element */
1260 g->border_size = TILEX / 8; /* "CRUMBLED" border size */
1261 g->scale_up_factor = 1; /* default: no scaling up */
1262 g->clone_from = -1; /* do not use clone graphic */
1263 g->anim_delay_fixed = 0;
1264 g->anim_delay_random = 0;
1265 g->post_delay_fixed = 0;
1266 g->post_delay_random = 0;
1267 g->fade_mode = FADE_MODE_DEFAULT;
1271 g->align = ALIGN_CENTER; /* default for title screens */
1272 g->valign = VALIGN_MIDDLE; /* default for title screens */
1273 g->sort_priority = 0; /* default for title screens */
1275 g->bitmap = src_bitmap;
1278 /* optional zoom factor for scaling up the image to a larger size */
1279 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1280 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1281 if (g->scale_up_factor < 1)
1282 g->scale_up_factor = 1; /* no scaling */
1286 if (g->use_image_size)
1288 /* set new default bitmap size (with scaling, but without small images) */
1289 g->width = get_scaled_graphic_width(graphic);
1290 g->height = get_scaled_graphic_height(graphic);
1294 /* optional x and y tile position of animation frame sequence */
1295 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1296 g->src_x = parameter[GFX_ARG_XPOS] * TILEX;
1297 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1298 g->src_y = parameter[GFX_ARG_YPOS] * TILEY;
1300 /* optional x and y pixel position of animation frame sequence */
1301 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1302 g->src_x = parameter[GFX_ARG_X];
1303 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1304 g->src_y = parameter[GFX_ARG_Y];
1306 /* optional width and height of each animation frame */
1307 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1308 g->width = parameter[GFX_ARG_WIDTH];
1309 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1310 g->height = parameter[GFX_ARG_HEIGHT];
1313 /* optional zoom factor for scaling up the image to a larger size */
1314 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1315 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1316 if (g->scale_up_factor < 1)
1317 g->scale_up_factor = 1; /* no scaling */
1322 /* get final bitmap size (with scaling, but without small images) */
1323 int src_image_width = get_scaled_graphic_width(graphic);
1324 int src_image_height = get_scaled_graphic_height(graphic);
1326 anim_frames_per_row = src_image_width / g->width;
1327 anim_frames_per_col = src_image_height / g->height;
1329 g->src_image_width = src_image_width;
1330 g->src_image_height = src_image_height;
1333 /* correct x or y offset dependent of vertical or horizontal frame order */
1334 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1336 g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1337 parameter[GFX_ARG_OFFSET] : g->height);
1338 anim_frames_per_line = anim_frames_per_col;
1340 else /* frames are ordered horizontally */
1342 g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1343 parameter[GFX_ARG_OFFSET] : g->width);
1344 anim_frames_per_line = anim_frames_per_row;
1347 /* optionally, the x and y offset of frames can be specified directly */
1348 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1349 g->offset_x = parameter[GFX_ARG_XOFFSET];
1350 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1351 g->offset_y = parameter[GFX_ARG_YOFFSET];
1353 /* optionally, moving animations may have separate start and end graphics */
1354 g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1356 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1357 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1359 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1360 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1361 g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1362 parameter[GFX_ARG_2ND_OFFSET] : g->height);
1363 else /* frames are ordered horizontally */
1364 g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1365 parameter[GFX_ARG_2ND_OFFSET] : g->width);
1367 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1368 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1369 g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1370 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1371 g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1373 /* optionally, the second movement tile can be specified as start tile */
1374 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1375 g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1377 /* automatically determine correct number of frames, if not defined */
1378 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1379 g->anim_frames = parameter[GFX_ARG_FRAMES];
1380 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1381 g->anim_frames = anim_frames_per_row;
1382 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1383 g->anim_frames = anim_frames_per_col;
1387 if (g->anim_frames == 0) /* frames must be at least 1 */
1390 g->anim_frames_per_line =
1391 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1392 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1394 g->anim_delay = parameter[GFX_ARG_DELAY];
1395 if (g->anim_delay == 0) /* delay must be at least 1 */
1398 g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1400 if (g->anim_frames == 1)
1401 g->anim_mode = ANIM_NONE;
1404 /* automatically determine correct start frame, if not defined */
1405 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1406 g->anim_start_frame = 0;
1407 else if (g->anim_mode & ANIM_REVERSE)
1408 g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1410 g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1412 /* animation synchronized with global frame counter, not move position */
1413 g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1415 /* optional element for cloning crumble graphics */
1416 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1417 g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1419 /* optional element for cloning digging graphics */
1420 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1421 g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1423 /* optional border size for "crumbling" diggable graphics */
1424 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1425 g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1427 /* this is only used for player "boring" and "sleeping" actions */
1428 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1429 g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1430 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1431 g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1432 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1433 g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1434 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1435 g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1437 /* this is only used for toon animations */
1438 g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1439 g->step_delay = parameter[GFX_ARG_STEP_DELAY];
1441 /* this is only used for drawing font characters */
1442 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1443 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1445 /* this is only used for drawing envelope graphics */
1446 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1448 /* optional graphic for cloning all graphics settings */
1449 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1450 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1452 /* optional settings for drawing title screens and title messages */
1453 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1454 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1455 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1456 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1457 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1458 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1459 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1460 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1461 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1462 g->align = parameter[GFX_ARG_ALIGN];
1463 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1464 g->valign = parameter[GFX_ARG_VALIGN];
1465 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1466 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1469 static void set_graphic_parameters(int graphic)
1472 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1473 char **parameter_raw = image->parameter;
1474 Bitmap *src_bitmap = getBitmapFromImageID(graphic);
1475 int parameter[NUM_GFX_ARGS];
1478 /* if fallback to default artwork is done, also use the default parameters */
1479 if (image->fallback_to_default)
1480 parameter_raw = image->default_parameter;
1482 /* get integer values from string parameters */
1483 for (i = 0; i < NUM_GFX_ARGS; i++)
1484 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1485 image_config_suffix[i].token,
1486 image_config_suffix[i].type);
1488 set_graphic_parameters_ext(graphic, &graphic_info[graphic],
1489 parameter, src_bitmap);
1493 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1494 char **parameter_raw = image->parameter;
1495 Bitmap *src_bitmap = getBitmapFromImageID(graphic);
1496 int parameter[NUM_GFX_ARGS];
1497 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1498 int anim_frames_per_line = 1;
1501 /* if fallback to default artwork is done, also use the default parameters */
1502 if (image->fallback_to_default)
1503 parameter_raw = image->default_parameter;
1505 /* get integer values from string parameters */
1506 for (i = 0; i < NUM_GFX_ARGS; i++)
1507 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1508 image_config_suffix[i].token,
1509 image_config_suffix[i].type);
1511 graphic_info[graphic].bitmap = src_bitmap;
1513 /* always start with reliable default values */
1514 graphic_info[graphic].src_image_width = 0;
1515 graphic_info[graphic].src_image_height = 0;
1516 graphic_info[graphic].src_x = 0;
1517 graphic_info[graphic].src_y = 0;
1518 graphic_info[graphic].width = TILEX; /* default for element graphics */
1519 graphic_info[graphic].height = TILEY; /* default for element graphics */
1520 graphic_info[graphic].offset_x = 0; /* one or both of these values ... */
1521 graphic_info[graphic].offset_y = 0; /* ... will be corrected later */
1522 graphic_info[graphic].offset2_x = 0; /* one or both of these values ... */
1523 graphic_info[graphic].offset2_y = 0; /* ... will be corrected later */
1524 graphic_info[graphic].swap_double_tiles = -1; /* auto-detect tile swapping */
1525 graphic_info[graphic].crumbled_like = -1; /* do not use clone element */
1526 graphic_info[graphic].diggable_like = -1; /* do not use clone element */
1527 graphic_info[graphic].border_size = TILEX / 8; /* "CRUMBLED" border size */
1528 graphic_info[graphic].scale_up_factor = 1; /* default: no scaling up */
1529 graphic_info[graphic].clone_from = -1; /* do not use clone graphic */
1530 graphic_info[graphic].anim_delay_fixed = 0;
1531 graphic_info[graphic].anim_delay_random = 0;
1532 graphic_info[graphic].post_delay_fixed = 0;
1533 graphic_info[graphic].post_delay_random = 0;
1534 graphic_info[graphic].fade_mode = FADE_MODE_DEFAULT;
1535 graphic_info[graphic].fade_delay = -1;
1536 graphic_info[graphic].post_delay = -1;
1537 graphic_info[graphic].auto_delay = -1;
1538 graphic_info[graphic].align = ALIGN_CENTER; /* default for title screens */
1539 graphic_info[graphic].valign = VALIGN_MIDDLE; /* default for title screens */
1540 graphic_info[graphic].sort_priority = 0; /* default for title screens */
1543 /* optional zoom factor for scaling up the image to a larger size */
1544 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1545 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1546 if (graphic_info[graphic].scale_up_factor < 1)
1547 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
1551 if (graphic_info[graphic].use_image_size)
1553 /* set new default bitmap size (with scaling, but without small images) */
1554 graphic_info[graphic].width = get_scaled_graphic_width(graphic);
1555 graphic_info[graphic].height = get_scaled_graphic_height(graphic);
1559 /* optional x and y tile position of animation frame sequence */
1560 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1561 graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
1562 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1563 graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
1565 /* optional x and y pixel position of animation frame sequence */
1566 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1567 graphic_info[graphic].src_x = parameter[GFX_ARG_X];
1568 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1569 graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
1571 /* optional width and height of each animation frame */
1572 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1573 graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
1574 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1575 graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
1578 /* optional zoom factor for scaling up the image to a larger size */
1579 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1580 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1581 if (graphic_info[graphic].scale_up_factor < 1)
1582 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
1587 /* get final bitmap size (with scaling, but without small images) */
1588 int src_image_width = get_scaled_graphic_width(graphic);
1589 int src_image_height = get_scaled_graphic_height(graphic);
1591 anim_frames_per_row = src_image_width / graphic_info[graphic].width;
1592 anim_frames_per_col = src_image_height / graphic_info[graphic].height;
1594 graphic_info[graphic].src_image_width = src_image_width;
1595 graphic_info[graphic].src_image_height = src_image_height;
1598 /* correct x or y offset dependent of vertical or horizontal frame order */
1599 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1601 graphic_info[graphic].offset_y =
1602 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1603 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
1604 anim_frames_per_line = anim_frames_per_col;
1606 else /* frames are ordered horizontally */
1608 graphic_info[graphic].offset_x =
1609 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1610 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
1611 anim_frames_per_line = anim_frames_per_row;
1614 /* optionally, the x and y offset of frames can be specified directly */
1615 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1616 graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
1617 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1618 graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
1620 /* optionally, moving animations may have separate start and end graphics */
1621 graphic_info[graphic].double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1623 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1624 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1626 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1627 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1628 graphic_info[graphic].offset2_y =
1629 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1630 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].height);
1631 else /* frames are ordered horizontally */
1632 graphic_info[graphic].offset2_x =
1633 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1634 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].width);
1636 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1637 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1638 graphic_info[graphic].offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1639 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1640 graphic_info[graphic].offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1642 /* optionally, the second movement tile can be specified as start tile */
1643 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1644 graphic_info[graphic].swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1646 /* automatically determine correct number of frames, if not defined */
1647 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1648 graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
1649 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1650 graphic_info[graphic].anim_frames = anim_frames_per_row;
1651 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1652 graphic_info[graphic].anim_frames = anim_frames_per_col;
1654 graphic_info[graphic].anim_frames = 1;
1656 if (graphic_info[graphic].anim_frames == 0) /* frames must be at least 1 */
1657 graphic_info[graphic].anim_frames = 1;
1659 graphic_info[graphic].anim_frames_per_line =
1660 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1661 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1663 graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
1664 if (graphic_info[graphic].anim_delay == 0) /* delay must be at least 1 */
1665 graphic_info[graphic].anim_delay = 1;
1667 graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
1669 if (graphic_info[graphic].anim_frames == 1)
1670 graphic_info[graphic].anim_mode = ANIM_NONE;
1673 /* automatically determine correct start frame, if not defined */
1674 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1675 graphic_info[graphic].anim_start_frame = 0;
1676 else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
1677 graphic_info[graphic].anim_start_frame =
1678 graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1680 graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
1682 /* animation synchronized with global frame counter, not move position */
1683 graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1685 /* optional element for cloning crumble graphics */
1686 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1687 graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1689 /* optional element for cloning digging graphics */
1690 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1691 graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1693 /* optional border size for "crumbling" diggable graphics */
1694 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1695 graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
1697 /* this is only used for player "boring" and "sleeping" actions */
1698 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1699 graphic_info[graphic].anim_delay_fixed =
1700 parameter[GFX_ARG_ANIM_DELAY_FIXED];
1701 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1702 graphic_info[graphic].anim_delay_random =
1703 parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1704 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1705 graphic_info[graphic].post_delay_fixed =
1706 parameter[GFX_ARG_POST_DELAY_FIXED];
1707 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1708 graphic_info[graphic].post_delay_random =
1709 parameter[GFX_ARG_POST_DELAY_RANDOM];
1711 /* this is only used for toon animations */
1712 graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
1713 graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY];
1715 /* this is only used for drawing font characters */
1716 graphic_info[graphic].draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1717 graphic_info[graphic].draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1719 /* this is only used for drawing envelope graphics */
1720 graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1722 /* optional graphic for cloning all graphics settings */
1723 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1724 graphic_info[graphic].clone_from = parameter[GFX_ARG_CLONE_FROM];
1726 /* optional settings for drawing title screens and title messages */
1727 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1728 graphic_info[graphic].fade_mode = parameter[GFX_ARG_FADE_MODE];
1729 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1730 graphic_info[graphic].fade_delay = parameter[GFX_ARG_FADE_DELAY];
1731 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1732 graphic_info[graphic].post_delay = parameter[GFX_ARG_POST_DELAY];
1733 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1734 graphic_info[graphic].auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1735 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1736 graphic_info[graphic].align = parameter[GFX_ARG_ALIGN];
1737 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1738 graphic_info[graphic].valign = parameter[GFX_ARG_VALIGN];
1739 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1740 graphic_info[graphic].sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1743 UPDATE_BUSY_STATE();
1746 static void set_cloned_graphic_parameters(int graphic)
1748 int fallback_graphic = IMG_CHAR_EXCLAM;
1749 int max_num_images = getImageListSize();
1750 int clone_graphic = graphic_info[graphic].clone_from;
1751 int num_references_followed = 1;
1753 while (graphic_info[clone_graphic].clone_from != -1 &&
1754 num_references_followed < max_num_images)
1756 clone_graphic = graphic_info[clone_graphic].clone_from;
1758 num_references_followed++;
1761 if (num_references_followed >= max_num_images)
1763 Error(ERR_INFO_LINE, "-");
1764 Error(ERR_INFO, "warning: error found in config file:");
1765 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1766 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1767 Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1768 Error(ERR_INFO, "custom graphic rejected for this element/action");
1770 if (graphic == fallback_graphic)
1771 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1773 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1774 Error(ERR_INFO_LINE, "-");
1776 graphic_info[graphic] = graphic_info[fallback_graphic];
1780 graphic_info[graphic] = graphic_info[clone_graphic];
1781 graphic_info[graphic].clone_from = clone_graphic;
1785 static void InitGraphicInfo()
1787 int fallback_graphic = IMG_CHAR_EXCLAM;
1788 int num_images = getImageListSize();
1791 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1792 static boolean clipmasks_initialized = FALSE;
1794 XGCValues clip_gc_values;
1795 unsigned long clip_gc_valuemask;
1796 GC copy_clipmask_gc = None;
1799 /* use image size as default values for width and height for these images */
1800 static int full_size_graphics[] =
1805 IMG_BACKGROUND_ENVELOPE_1,
1806 IMG_BACKGROUND_ENVELOPE_2,
1807 IMG_BACKGROUND_ENVELOPE_3,
1808 IMG_BACKGROUND_ENVELOPE_4,
1811 IMG_BACKGROUND_TITLE_INITIAL,
1812 IMG_BACKGROUND_TITLE,
1813 IMG_BACKGROUND_MAIN,
1814 IMG_BACKGROUND_LEVELS,
1815 IMG_BACKGROUND_SCORES,
1816 IMG_BACKGROUND_EDITOR,
1817 IMG_BACKGROUND_INFO,
1818 IMG_BACKGROUND_INFO_ELEMENTS,
1819 IMG_BACKGROUND_INFO_MUSIC,
1820 IMG_BACKGROUND_INFO_CREDITS,
1821 IMG_BACKGROUND_INFO_PROGRAM,
1822 IMG_BACKGROUND_INFO_LEVELSET,
1823 IMG_BACKGROUND_SETUP,
1824 IMG_BACKGROUND_DOOR,
1826 IMG_TITLESCREEN_INITIAL_1,
1827 IMG_TITLESCREEN_INITIAL_2,
1828 IMG_TITLESCREEN_INITIAL_3,
1829 IMG_TITLESCREEN_INITIAL_4,
1830 IMG_TITLESCREEN_INITIAL_5,
1840 checked_free(graphic_info);
1842 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1845 /* initialize "use_image_size" flag with default value */
1846 for (i = 0; i < num_images; i++)
1847 graphic_info[i].use_image_size = FALSE;
1849 /* initialize "use_image_size" flag from static configuration above */
1850 for (i = 0; full_size_graphics[i] != -1; i++)
1851 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1854 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1855 if (clipmasks_initialized)
1857 for (i = 0; i < num_images; i++)
1859 if (graphic_info[i].clip_mask)
1860 XFreePixmap(display, graphic_info[i].clip_mask);
1861 if (graphic_info[i].clip_gc)
1862 XFreeGC(display, graphic_info[i].clip_gc);
1864 graphic_info[i].clip_mask = None;
1865 graphic_info[i].clip_gc = None;
1870 /* first set all graphic paramaters ... */
1871 for (i = 0; i < num_images; i++)
1872 set_graphic_parameters(i);
1874 /* ... then copy these parameters for cloned graphics */
1875 for (i = 0; i < num_images; i++)
1876 if (graphic_info[i].clone_from != -1)
1877 set_cloned_graphic_parameters(i);
1879 for (i = 0; i < num_images; i++)
1884 int first_frame, last_frame;
1885 int src_bitmap_width, src_bitmap_height;
1887 /* now check if no animation frames are outside of the loaded image */
1889 if (graphic_info[i].bitmap == NULL)
1890 continue; /* skip check for optional images that are undefined */
1892 /* get image size (this can differ from the standard element tile size!) */
1893 width = graphic_info[i].width;
1894 height = graphic_info[i].height;
1896 /* get final bitmap size (with scaling, but without small images) */
1897 src_bitmap_width = graphic_info[i].src_image_width;
1898 src_bitmap_height = graphic_info[i].src_image_height;
1900 /* check if first animation frame is inside specified bitmap */
1903 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1906 /* this avoids calculating wrong start position for out-of-bounds frame */
1907 src_x = graphic_info[i].src_x;
1908 src_y = graphic_info[i].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: first animation frame out of bounds (%d, %d) [%d, %d]",
1922 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 /* check if last animation frame is inside specified bitmap */
1936 last_frame = graphic_info[i].anim_frames - 1;
1937 getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1939 if (src_x < 0 || src_y < 0 ||
1940 src_x + width > src_bitmap_width ||
1941 src_y + height > src_bitmap_height)
1943 Error(ERR_INFO_LINE, "-");
1944 Error(ERR_INFO, "warning: error found in config file:");
1945 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1946 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1947 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1949 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1950 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1951 Error(ERR_INFO, "custom graphic rejected for this element/action");
1953 if (i == fallback_graphic)
1954 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1956 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1957 Error(ERR_INFO_LINE, "-");
1959 graphic_info[i] = graphic_info[fallback_graphic];
1962 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1963 /* currently we only need a tile clip mask from the first frame */
1964 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1966 if (copy_clipmask_gc == None)
1968 clip_gc_values.graphics_exposures = False;
1969 clip_gc_valuemask = GCGraphicsExposures;
1970 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
1971 clip_gc_valuemask, &clip_gc_values);
1974 graphic_info[i].clip_mask =
1975 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
1977 src_pixmap = src_bitmap->clip_mask;
1978 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
1979 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
1981 clip_gc_values.graphics_exposures = False;
1982 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
1983 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
1985 graphic_info[i].clip_gc =
1986 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
1990 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1991 if (copy_clipmask_gc)
1992 XFreeGC(display, copy_clipmask_gc);
1994 clipmasks_initialized = TRUE;
1998 static void InitElementSoundInfo()
2000 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
2001 int num_property_mappings = getSoundListPropertyMappingSize();
2004 /* set values to -1 to identify later as "uninitialized" values */
2005 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2006 for (act = 0; act < NUM_ACTIONS; act++)
2007 element_info[i].sound[act] = -1;
2009 /* initialize element/sound mapping from static configuration */
2010 for (i = 0; element_to_sound[i].element > -1; i++)
2012 int element = element_to_sound[i].element;
2013 int action = element_to_sound[i].action;
2014 int sound = element_to_sound[i].sound;
2015 boolean is_class = element_to_sound[i].is_class;
2018 action = ACTION_DEFAULT;
2021 element_info[element].sound[action] = sound;
2023 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2024 if (strEqual(element_info[j].class_name,
2025 element_info[element].class_name))
2026 element_info[j].sound[action] = sound;
2029 /* initialize element class/sound mapping from dynamic configuration */
2030 for (i = 0; i < num_property_mappings; i++)
2032 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
2033 int action = property_mapping[i].ext1_index;
2034 int sound = property_mapping[i].artwork_index;
2036 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
2040 action = ACTION_DEFAULT;
2042 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2043 if (strEqual(element_info[j].class_name,
2044 element_info[element_class].class_name))
2045 element_info[j].sound[action] = sound;
2048 /* initialize element/sound mapping from dynamic configuration */
2049 for (i = 0; i < num_property_mappings; i++)
2051 int element = property_mapping[i].base_index;
2052 int action = property_mapping[i].ext1_index;
2053 int sound = property_mapping[i].artwork_index;
2055 if (element >= MAX_NUM_ELEMENTS)
2059 action = ACTION_DEFAULT;
2061 element_info[element].sound[action] = sound;
2064 /* now set all '-1' values to element specific default values */
2065 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2067 for (act = 0; act < NUM_ACTIONS; act++)
2069 /* generic default action sound (defined by "[default]" directive) */
2070 int default_action_sound = element_info[EL_DEFAULT].sound[act];
2072 /* look for special default action sound (classic game specific) */
2073 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
2074 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
2075 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
2076 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
2077 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
2078 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
2080 /* !!! there's no such thing as a "default action sound" !!! */
2082 /* look for element specific default sound (independent from action) */
2083 if (element_info[i].sound[ACTION_DEFAULT] != -1)
2084 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
2088 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
2089 /* !!! make this better !!! */
2090 if (i == EL_EMPTY_SPACE)
2091 default_action_sound = element_info[EL_DEFAULT].sound[act];
2094 /* no sound for this specific action -- use default action sound */
2095 if (element_info[i].sound[act] == -1)
2096 element_info[i].sound[act] = default_action_sound;
2100 /* copy sound settings to some elements that are only stored in level file
2101 in native R'n'D levels, but are used by game engine in native EM levels */
2102 for (i = 0; copy_properties[i][0] != -1; i++)
2103 for (j = 1; j <= 4; j++)
2104 for (act = 0; act < NUM_ACTIONS; act++)
2105 element_info[copy_properties[i][j]].sound[act] =
2106 element_info[copy_properties[i][0]].sound[act];
2109 static void InitGameModeSoundInfo()
2113 /* set values to -1 to identify later as "uninitialized" values */
2114 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2117 /* initialize gamemode/sound mapping from static configuration */
2118 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
2120 int gamemode = gamemode_to_sound[i].gamemode;
2121 int sound = gamemode_to_sound[i].sound;
2124 gamemode = GAME_MODE_DEFAULT;
2126 menu.sound[gamemode] = sound;
2129 /* now set all '-1' values to levelset specific default values */
2130 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2131 if (menu.sound[i] == -1)
2132 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
2135 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2136 if (menu.sound[i] != -1)
2137 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
2141 static void set_sound_parameters(int sound, char **parameter_raw)
2143 int parameter[NUM_SND_ARGS];
2146 /* get integer values from string parameters */
2147 for (i = 0; i < NUM_SND_ARGS; i++)
2149 get_parameter_value(parameter_raw[i],
2150 sound_config_suffix[i].token,
2151 sound_config_suffix[i].type);
2153 /* explicit loop mode setting in configuration overrides default value */
2154 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2155 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
2157 /* sound volume to change the original volume when loading the sound file */
2158 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
2160 /* sound priority to give certain sounds a higher or lower priority */
2161 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
2164 static void InitSoundInfo()
2166 int *sound_effect_properties;
2167 int num_sounds = getSoundListSize();
2170 checked_free(sound_info);
2172 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
2173 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
2175 /* initialize sound effect for all elements to "no sound" */
2176 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2177 for (j = 0; j < NUM_ACTIONS; j++)
2178 element_info[i].sound[j] = SND_UNDEFINED;
2180 for (i = 0; i < num_sounds; i++)
2182 struct FileInfo *sound = getSoundListEntry(i);
2183 int len_effect_text = strlen(sound->token);
2185 sound_effect_properties[i] = ACTION_OTHER;
2186 sound_info[i].loop = FALSE; /* default: play sound only once */
2189 printf("::: sound %d: '%s'\n", i, sound->token);
2192 /* determine all loop sounds and identify certain sound classes */
2194 for (j = 0; element_action_info[j].suffix; j++)
2196 int len_action_text = strlen(element_action_info[j].suffix);
2198 if (len_action_text < len_effect_text &&
2199 strEqual(&sound->token[len_effect_text - len_action_text],
2200 element_action_info[j].suffix))
2202 sound_effect_properties[i] = element_action_info[j].value;
2203 sound_info[i].loop = element_action_info[j].is_loop_sound;
2209 /* associate elements and some selected sound actions */
2211 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2213 if (element_info[j].class_name)
2215 int len_class_text = strlen(element_info[j].class_name);
2217 if (len_class_text + 1 < len_effect_text &&
2218 strncmp(sound->token,
2219 element_info[j].class_name, len_class_text) == 0 &&
2220 sound->token[len_class_text] == '.')
2222 int sound_action_value = sound_effect_properties[i];
2224 element_info[j].sound[sound_action_value] = i;
2229 set_sound_parameters(i, sound->parameter);
2232 free(sound_effect_properties);
2235 static void InitGameModeMusicInfo()
2237 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
2238 int num_property_mappings = getMusicListPropertyMappingSize();
2239 int default_levelset_music = -1;
2242 /* set values to -1 to identify later as "uninitialized" values */
2243 for (i = 0; i < MAX_LEVELS; i++)
2244 levelset.music[i] = -1;
2245 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2248 /* initialize gamemode/music mapping from static configuration */
2249 for (i = 0; gamemode_to_music[i].music > -1; i++)
2251 int gamemode = gamemode_to_music[i].gamemode;
2252 int music = gamemode_to_music[i].music;
2255 printf("::: gamemode == %d, music == %d\n", gamemode, music);
2259 gamemode = GAME_MODE_DEFAULT;
2261 menu.music[gamemode] = music;
2264 /* initialize gamemode/music mapping from dynamic configuration */
2265 for (i = 0; i < num_property_mappings; i++)
2267 int prefix = property_mapping[i].base_index;
2268 int gamemode = property_mapping[i].ext1_index;
2269 int level = property_mapping[i].ext2_index;
2270 int music = property_mapping[i].artwork_index;
2273 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
2274 prefix, gamemode, level, music);
2277 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
2281 gamemode = GAME_MODE_DEFAULT;
2283 /* level specific music only allowed for in-game music */
2284 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
2285 gamemode = GAME_MODE_PLAYING;
2290 default_levelset_music = music;
2293 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
2294 levelset.music[level] = music;
2295 if (gamemode != GAME_MODE_PLAYING)
2296 menu.music[gamemode] = music;
2299 /* now set all '-1' values to menu specific default values */
2300 /* (undefined values of "levelset.music[]" might stay at "-1" to
2301 allow dynamic selection of music files from music directory!) */
2302 for (i = 0; i < MAX_LEVELS; i++)
2303 if (levelset.music[i] == -1)
2304 levelset.music[i] = default_levelset_music;
2305 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2306 if (menu.music[i] == -1)
2307 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
2310 for (i = 0; i < MAX_LEVELS; i++)
2311 if (levelset.music[i] != -1)
2312 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
2313 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2314 if (menu.music[i] != -1)
2315 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
2319 static void set_music_parameters(int music, char **parameter_raw)
2321 int parameter[NUM_MUS_ARGS];
2324 /* get integer values from string parameters */
2325 for (i = 0; i < NUM_MUS_ARGS; i++)
2327 get_parameter_value(parameter_raw[i],
2328 music_config_suffix[i].token,
2329 music_config_suffix[i].type);
2331 /* explicit loop mode setting in configuration overrides default value */
2332 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2333 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
2336 static void InitMusicInfo()
2338 int num_music = getMusicListSize();
2341 checked_free(music_info);
2343 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
2345 for (i = 0; i < num_music; i++)
2347 struct FileInfo *music = getMusicListEntry(i);
2348 int len_music_text = strlen(music->token);
2350 music_info[i].loop = TRUE; /* default: play music in loop mode */
2352 /* determine all loop music */
2354 for (j = 0; music_prefix_info[j].prefix; j++)
2356 int len_prefix_text = strlen(music_prefix_info[j].prefix);
2358 if (len_prefix_text < len_music_text &&
2359 strncmp(music->token,
2360 music_prefix_info[j].prefix, len_prefix_text) == 0)
2362 music_info[i].loop = music_prefix_info[j].is_loop_music;
2368 set_music_parameters(i, music->parameter);
2372 static void ReinitializeGraphics()
2374 print_timestamp_init("ReinitializeGraphics");
2376 InitGraphicInfo(); /* graphic properties mapping */
2377 print_timestamp_time("InitGraphicInfo");
2378 InitElementGraphicInfo(); /* element game graphic mapping */
2379 print_timestamp_time("InitElementGraphicInfo");
2380 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
2381 print_timestamp_time("InitElementSpecialGraphicInfo");
2383 InitElementSmallImages(); /* scale elements to all needed sizes */
2384 print_timestamp_time("InitElementSmallImages");
2385 InitScaledImages(); /* scale all other images, if needed */
2386 print_timestamp_time("InitScaledImages");
2387 InitFontGraphicInfo(); /* initialize text drawing functions */
2388 print_timestamp_time("InitFontGraphicInfo");
2390 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
2391 print_timestamp_time("InitGraphicInfo_EM");
2393 SetMainBackgroundImage(IMG_BACKGROUND);
2394 print_timestamp_time("SetMainBackgroundImage");
2395 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2396 print_timestamp_time("SetDoorBackgroundImage");
2399 print_timestamp_time("InitGadgets");
2401 print_timestamp_time("InitToons");
2403 print_timestamp_done("ReinitializeGraphics");
2406 static void ReinitializeSounds()
2408 InitSoundInfo(); /* sound properties mapping */
2409 InitElementSoundInfo(); /* element game sound mapping */
2410 InitGameModeSoundInfo(); /* game mode sound mapping */
2412 InitPlayLevelSound(); /* internal game sound settings */
2415 static void ReinitializeMusic()
2417 InitMusicInfo(); /* music properties mapping */
2418 InitGameModeMusicInfo(); /* game mode music mapping */
2421 static int get_special_property_bit(int element, int property_bit_nr)
2423 struct PropertyBitInfo
2429 static struct PropertyBitInfo pb_can_move_into_acid[] =
2431 /* the player may be able fall into acid when gravity is activated */
2436 { EL_SP_MURPHY, 0 },
2437 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2439 /* all elements that can move may be able to also move into acid */
2442 { EL_BUG_RIGHT, 1 },
2445 { EL_SPACESHIP, 2 },
2446 { EL_SPACESHIP_LEFT, 2 },
2447 { EL_SPACESHIP_RIGHT, 2 },
2448 { EL_SPACESHIP_UP, 2 },
2449 { EL_SPACESHIP_DOWN, 2 },
2450 { EL_BD_BUTTERFLY, 3 },
2451 { EL_BD_BUTTERFLY_LEFT, 3 },
2452 { EL_BD_BUTTERFLY_RIGHT, 3 },
2453 { EL_BD_BUTTERFLY_UP, 3 },
2454 { EL_BD_BUTTERFLY_DOWN, 3 },
2455 { EL_BD_FIREFLY, 4 },
2456 { EL_BD_FIREFLY_LEFT, 4 },
2457 { EL_BD_FIREFLY_RIGHT, 4 },
2458 { EL_BD_FIREFLY_UP, 4 },
2459 { EL_BD_FIREFLY_DOWN, 4 },
2461 { EL_YAMYAM_LEFT, 5 },
2462 { EL_YAMYAM_RIGHT, 5 },
2463 { EL_YAMYAM_UP, 5 },
2464 { EL_YAMYAM_DOWN, 5 },
2465 { EL_DARK_YAMYAM, 6 },
2468 { EL_PACMAN_LEFT, 8 },
2469 { EL_PACMAN_RIGHT, 8 },
2470 { EL_PACMAN_UP, 8 },
2471 { EL_PACMAN_DOWN, 8 },
2473 { EL_MOLE_LEFT, 9 },
2474 { EL_MOLE_RIGHT, 9 },
2476 { EL_MOLE_DOWN, 9 },
2480 { EL_SATELLITE, 13 },
2481 { EL_SP_SNIKSNAK, 14 },
2482 { EL_SP_ELECTRON, 15 },
2485 { EL_EMC_ANDROID, 18 },
2490 static struct PropertyBitInfo pb_dont_collide_with[] =
2492 { EL_SP_SNIKSNAK, 0 },
2493 { EL_SP_ELECTRON, 1 },
2501 struct PropertyBitInfo *pb_info;
2504 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2505 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2510 struct PropertyBitInfo *pb_info = NULL;
2513 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2514 if (pb_definition[i].bit_nr == property_bit_nr)
2515 pb_info = pb_definition[i].pb_info;
2517 if (pb_info == NULL)
2520 for (i = 0; pb_info[i].element != -1; i++)
2521 if (pb_info[i].element == element)
2522 return pb_info[i].bit_nr;
2527 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2528 boolean property_value)
2530 int bit_nr = get_special_property_bit(element, property_bit_nr);
2535 *bitfield |= (1 << bit_nr);
2537 *bitfield &= ~(1 << bit_nr);
2541 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2543 int bit_nr = get_special_property_bit(element, property_bit_nr);
2546 return ((*bitfield & (1 << bit_nr)) != 0);
2551 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2553 static int group_nr;
2554 static struct ElementGroupInfo *group;
2555 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2558 if (actual_group == NULL) /* not yet initialized */
2561 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
2563 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2564 group_element - EL_GROUP_START + 1);
2566 /* replace element which caused too deep recursion by question mark */
2567 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2572 if (recursion_depth == 0) /* initialization */
2574 group = actual_group;
2575 group_nr = GROUP_NR(group_element);
2577 group->num_elements_resolved = 0;
2578 group->choice_pos = 0;
2580 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2581 element_info[i].in_group[group_nr] = FALSE;
2584 for (i = 0; i < actual_group->num_elements; i++)
2586 int element = actual_group->element[i];
2588 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2591 if (IS_GROUP_ELEMENT(element))
2592 ResolveGroupElementExt(element, recursion_depth + 1);
2595 group->element_resolved[group->num_elements_resolved++] = element;
2596 element_info[element].in_group[group_nr] = TRUE;
2601 void ResolveGroupElement(int group_element)
2603 ResolveGroupElementExt(group_element, 0);
2606 void InitElementPropertiesStatic()
2608 static int ep_diggable[] =
2613 EL_SP_BUGGY_BASE_ACTIVATING,
2616 EL_INVISIBLE_SAND_ACTIVE,
2619 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2620 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2625 EL_SP_BUGGY_BASE_ACTIVE,
2632 static int ep_collectible_only[] =
2654 EL_DYNABOMB_INCREASE_NUMBER,
2655 EL_DYNABOMB_INCREASE_SIZE,
2656 EL_DYNABOMB_INCREASE_POWER,
2674 /* !!! handle separately !!! */
2675 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2681 static int ep_dont_run_into[] =
2683 /* same elements as in 'ep_dont_touch' */
2689 /* same elements as in 'ep_dont_collide_with' */
2701 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2706 EL_SP_BUGGY_BASE_ACTIVE,
2713 static int ep_dont_collide_with[] =
2715 /* same elements as in 'ep_dont_touch' */
2732 static int ep_dont_touch[] =
2742 static int ep_indestructible[] =
2746 EL_ACID_POOL_TOPLEFT,
2747 EL_ACID_POOL_TOPRIGHT,
2748 EL_ACID_POOL_BOTTOMLEFT,
2749 EL_ACID_POOL_BOTTOM,
2750 EL_ACID_POOL_BOTTOMRIGHT,
2751 EL_SP_HARDWARE_GRAY,
2752 EL_SP_HARDWARE_GREEN,
2753 EL_SP_HARDWARE_BLUE,
2755 EL_SP_HARDWARE_YELLOW,
2756 EL_SP_HARDWARE_BASE_1,
2757 EL_SP_HARDWARE_BASE_2,
2758 EL_SP_HARDWARE_BASE_3,
2759 EL_SP_HARDWARE_BASE_4,
2760 EL_SP_HARDWARE_BASE_5,
2761 EL_SP_HARDWARE_BASE_6,
2762 EL_INVISIBLE_STEELWALL,
2763 EL_INVISIBLE_STEELWALL_ACTIVE,
2764 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2765 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2766 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2767 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2768 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2769 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2770 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2771 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2772 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2773 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2774 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2775 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2777 EL_LIGHT_SWITCH_ACTIVE,
2778 EL_SIGN_EXCLAMATION,
2779 EL_SIGN_RADIOACTIVITY,
2786 EL_SIGN_ENTRY_FORBIDDEN,
2787 EL_SIGN_EMERGENCY_EXIT,
2795 EL_STEEL_EXIT_CLOSED,
2797 EL_EM_STEEL_EXIT_CLOSED,
2798 EL_EM_STEEL_EXIT_OPEN,
2799 EL_DC_STEELWALL_1_LEFT,
2800 EL_DC_STEELWALL_1_RIGHT,
2801 EL_DC_STEELWALL_1_TOP,
2802 EL_DC_STEELWALL_1_BOTTOM,
2803 EL_DC_STEELWALL_1_HORIZONTAL,
2804 EL_DC_STEELWALL_1_VERTICAL,
2805 EL_DC_STEELWALL_1_TOPLEFT,
2806 EL_DC_STEELWALL_1_TOPRIGHT,
2807 EL_DC_STEELWALL_1_BOTTOMLEFT,
2808 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2809 EL_DC_STEELWALL_1_TOPLEFT_2,
2810 EL_DC_STEELWALL_1_TOPRIGHT_2,
2811 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2812 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2813 EL_DC_STEELWALL_2_LEFT,
2814 EL_DC_STEELWALL_2_RIGHT,
2815 EL_DC_STEELWALL_2_TOP,
2816 EL_DC_STEELWALL_2_BOTTOM,
2817 EL_DC_STEELWALL_2_HORIZONTAL,
2818 EL_DC_STEELWALL_2_VERTICAL,
2819 EL_DC_STEELWALL_2_MIDDLE,
2820 EL_DC_STEELWALL_2_SINGLE,
2821 EL_STEELWALL_SLIPPERY,
2835 EL_GATE_1_GRAY_ACTIVE,
2836 EL_GATE_2_GRAY_ACTIVE,
2837 EL_GATE_3_GRAY_ACTIVE,
2838 EL_GATE_4_GRAY_ACTIVE,
2847 EL_EM_GATE_1_GRAY_ACTIVE,
2848 EL_EM_GATE_2_GRAY_ACTIVE,
2849 EL_EM_GATE_3_GRAY_ACTIVE,
2850 EL_EM_GATE_4_GRAY_ACTIVE,
2859 EL_EMC_GATE_5_GRAY_ACTIVE,
2860 EL_EMC_GATE_6_GRAY_ACTIVE,
2861 EL_EMC_GATE_7_GRAY_ACTIVE,
2862 EL_EMC_GATE_8_GRAY_ACTIVE,
2864 EL_DC_GATE_WHITE_GRAY,
2865 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2866 EL_DC_GATE_FAKE_GRAY,
2868 EL_SWITCHGATE_OPENING,
2869 EL_SWITCHGATE_CLOSED,
2870 EL_SWITCHGATE_CLOSING,
2872 EL_DC_SWITCHGATE_SWITCH_UP,
2873 EL_DC_SWITCHGATE_SWITCH_DOWN,
2876 EL_TIMEGATE_OPENING,
2878 EL_TIMEGATE_CLOSING,
2880 EL_DC_TIMEGATE_SWITCH,
2881 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2886 EL_TUBE_VERTICAL_LEFT,
2887 EL_TUBE_VERTICAL_RIGHT,
2888 EL_TUBE_HORIZONTAL_UP,
2889 EL_TUBE_HORIZONTAL_DOWN,
2894 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2895 EL_EXPANDABLE_STEELWALL_VERTICAL,
2896 EL_EXPANDABLE_STEELWALL_ANY,
2901 static int ep_slippery[] =
2915 EL_ROBOT_WHEEL_ACTIVE,
2921 EL_ACID_POOL_TOPLEFT,
2922 EL_ACID_POOL_TOPRIGHT,
2932 EL_STEELWALL_SLIPPERY,
2935 EL_EMC_WALL_SLIPPERY_1,
2936 EL_EMC_WALL_SLIPPERY_2,
2937 EL_EMC_WALL_SLIPPERY_3,
2938 EL_EMC_WALL_SLIPPERY_4,
2940 EL_EMC_MAGIC_BALL_ACTIVE,
2945 static int ep_can_change[] =
2950 static int ep_can_move[] =
2952 /* same elements as in 'pb_can_move_into_acid' */
2975 static int ep_can_fall[] =
2989 EL_QUICKSAND_FAST_FULL,
2991 EL_BD_MAGIC_WALL_FULL,
2992 EL_DC_MAGIC_WALL_FULL,
3006 static int ep_can_smash_player[] =
3032 static int ep_can_smash_enemies[] =
3041 static int ep_can_smash_everything[] =
3050 static int ep_explodes_by_fire[] =
3052 /* same elements as in 'ep_explodes_impact' */
3057 /* same elements as in 'ep_explodes_smashed' */
3067 EL_EM_DYNAMITE_ACTIVE,
3068 EL_DYNABOMB_PLAYER_1_ACTIVE,
3069 EL_DYNABOMB_PLAYER_2_ACTIVE,
3070 EL_DYNABOMB_PLAYER_3_ACTIVE,
3071 EL_DYNABOMB_PLAYER_4_ACTIVE,
3072 EL_DYNABOMB_INCREASE_NUMBER,
3073 EL_DYNABOMB_INCREASE_SIZE,
3074 EL_DYNABOMB_INCREASE_POWER,
3075 EL_SP_DISK_RED_ACTIVE,
3089 static int ep_explodes_smashed[] =
3091 /* same elements as in 'ep_explodes_impact' */
3105 static int ep_explodes_impact[] =
3114 static int ep_walkable_over[] =
3118 EL_SOKOBAN_FIELD_EMPTY,
3124 EL_EM_STEEL_EXIT_OPEN,
3133 EL_GATE_1_GRAY_ACTIVE,
3134 EL_GATE_2_GRAY_ACTIVE,
3135 EL_GATE_3_GRAY_ACTIVE,
3136 EL_GATE_4_GRAY_ACTIVE,
3144 static int ep_walkable_inside[] =
3149 EL_TUBE_VERTICAL_LEFT,
3150 EL_TUBE_VERTICAL_RIGHT,
3151 EL_TUBE_HORIZONTAL_UP,
3152 EL_TUBE_HORIZONTAL_DOWN,
3161 static int ep_walkable_under[] =
3166 static int ep_passable_over[] =
3176 EL_EM_GATE_1_GRAY_ACTIVE,
3177 EL_EM_GATE_2_GRAY_ACTIVE,
3178 EL_EM_GATE_3_GRAY_ACTIVE,
3179 EL_EM_GATE_4_GRAY_ACTIVE,
3188 EL_EMC_GATE_5_GRAY_ACTIVE,
3189 EL_EMC_GATE_6_GRAY_ACTIVE,
3190 EL_EMC_GATE_7_GRAY_ACTIVE,
3191 EL_EMC_GATE_8_GRAY_ACTIVE,
3193 EL_DC_GATE_WHITE_GRAY,
3194 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3201 static int ep_passable_inside[] =
3207 EL_SP_PORT_HORIZONTAL,
3208 EL_SP_PORT_VERTICAL,
3210 EL_SP_GRAVITY_PORT_LEFT,
3211 EL_SP_GRAVITY_PORT_RIGHT,
3212 EL_SP_GRAVITY_PORT_UP,
3213 EL_SP_GRAVITY_PORT_DOWN,
3214 EL_SP_GRAVITY_ON_PORT_LEFT,
3215 EL_SP_GRAVITY_ON_PORT_RIGHT,
3216 EL_SP_GRAVITY_ON_PORT_UP,
3217 EL_SP_GRAVITY_ON_PORT_DOWN,
3218 EL_SP_GRAVITY_OFF_PORT_LEFT,
3219 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3220 EL_SP_GRAVITY_OFF_PORT_UP,
3221 EL_SP_GRAVITY_OFF_PORT_DOWN,
3226 static int ep_passable_under[] =
3231 static int ep_droppable[] =
3236 static int ep_explodes_1x1_old[] =
3241 static int ep_pushable[] =
3253 EL_SOKOBAN_FIELD_FULL,
3262 static int ep_explodes_cross_old[] =
3267 static int ep_protected[] =
3269 /* same elements as in 'ep_walkable_inside' */
3273 EL_TUBE_VERTICAL_LEFT,
3274 EL_TUBE_VERTICAL_RIGHT,
3275 EL_TUBE_HORIZONTAL_UP,
3276 EL_TUBE_HORIZONTAL_DOWN,
3282 /* same elements as in 'ep_passable_over' */
3291 EL_EM_GATE_1_GRAY_ACTIVE,
3292 EL_EM_GATE_2_GRAY_ACTIVE,
3293 EL_EM_GATE_3_GRAY_ACTIVE,
3294 EL_EM_GATE_4_GRAY_ACTIVE,
3303 EL_EMC_GATE_5_GRAY_ACTIVE,
3304 EL_EMC_GATE_6_GRAY_ACTIVE,
3305 EL_EMC_GATE_7_GRAY_ACTIVE,
3306 EL_EMC_GATE_8_GRAY_ACTIVE,
3308 EL_DC_GATE_WHITE_GRAY,
3309 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3313 /* same elements as in 'ep_passable_inside' */
3318 EL_SP_PORT_HORIZONTAL,
3319 EL_SP_PORT_VERTICAL,
3321 EL_SP_GRAVITY_PORT_LEFT,
3322 EL_SP_GRAVITY_PORT_RIGHT,
3323 EL_SP_GRAVITY_PORT_UP,
3324 EL_SP_GRAVITY_PORT_DOWN,
3325 EL_SP_GRAVITY_ON_PORT_LEFT,
3326 EL_SP_GRAVITY_ON_PORT_RIGHT,
3327 EL_SP_GRAVITY_ON_PORT_UP,
3328 EL_SP_GRAVITY_ON_PORT_DOWN,
3329 EL_SP_GRAVITY_OFF_PORT_LEFT,
3330 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3331 EL_SP_GRAVITY_OFF_PORT_UP,
3332 EL_SP_GRAVITY_OFF_PORT_DOWN,
3337 static int ep_throwable[] =
3342 static int ep_can_explode[] =
3344 /* same elements as in 'ep_explodes_impact' */
3349 /* same elements as in 'ep_explodes_smashed' */
3355 /* elements that can explode by explosion or by dragonfire */
3359 EL_EM_DYNAMITE_ACTIVE,
3360 EL_DYNABOMB_PLAYER_1_ACTIVE,
3361 EL_DYNABOMB_PLAYER_2_ACTIVE,
3362 EL_DYNABOMB_PLAYER_3_ACTIVE,
3363 EL_DYNABOMB_PLAYER_4_ACTIVE,
3364 EL_DYNABOMB_INCREASE_NUMBER,
3365 EL_DYNABOMB_INCREASE_SIZE,
3366 EL_DYNABOMB_INCREASE_POWER,
3367 EL_SP_DISK_RED_ACTIVE,
3375 /* elements that can explode only by explosion */
3381 static int ep_gravity_reachable[] =
3387 EL_INVISIBLE_SAND_ACTIVE,
3392 EL_SP_PORT_HORIZONTAL,
3393 EL_SP_PORT_VERTICAL,
3395 EL_SP_GRAVITY_PORT_LEFT,
3396 EL_SP_GRAVITY_PORT_RIGHT,
3397 EL_SP_GRAVITY_PORT_UP,
3398 EL_SP_GRAVITY_PORT_DOWN,
3399 EL_SP_GRAVITY_ON_PORT_LEFT,
3400 EL_SP_GRAVITY_ON_PORT_RIGHT,
3401 EL_SP_GRAVITY_ON_PORT_UP,
3402 EL_SP_GRAVITY_ON_PORT_DOWN,
3403 EL_SP_GRAVITY_OFF_PORT_LEFT,
3404 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3405 EL_SP_GRAVITY_OFF_PORT_UP,
3406 EL_SP_GRAVITY_OFF_PORT_DOWN,
3412 static int ep_player[] =
3419 EL_SOKOBAN_FIELD_PLAYER,
3425 static int ep_can_pass_magic_wall[] =
3439 static int ep_can_pass_dc_magic_wall[] =
3455 static int ep_switchable[] =
3459 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3460 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3461 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3462 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3463 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3464 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3465 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3466 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3467 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3468 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3469 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3470 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3471 EL_SWITCHGATE_SWITCH_UP,
3472 EL_SWITCHGATE_SWITCH_DOWN,
3473 EL_DC_SWITCHGATE_SWITCH_UP,
3474 EL_DC_SWITCHGATE_SWITCH_DOWN,
3476 EL_LIGHT_SWITCH_ACTIVE,
3478 EL_DC_TIMEGATE_SWITCH,
3479 EL_BALLOON_SWITCH_LEFT,
3480 EL_BALLOON_SWITCH_RIGHT,
3481 EL_BALLOON_SWITCH_UP,
3482 EL_BALLOON_SWITCH_DOWN,
3483 EL_BALLOON_SWITCH_ANY,
3484 EL_BALLOON_SWITCH_NONE,
3487 EL_EMC_MAGIC_BALL_SWITCH,
3488 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3493 static int ep_bd_element[] =
3527 static int ep_sp_element[] =
3529 /* should always be valid */
3532 /* standard classic Supaplex elements */
3539 EL_SP_HARDWARE_GRAY,
3547 EL_SP_GRAVITY_PORT_RIGHT,
3548 EL_SP_GRAVITY_PORT_DOWN,
3549 EL_SP_GRAVITY_PORT_LEFT,
3550 EL_SP_GRAVITY_PORT_UP,
3555 EL_SP_PORT_VERTICAL,
3556 EL_SP_PORT_HORIZONTAL,
3562 EL_SP_HARDWARE_BASE_1,
3563 EL_SP_HARDWARE_GREEN,
3564 EL_SP_HARDWARE_BLUE,
3566 EL_SP_HARDWARE_YELLOW,
3567 EL_SP_HARDWARE_BASE_2,
3568 EL_SP_HARDWARE_BASE_3,
3569 EL_SP_HARDWARE_BASE_4,
3570 EL_SP_HARDWARE_BASE_5,
3571 EL_SP_HARDWARE_BASE_6,
3575 /* additional elements that appeared in newer Supaplex levels */
3578 /* additional gravity port elements (not switching, but setting gravity) */
3579 EL_SP_GRAVITY_ON_PORT_LEFT,
3580 EL_SP_GRAVITY_ON_PORT_RIGHT,
3581 EL_SP_GRAVITY_ON_PORT_UP,
3582 EL_SP_GRAVITY_ON_PORT_DOWN,
3583 EL_SP_GRAVITY_OFF_PORT_LEFT,
3584 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3585 EL_SP_GRAVITY_OFF_PORT_UP,
3586 EL_SP_GRAVITY_OFF_PORT_DOWN,
3588 /* more than one Murphy in a level results in an inactive clone */
3591 /* runtime Supaplex elements */
3592 EL_SP_DISK_RED_ACTIVE,
3593 EL_SP_TERMINAL_ACTIVE,
3594 EL_SP_BUGGY_BASE_ACTIVATING,
3595 EL_SP_BUGGY_BASE_ACTIVE,
3602 static int ep_sb_element[] =
3607 EL_SOKOBAN_FIELD_EMPTY,
3608 EL_SOKOBAN_FIELD_FULL,
3609 EL_SOKOBAN_FIELD_PLAYER,
3614 EL_INVISIBLE_STEELWALL,
3619 static int ep_gem[] =
3631 static int ep_food_dark_yamyam[] =
3659 static int ep_food_penguin[] =
3673 static int ep_food_pig[] =
3685 static int ep_historic_wall[] =
3696 EL_GATE_1_GRAY_ACTIVE,
3697 EL_GATE_2_GRAY_ACTIVE,
3698 EL_GATE_3_GRAY_ACTIVE,
3699 EL_GATE_4_GRAY_ACTIVE,
3708 EL_EM_GATE_1_GRAY_ACTIVE,
3709 EL_EM_GATE_2_GRAY_ACTIVE,
3710 EL_EM_GATE_3_GRAY_ACTIVE,
3711 EL_EM_GATE_4_GRAY_ACTIVE,
3718 EL_EXPANDABLE_WALL_HORIZONTAL,
3719 EL_EXPANDABLE_WALL_VERTICAL,
3720 EL_EXPANDABLE_WALL_ANY,
3721 EL_EXPANDABLE_WALL_GROWING,
3722 EL_BD_EXPANDABLE_WALL,
3729 EL_SP_HARDWARE_GRAY,
3730 EL_SP_HARDWARE_GREEN,
3731 EL_SP_HARDWARE_BLUE,
3733 EL_SP_HARDWARE_YELLOW,
3734 EL_SP_HARDWARE_BASE_1,
3735 EL_SP_HARDWARE_BASE_2,
3736 EL_SP_HARDWARE_BASE_3,
3737 EL_SP_HARDWARE_BASE_4,
3738 EL_SP_HARDWARE_BASE_5,
3739 EL_SP_HARDWARE_BASE_6,
3741 EL_SP_TERMINAL_ACTIVE,
3744 EL_INVISIBLE_STEELWALL,
3745 EL_INVISIBLE_STEELWALL_ACTIVE,
3747 EL_INVISIBLE_WALL_ACTIVE,
3748 EL_STEELWALL_SLIPPERY,
3765 static int ep_historic_solid[] =
3769 EL_EXPANDABLE_WALL_HORIZONTAL,
3770 EL_EXPANDABLE_WALL_VERTICAL,
3771 EL_EXPANDABLE_WALL_ANY,
3772 EL_BD_EXPANDABLE_WALL,
3785 EL_QUICKSAND_FILLING,
3786 EL_QUICKSAND_EMPTYING,
3788 EL_MAGIC_WALL_ACTIVE,
3789 EL_MAGIC_WALL_EMPTYING,
3790 EL_MAGIC_WALL_FILLING,
3794 EL_BD_MAGIC_WALL_ACTIVE,
3795 EL_BD_MAGIC_WALL_EMPTYING,
3796 EL_BD_MAGIC_WALL_FULL,
3797 EL_BD_MAGIC_WALL_FILLING,
3798 EL_BD_MAGIC_WALL_DEAD,
3807 EL_SP_TERMINAL_ACTIVE,
3811 EL_INVISIBLE_WALL_ACTIVE,
3812 EL_SWITCHGATE_SWITCH_UP,
3813 EL_SWITCHGATE_SWITCH_DOWN,
3814 EL_DC_SWITCHGATE_SWITCH_UP,
3815 EL_DC_SWITCHGATE_SWITCH_DOWN,
3817 EL_TIMEGATE_SWITCH_ACTIVE,
3818 EL_DC_TIMEGATE_SWITCH,
3819 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3831 /* the following elements are a direct copy of "indestructible" elements,
3832 except "EL_ACID", which is "indestructible", but not "solid"! */
3837 EL_ACID_POOL_TOPLEFT,
3838 EL_ACID_POOL_TOPRIGHT,
3839 EL_ACID_POOL_BOTTOMLEFT,
3840 EL_ACID_POOL_BOTTOM,
3841 EL_ACID_POOL_BOTTOMRIGHT,
3842 EL_SP_HARDWARE_GRAY,
3843 EL_SP_HARDWARE_GREEN,
3844 EL_SP_HARDWARE_BLUE,
3846 EL_SP_HARDWARE_YELLOW,
3847 EL_SP_HARDWARE_BASE_1,
3848 EL_SP_HARDWARE_BASE_2,
3849 EL_SP_HARDWARE_BASE_3,
3850 EL_SP_HARDWARE_BASE_4,
3851 EL_SP_HARDWARE_BASE_5,
3852 EL_SP_HARDWARE_BASE_6,
3853 EL_INVISIBLE_STEELWALL,
3854 EL_INVISIBLE_STEELWALL_ACTIVE,
3855 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3856 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3857 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3858 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3859 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3860 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3861 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3862 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3863 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3864 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3865 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3866 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3868 EL_LIGHT_SWITCH_ACTIVE,
3869 EL_SIGN_EXCLAMATION,
3870 EL_SIGN_RADIOACTIVITY,
3877 EL_SIGN_ENTRY_FORBIDDEN,
3878 EL_SIGN_EMERGENCY_EXIT,
3886 EL_STEEL_EXIT_CLOSED,
3888 EL_DC_STEELWALL_1_LEFT,
3889 EL_DC_STEELWALL_1_RIGHT,
3890 EL_DC_STEELWALL_1_TOP,
3891 EL_DC_STEELWALL_1_BOTTOM,
3892 EL_DC_STEELWALL_1_HORIZONTAL,
3893 EL_DC_STEELWALL_1_VERTICAL,
3894 EL_DC_STEELWALL_1_TOPLEFT,
3895 EL_DC_STEELWALL_1_TOPRIGHT,
3896 EL_DC_STEELWALL_1_BOTTOMLEFT,
3897 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3898 EL_DC_STEELWALL_1_TOPLEFT_2,
3899 EL_DC_STEELWALL_1_TOPRIGHT_2,
3900 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3901 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3902 EL_DC_STEELWALL_2_LEFT,
3903 EL_DC_STEELWALL_2_RIGHT,
3904 EL_DC_STEELWALL_2_TOP,
3905 EL_DC_STEELWALL_2_BOTTOM,
3906 EL_DC_STEELWALL_2_HORIZONTAL,
3907 EL_DC_STEELWALL_2_VERTICAL,
3908 EL_DC_STEELWALL_2_MIDDLE,
3909 EL_DC_STEELWALL_2_SINGLE,
3910 EL_STEELWALL_SLIPPERY,
3924 EL_GATE_1_GRAY_ACTIVE,
3925 EL_GATE_2_GRAY_ACTIVE,
3926 EL_GATE_3_GRAY_ACTIVE,
3927 EL_GATE_4_GRAY_ACTIVE,
3936 EL_EM_GATE_1_GRAY_ACTIVE,
3937 EL_EM_GATE_2_GRAY_ACTIVE,
3938 EL_EM_GATE_3_GRAY_ACTIVE,
3939 EL_EM_GATE_4_GRAY_ACTIVE,
3941 EL_SWITCHGATE_OPENING,
3942 EL_SWITCHGATE_CLOSED,
3943 EL_SWITCHGATE_CLOSING,
3945 EL_TIMEGATE_OPENING,
3947 EL_TIMEGATE_CLOSING,
3951 EL_TUBE_VERTICAL_LEFT,
3952 EL_TUBE_VERTICAL_RIGHT,
3953 EL_TUBE_HORIZONTAL_UP,
3954 EL_TUBE_HORIZONTAL_DOWN,
3963 static int ep_classic_enemy[] =
3980 static int ep_belt[] =
3982 EL_CONVEYOR_BELT_1_LEFT,
3983 EL_CONVEYOR_BELT_1_MIDDLE,
3984 EL_CONVEYOR_BELT_1_RIGHT,
3985 EL_CONVEYOR_BELT_2_LEFT,
3986 EL_CONVEYOR_BELT_2_MIDDLE,
3987 EL_CONVEYOR_BELT_2_RIGHT,
3988 EL_CONVEYOR_BELT_3_LEFT,
3989 EL_CONVEYOR_BELT_3_MIDDLE,
3990 EL_CONVEYOR_BELT_3_RIGHT,
3991 EL_CONVEYOR_BELT_4_LEFT,
3992 EL_CONVEYOR_BELT_4_MIDDLE,
3993 EL_CONVEYOR_BELT_4_RIGHT,
3998 static int ep_belt_active[] =
4000 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
4001 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
4002 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
4003 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
4004 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
4005 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
4006 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
4007 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
4008 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
4009 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
4010 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
4011 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
4016 static int ep_belt_switch[] =
4018 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4019 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4020 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4021 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4022 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4023 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4024 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4025 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4026 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4027 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4028 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4029 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4034 static int ep_tube[] =
4041 EL_TUBE_HORIZONTAL_UP,
4042 EL_TUBE_HORIZONTAL_DOWN,
4044 EL_TUBE_VERTICAL_LEFT,
4045 EL_TUBE_VERTICAL_RIGHT,
4051 static int ep_acid_pool[] =
4053 EL_ACID_POOL_TOPLEFT,
4054 EL_ACID_POOL_TOPRIGHT,
4055 EL_ACID_POOL_BOTTOMLEFT,
4056 EL_ACID_POOL_BOTTOM,
4057 EL_ACID_POOL_BOTTOMRIGHT,
4062 static int ep_keygate[] =
4072 EL_GATE_1_GRAY_ACTIVE,
4073 EL_GATE_2_GRAY_ACTIVE,
4074 EL_GATE_3_GRAY_ACTIVE,
4075 EL_GATE_4_GRAY_ACTIVE,
4084 EL_EM_GATE_1_GRAY_ACTIVE,
4085 EL_EM_GATE_2_GRAY_ACTIVE,
4086 EL_EM_GATE_3_GRAY_ACTIVE,
4087 EL_EM_GATE_4_GRAY_ACTIVE,
4096 EL_EMC_GATE_5_GRAY_ACTIVE,
4097 EL_EMC_GATE_6_GRAY_ACTIVE,
4098 EL_EMC_GATE_7_GRAY_ACTIVE,
4099 EL_EMC_GATE_8_GRAY_ACTIVE,
4101 EL_DC_GATE_WHITE_GRAY,
4102 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4107 static int ep_amoeboid[] =
4119 static int ep_amoebalive[] =
4130 static int ep_has_editor_content[] =
4152 static int ep_can_turn_each_move[] =
4154 /* !!! do something with this one !!! */
4158 static int ep_can_grow[] =
4172 static int ep_active_bomb[] =
4175 EL_EM_DYNAMITE_ACTIVE,
4176 EL_DYNABOMB_PLAYER_1_ACTIVE,
4177 EL_DYNABOMB_PLAYER_2_ACTIVE,
4178 EL_DYNABOMB_PLAYER_3_ACTIVE,
4179 EL_DYNABOMB_PLAYER_4_ACTIVE,
4180 EL_SP_DISK_RED_ACTIVE,
4185 static int ep_inactive[] =
4195 EL_QUICKSAND_FAST_EMPTY,
4218 EL_GATE_1_GRAY_ACTIVE,
4219 EL_GATE_2_GRAY_ACTIVE,
4220 EL_GATE_3_GRAY_ACTIVE,
4221 EL_GATE_4_GRAY_ACTIVE,
4230 EL_EM_GATE_1_GRAY_ACTIVE,
4231 EL_EM_GATE_2_GRAY_ACTIVE,
4232 EL_EM_GATE_3_GRAY_ACTIVE,
4233 EL_EM_GATE_4_GRAY_ACTIVE,
4242 EL_EMC_GATE_5_GRAY_ACTIVE,
4243 EL_EMC_GATE_6_GRAY_ACTIVE,
4244 EL_EMC_GATE_7_GRAY_ACTIVE,
4245 EL_EMC_GATE_8_GRAY_ACTIVE,
4247 EL_DC_GATE_WHITE_GRAY,
4248 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4249 EL_DC_GATE_FAKE_GRAY,
4252 EL_INVISIBLE_STEELWALL,
4260 EL_WALL_EMERALD_YELLOW,
4261 EL_DYNABOMB_INCREASE_NUMBER,
4262 EL_DYNABOMB_INCREASE_SIZE,
4263 EL_DYNABOMB_INCREASE_POWER,
4267 EL_SOKOBAN_FIELD_EMPTY,
4268 EL_SOKOBAN_FIELD_FULL,
4269 EL_WALL_EMERALD_RED,
4270 EL_WALL_EMERALD_PURPLE,
4271 EL_ACID_POOL_TOPLEFT,
4272 EL_ACID_POOL_TOPRIGHT,
4273 EL_ACID_POOL_BOTTOMLEFT,
4274 EL_ACID_POOL_BOTTOM,
4275 EL_ACID_POOL_BOTTOMRIGHT,
4279 EL_BD_MAGIC_WALL_DEAD,
4281 EL_DC_MAGIC_WALL_DEAD,
4282 EL_AMOEBA_TO_DIAMOND,
4290 EL_SP_GRAVITY_PORT_RIGHT,
4291 EL_SP_GRAVITY_PORT_DOWN,
4292 EL_SP_GRAVITY_PORT_LEFT,
4293 EL_SP_GRAVITY_PORT_UP,
4294 EL_SP_PORT_HORIZONTAL,
4295 EL_SP_PORT_VERTICAL,
4306 EL_SP_HARDWARE_GRAY,
4307 EL_SP_HARDWARE_GREEN,
4308 EL_SP_HARDWARE_BLUE,
4310 EL_SP_HARDWARE_YELLOW,
4311 EL_SP_HARDWARE_BASE_1,
4312 EL_SP_HARDWARE_BASE_2,
4313 EL_SP_HARDWARE_BASE_3,
4314 EL_SP_HARDWARE_BASE_4,
4315 EL_SP_HARDWARE_BASE_5,
4316 EL_SP_HARDWARE_BASE_6,
4317 EL_SP_GRAVITY_ON_PORT_LEFT,
4318 EL_SP_GRAVITY_ON_PORT_RIGHT,
4319 EL_SP_GRAVITY_ON_PORT_UP,
4320 EL_SP_GRAVITY_ON_PORT_DOWN,
4321 EL_SP_GRAVITY_OFF_PORT_LEFT,
4322 EL_SP_GRAVITY_OFF_PORT_RIGHT,
4323 EL_SP_GRAVITY_OFF_PORT_UP,
4324 EL_SP_GRAVITY_OFF_PORT_DOWN,
4325 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4326 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4327 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4328 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4329 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4330 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4331 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4332 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4333 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4334 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4335 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4336 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4337 EL_SIGN_EXCLAMATION,
4338 EL_SIGN_RADIOACTIVITY,
4345 EL_SIGN_ENTRY_FORBIDDEN,
4346 EL_SIGN_EMERGENCY_EXIT,
4354 EL_DC_STEELWALL_1_LEFT,
4355 EL_DC_STEELWALL_1_RIGHT,
4356 EL_DC_STEELWALL_1_TOP,
4357 EL_DC_STEELWALL_1_BOTTOM,
4358 EL_DC_STEELWALL_1_HORIZONTAL,
4359 EL_DC_STEELWALL_1_VERTICAL,
4360 EL_DC_STEELWALL_1_TOPLEFT,
4361 EL_DC_STEELWALL_1_TOPRIGHT,
4362 EL_DC_STEELWALL_1_BOTTOMLEFT,
4363 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4364 EL_DC_STEELWALL_1_TOPLEFT_2,
4365 EL_DC_STEELWALL_1_TOPRIGHT_2,
4366 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4367 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4368 EL_DC_STEELWALL_2_LEFT,
4369 EL_DC_STEELWALL_2_RIGHT,
4370 EL_DC_STEELWALL_2_TOP,
4371 EL_DC_STEELWALL_2_BOTTOM,
4372 EL_DC_STEELWALL_2_HORIZONTAL,
4373 EL_DC_STEELWALL_2_VERTICAL,
4374 EL_DC_STEELWALL_2_MIDDLE,
4375 EL_DC_STEELWALL_2_SINGLE,
4376 EL_STEELWALL_SLIPPERY,
4381 EL_EMC_WALL_SLIPPERY_1,
4382 EL_EMC_WALL_SLIPPERY_2,
4383 EL_EMC_WALL_SLIPPERY_3,
4384 EL_EMC_WALL_SLIPPERY_4,
4405 static int ep_em_slippery_wall[] =
4410 static int ep_gfx_crumbled[] =
4421 static int ep_editor_cascade_active[] =
4423 EL_INTERNAL_CASCADE_BD_ACTIVE,
4424 EL_INTERNAL_CASCADE_EM_ACTIVE,
4425 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4426 EL_INTERNAL_CASCADE_RND_ACTIVE,
4427 EL_INTERNAL_CASCADE_SB_ACTIVE,
4428 EL_INTERNAL_CASCADE_SP_ACTIVE,
4429 EL_INTERNAL_CASCADE_DC_ACTIVE,
4430 EL_INTERNAL_CASCADE_DX_ACTIVE,
4431 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4432 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4433 EL_INTERNAL_CASCADE_CE_ACTIVE,
4434 EL_INTERNAL_CASCADE_GE_ACTIVE,
4435 EL_INTERNAL_CASCADE_REF_ACTIVE,
4436 EL_INTERNAL_CASCADE_USER_ACTIVE,
4437 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4442 static int ep_editor_cascade_inactive[] =
4444 EL_INTERNAL_CASCADE_BD,
4445 EL_INTERNAL_CASCADE_EM,
4446 EL_INTERNAL_CASCADE_EMC,
4447 EL_INTERNAL_CASCADE_RND,
4448 EL_INTERNAL_CASCADE_SB,
4449 EL_INTERNAL_CASCADE_SP,
4450 EL_INTERNAL_CASCADE_DC,
4451 EL_INTERNAL_CASCADE_DX,
4452 EL_INTERNAL_CASCADE_CHARS,
4453 EL_INTERNAL_CASCADE_STEEL_CHARS,
4454 EL_INTERNAL_CASCADE_CE,
4455 EL_INTERNAL_CASCADE_GE,
4456 EL_INTERNAL_CASCADE_REF,
4457 EL_INTERNAL_CASCADE_USER,
4458 EL_INTERNAL_CASCADE_DYNAMIC,
4463 static int ep_obsolete[] =
4467 EL_EM_KEY_1_FILE_OBSOLETE,
4468 EL_EM_KEY_2_FILE_OBSOLETE,
4469 EL_EM_KEY_3_FILE_OBSOLETE,
4470 EL_EM_KEY_4_FILE_OBSOLETE,
4471 EL_ENVELOPE_OBSOLETE,
4480 } element_properties[] =
4482 { ep_diggable, EP_DIGGABLE },
4483 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4484 { ep_dont_run_into, EP_DONT_RUN_INTO },
4485 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4486 { ep_dont_touch, EP_DONT_TOUCH },
4487 { ep_indestructible, EP_INDESTRUCTIBLE },
4488 { ep_slippery, EP_SLIPPERY },
4489 { ep_can_change, EP_CAN_CHANGE },
4490 { ep_can_move, EP_CAN_MOVE },
4491 { ep_can_fall, EP_CAN_FALL },
4492 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4493 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4494 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4495 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4496 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4497 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4498 { ep_walkable_over, EP_WALKABLE_OVER },
4499 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4500 { ep_walkable_under, EP_WALKABLE_UNDER },
4501 { ep_passable_over, EP_PASSABLE_OVER },
4502 { ep_passable_inside, EP_PASSABLE_INSIDE },
4503 { ep_passable_under, EP_PASSABLE_UNDER },
4504 { ep_droppable, EP_DROPPABLE },
4505 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4506 { ep_pushable, EP_PUSHABLE },
4507 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4508 { ep_protected, EP_PROTECTED },
4509 { ep_throwable, EP_THROWABLE },
4510 { ep_can_explode, EP_CAN_EXPLODE },
4511 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4513 { ep_player, EP_PLAYER },
4514 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4515 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4516 { ep_switchable, EP_SWITCHABLE },
4517 { ep_bd_element, EP_BD_ELEMENT },
4518 { ep_sp_element, EP_SP_ELEMENT },
4519 { ep_sb_element, EP_SB_ELEMENT },
4521 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4522 { ep_food_penguin, EP_FOOD_PENGUIN },
4523 { ep_food_pig, EP_FOOD_PIG },
4524 { ep_historic_wall, EP_HISTORIC_WALL },
4525 { ep_historic_solid, EP_HISTORIC_SOLID },
4526 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4527 { ep_belt, EP_BELT },
4528 { ep_belt_active, EP_BELT_ACTIVE },
4529 { ep_belt_switch, EP_BELT_SWITCH },
4530 { ep_tube, EP_TUBE },
4531 { ep_acid_pool, EP_ACID_POOL },
4532 { ep_keygate, EP_KEYGATE },
4533 { ep_amoeboid, EP_AMOEBOID },
4534 { ep_amoebalive, EP_AMOEBALIVE },
4535 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4536 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4537 { ep_can_grow, EP_CAN_GROW },
4538 { ep_active_bomb, EP_ACTIVE_BOMB },
4539 { ep_inactive, EP_INACTIVE },
4541 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4543 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4545 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4546 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4548 { ep_obsolete, EP_OBSOLETE },
4555 /* always start with reliable default values (element has no properties) */
4556 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4557 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4558 SET_PROPERTY(i, j, FALSE);
4560 /* set all base element properties from above array definitions */
4561 for (i = 0; element_properties[i].elements != NULL; i++)
4562 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4563 SET_PROPERTY((element_properties[i].elements)[j],
4564 element_properties[i].property, TRUE);
4566 /* copy properties to some elements that are only stored in level file */
4567 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4568 for (j = 0; copy_properties[j][0] != -1; j++)
4569 if (HAS_PROPERTY(copy_properties[j][0], i))
4570 for (k = 1; k <= 4; k++)
4571 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4573 /* set static element properties that are not listed in array definitions */
4574 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4575 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4578 void InitElementPropertiesEngine(int engine_version)
4580 static int no_wall_properties[] =
4583 EP_COLLECTIBLE_ONLY,
4585 EP_DONT_COLLIDE_WITH,
4588 EP_CAN_SMASH_PLAYER,
4589 EP_CAN_SMASH_ENEMIES,
4590 EP_CAN_SMASH_EVERYTHING,
4595 EP_FOOD_DARK_YAMYAM,
4611 /* important: after initialization in InitElementPropertiesStatic(), the
4612 elements are not again initialized to a default value; therefore all
4613 changes have to make sure that they leave the element with a defined
4614 property (which means that conditional property changes must be set to
4615 a reliable default value before) */
4617 /* resolve group elements */
4618 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4619 ResolveGroupElement(EL_GROUP_START + i);
4621 /* set all special, combined or engine dependent element properties */
4622 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4624 /* ---------- INACTIVE ------------------------------------------------- */
4625 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4626 i <= EL_CHAR_END) ||
4627 (i >= EL_STEEL_CHAR_START &&
4628 i <= EL_STEEL_CHAR_END)));
4630 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4631 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4632 IS_WALKABLE_INSIDE(i) ||
4633 IS_WALKABLE_UNDER(i)));
4635 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4636 IS_PASSABLE_INSIDE(i) ||
4637 IS_PASSABLE_UNDER(i)));
4639 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4640 IS_PASSABLE_OVER(i)));
4642 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4643 IS_PASSABLE_INSIDE(i)));
4645 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4646 IS_PASSABLE_UNDER(i)));
4648 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4651 /* ---------- COLLECTIBLE ---------------------------------------------- */
4652 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4656 /* ---------- SNAPPABLE ------------------------------------------------ */
4657 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4658 IS_COLLECTIBLE(i) ||
4662 /* ---------- WALL ----------------------------------------------------- */
4663 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4665 for (j = 0; no_wall_properties[j] != -1; j++)
4666 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4667 i >= EL_FIRST_RUNTIME_UNREAL)
4668 SET_PROPERTY(i, EP_WALL, FALSE);
4670 if (IS_HISTORIC_WALL(i))
4671 SET_PROPERTY(i, EP_WALL, TRUE);
4673 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4674 if (engine_version < VERSION_IDENT(2,2,0,0))
4675 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4677 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4679 !IS_COLLECTIBLE(i)));
4681 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4682 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4683 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4685 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4686 IS_INDESTRUCTIBLE(i)));
4688 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4690 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4691 else if (engine_version < VERSION_IDENT(2,2,0,0))
4692 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4694 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4698 if (IS_CUSTOM_ELEMENT(i))
4700 /* these are additional properties which are initially false when set */
4702 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4704 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4705 if (DONT_COLLIDE_WITH(i))
4706 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4708 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4709 if (CAN_SMASH_EVERYTHING(i))
4710 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4711 if (CAN_SMASH_ENEMIES(i))
4712 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4715 /* ---------- CAN_SMASH ------------------------------------------------ */
4716 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4717 CAN_SMASH_ENEMIES(i) ||
4718 CAN_SMASH_EVERYTHING(i)));
4720 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4721 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4722 EXPLODES_BY_FIRE(i)));
4724 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4725 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4726 EXPLODES_SMASHED(i)));
4728 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4729 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4730 EXPLODES_IMPACT(i)));
4732 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4733 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4735 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4736 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4737 i == EL_BLACK_ORB));
4739 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4740 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4742 IS_CUSTOM_ELEMENT(i)));
4744 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4745 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4746 i == EL_SP_ELECTRON));
4748 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4749 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4750 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4751 getMoveIntoAcidProperty(&level, i));
4753 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4754 if (MAYBE_DONT_COLLIDE_WITH(i))
4755 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4756 getDontCollideWithProperty(&level, i));
4758 /* ---------- SP_PORT -------------------------------------------------- */
4759 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4760 IS_PASSABLE_INSIDE(i)));
4762 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4763 for (j = 0; j < level.num_android_clone_elements; j++)
4764 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4766 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4768 /* ---------- CAN_CHANGE ----------------------------------------------- */
4769 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4770 for (j = 0; j < element_info[i].num_change_pages; j++)
4771 if (element_info[i].change_page[j].can_change)
4772 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4774 /* ---------- HAS_ACTION ----------------------------------------------- */
4775 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4776 for (j = 0; j < element_info[i].num_change_pages; j++)
4777 if (element_info[i].change_page[j].has_action)
4778 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4780 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4781 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4784 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4786 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4787 element_info[i].crumbled[ACTION_DEFAULT] !=
4788 element_info[i].graphic[ACTION_DEFAULT]);
4790 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
4791 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4792 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
4795 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4796 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4797 IS_EDITOR_CASCADE_INACTIVE(i)));
4800 /* dynamically adjust element properties according to game engine version */
4802 static int ep_em_slippery_wall[] =
4807 EL_EXPANDABLE_WALL_HORIZONTAL,
4808 EL_EXPANDABLE_WALL_VERTICAL,
4809 EL_EXPANDABLE_WALL_ANY,
4810 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4811 EL_EXPANDABLE_STEELWALL_VERTICAL,
4812 EL_EXPANDABLE_STEELWALL_ANY,
4813 EL_EXPANDABLE_STEELWALL_GROWING,
4817 /* special EM style gems behaviour */
4818 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4819 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4820 level.em_slippery_gems);
4822 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4823 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4824 (level.em_slippery_gems &&
4825 engine_version > VERSION_IDENT(2,0,1,0)));
4828 /* this is needed because some graphics depend on element properties */
4829 if (game_status == GAME_MODE_PLAYING)
4830 InitElementGraphicInfo();
4833 void InitElementPropertiesAfterLoading(int engine_version)
4837 /* set some other uninitialized values of custom elements in older levels */
4838 if (engine_version < VERSION_IDENT(3,1,0,0))
4840 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4842 int element = EL_CUSTOM_START + i;
4844 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4846 element_info[element].explosion_delay = 17;
4847 element_info[element].ignition_delay = 8;
4852 static void InitGlobal()
4857 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4859 /* check if element_name_info entry defined for each element in "main.h" */
4860 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4861 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4863 element_info[i].token_name = element_name_info[i].token_name;
4864 element_info[i].class_name = element_name_info[i].class_name;
4865 element_info[i].editor_description= element_name_info[i].editor_description;
4868 printf("%04d: %s\n", i, element_name_info[i].token_name);
4872 /* create hash from image config list */
4873 image_config_hash = newSetupFileHash();
4874 for (i = 0; image_config[i].token != NULL; i++)
4875 setHashEntry(image_config_hash,
4876 image_config[i].token,
4877 image_config[i].value);
4879 /* create hash from element token list */
4880 element_token_hash = newSetupFileHash();
4881 for (i = 0; element_name_info[i].token_name != NULL; i++)
4882 setHashEntry(element_token_hash,
4883 element_name_info[i].token_name,
4886 /* create hash from graphic token list */
4887 graphic_token_hash = newSetupFileHash();
4888 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4889 if (strSuffix(image_config[i].value, ".pcx") ||
4890 strSuffix(image_config[i].value, ".wav") ||
4891 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4892 setHashEntry(graphic_token_hash,
4893 image_config[i].token,
4894 int2str(graphic++, 0));
4896 /* create hash from font token list */
4897 font_token_hash = newSetupFileHash();
4898 for (i = 0; font_info[i].token_name != NULL; i++)
4899 setHashEntry(font_token_hash,
4900 font_info[i].token_name,
4903 /* always start with reliable default values (all elements) */
4904 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4905 ActiveElement[i] = i;
4907 /* now add all entries that have an active state (active elements) */
4908 for (i = 0; element_with_active_state[i].element != -1; i++)
4910 int element = element_with_active_state[i].element;
4911 int element_active = element_with_active_state[i].element_active;
4913 ActiveElement[element] = element_active;
4916 /* always start with reliable default values (all buttons) */
4917 for (i = 0; i < NUM_IMAGE_FILES; i++)
4918 ActiveButton[i] = i;
4920 /* now add all entries that have an active state (active buttons) */
4921 for (i = 0; button_with_active_state[i].button != -1; i++)
4923 int button = button_with_active_state[i].button;
4924 int button_active = button_with_active_state[i].button_active;
4926 ActiveButton[button] = button_active;
4929 /* always start with reliable default values (all fonts) */
4930 for (i = 0; i < NUM_FONTS; i++)
4933 /* now add all entries that have an active state (active fonts) */
4934 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4936 int font = font_with_active_state[i].font_nr;
4937 int font_active = font_with_active_state[i].font_nr_active;
4939 ActiveFont[font] = font_active;
4942 global.autoplay_leveldir = NULL;
4943 global.convert_leveldir = NULL;
4945 global.frames_per_second = 0;
4946 global.fps_slowdown = FALSE;
4947 global.fps_slowdown_factor = 1;
4949 global.border_status = GAME_MODE_MAIN;
4951 global.fading_status = GAME_MODE_MAIN;
4952 global.fading_type = TYPE_ENTER_MENU;
4956 void Execute_Command(char *command)
4960 if (strEqual(command, "print graphicsinfo.conf"))
4962 printf("# You can configure additional/alternative image files here.\n");
4963 printf("# (The entries below are default and therefore commented out.)\n");
4965 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4967 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4970 for (i = 0; image_config[i].token != NULL; i++)
4971 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
4972 image_config[i].value));
4976 else if (strEqual(command, "print soundsinfo.conf"))
4978 printf("# You can configure additional/alternative sound files here.\n");
4979 printf("# (The entries below are default and therefore commented out.)\n");
4981 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4983 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4986 for (i = 0; sound_config[i].token != NULL; i++)
4987 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4988 sound_config[i].value));
4992 else if (strEqual(command, "print musicinfo.conf"))
4994 printf("# You can configure additional/alternative music files here.\n");
4995 printf("# (The entries below are default and therefore commented out.)\n");
4997 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4999 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5002 for (i = 0; music_config[i].token != NULL; i++)
5003 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
5004 music_config[i].value));
5008 else if (strEqual(command, "print editorsetup.conf"))
5010 printf("# You can configure your personal editor element list here.\n");
5011 printf("# (The entries below are default and therefore commented out.)\n");
5014 /* this is needed to be able to check element list for cascade elements */
5015 InitElementPropertiesStatic();
5016 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5018 PrintEditorElementList();
5022 else if (strEqual(command, "print helpanim.conf"))
5024 printf("# You can configure different element help animations here.\n");
5025 printf("# (The entries below are default and therefore commented out.)\n");
5028 for (i = 0; helpanim_config[i].token != NULL; i++)
5030 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
5031 helpanim_config[i].value));
5033 if (strEqual(helpanim_config[i].token, "end"))
5039 else if (strEqual(command, "print helptext.conf"))
5041 printf("# You can configure different element help text here.\n");
5042 printf("# (The entries below are default and therefore commented out.)\n");
5045 for (i = 0; helptext_config[i].token != NULL; i++)
5046 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
5047 helptext_config[i].value));
5051 else if (strncmp(command, "dump level ", 11) == 0)
5053 char *filename = &command[11];
5055 if (!fileExists(filename))
5056 Error(ERR_EXIT, "cannot open file '%s'", filename);
5058 LoadLevelFromFilename(&level, filename);
5063 else if (strncmp(command, "dump tape ", 10) == 0)
5065 char *filename = &command[10];
5067 if (!fileExists(filename))
5068 Error(ERR_EXIT, "cannot open file '%s'", filename);
5070 LoadTapeFromFilename(filename);
5075 else if (strncmp(command, "autoplay ", 9) == 0)
5077 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
5079 while (*str_ptr != '\0') /* continue parsing string */
5081 /* cut leading whitespace from string, replace it by string terminator */
5082 while (*str_ptr == ' ' || *str_ptr == '\t')
5085 if (*str_ptr == '\0') /* end of string reached */
5088 if (global.autoplay_leveldir == NULL) /* read level set string */
5090 global.autoplay_leveldir = str_ptr;
5091 global.autoplay_all = TRUE; /* default: play all tapes */
5093 for (i = 0; i < MAX_TAPES_PER_SET; i++)
5094 global.autoplay_level[i] = FALSE;
5096 else /* read level number string */
5098 int level_nr = atoi(str_ptr); /* get level_nr value */
5100 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5101 global.autoplay_level[level_nr] = TRUE;
5103 global.autoplay_all = FALSE;
5106 /* advance string pointer to the next whitespace (or end of string) */
5107 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5111 else if (strncmp(command, "convert ", 8) == 0)
5113 char *str_copy = getStringCopy(&command[8]);
5114 char *str_ptr = strchr(str_copy, ' ');
5116 global.convert_leveldir = str_copy;
5117 global.convert_level_nr = -1;
5119 if (str_ptr != NULL) /* level number follows */
5121 *str_ptr++ = '\0'; /* terminate leveldir string */
5122 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
5127 #if defined(TARGET_SDL)
5128 else if (strEqual(command, "SDL_ListModes"))
5133 SDL_Init(SDL_INIT_VIDEO);
5135 /* get available fullscreen/hardware modes */
5136 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
5138 /* check if there are any modes available */
5141 printf("No modes available!\n");
5146 /* check if our resolution is restricted */
5147 if (modes == (SDL_Rect **)-1)
5149 printf("All resolutions available.\n");
5153 printf("Available Modes:\n");
5155 for(i = 0; modes[i]; i++)
5156 printf(" %d x %d\n", modes[i]->w, modes[i]->h);
5166 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
5170 static void InitSetup()
5172 LoadSetup(); /* global setup info */
5174 /* set some options from setup file */
5176 if (setup.options.verbose)
5177 options.verbose = TRUE;
5180 static void InitGameInfo()
5182 game.restart_level = FALSE;
5185 static void InitPlayerInfo()
5189 /* choose default local player */
5190 local_player = &stored_player[0];
5192 for (i = 0; i < MAX_PLAYERS; i++)
5193 stored_player[i].connected = FALSE;
5195 local_player->connected = TRUE;
5198 static void InitArtworkInfo()
5203 static char *get_string_in_brackets(char *string)
5205 char *string_in_brackets = checked_malloc(strlen(string) + 3);
5207 sprintf(string_in_brackets, "[%s]", string);
5209 return string_in_brackets;
5212 static char *get_level_id_suffix(int id_nr)
5214 char *id_suffix = checked_malloc(1 + 3 + 1);
5216 if (id_nr < 0 || id_nr > 999)
5219 sprintf(id_suffix, ".%03d", id_nr);
5225 static char *get_element_class_token(int element)
5227 char *element_class_name = element_info[element].class_name;
5228 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
5230 sprintf(element_class_token, "[%s]", element_class_name);
5232 return element_class_token;
5235 static char *get_action_class_token(int action)
5237 char *action_class_name = &element_action_info[action].suffix[1];
5238 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
5240 sprintf(action_class_token, "[%s]", action_class_name);
5242 return action_class_token;
5246 static void InitArtworkConfig()
5248 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
5249 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
5250 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
5251 static char *action_id_suffix[NUM_ACTIONS + 1];
5252 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5253 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5254 static char *level_id_suffix[MAX_LEVELS + 1];
5255 static char *dummy[1] = { NULL };
5256 static char *ignore_generic_tokens[] =
5262 static char **ignore_image_tokens;
5263 static char **ignore_sound_tokens;
5264 static char **ignore_music_tokens;
5265 int num_ignore_generic_tokens;
5266 int num_ignore_image_tokens;
5267 int num_ignore_sound_tokens;
5268 int num_ignore_music_tokens;
5271 /* dynamically determine list of generic tokens to be ignored */
5272 num_ignore_generic_tokens = 0;
5273 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5274 num_ignore_generic_tokens++;
5276 /* dynamically determine list of image tokens to be ignored */
5277 num_ignore_image_tokens = num_ignore_generic_tokens;
5278 for (i = 0; image_config_vars[i].token != NULL; i++)
5279 num_ignore_image_tokens++;
5280 ignore_image_tokens =
5281 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5282 for (i = 0; i < num_ignore_generic_tokens; i++)
5283 ignore_image_tokens[i] = ignore_generic_tokens[i];
5284 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5285 ignore_image_tokens[num_ignore_generic_tokens + i] =
5286 image_config_vars[i].token;
5287 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5289 /* dynamically determine list of sound tokens to be ignored */
5290 num_ignore_sound_tokens = num_ignore_generic_tokens;
5291 ignore_sound_tokens =
5292 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5293 for (i = 0; i < num_ignore_generic_tokens; i++)
5294 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5295 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5297 /* dynamically determine list of music tokens to be ignored */
5298 num_ignore_music_tokens = num_ignore_generic_tokens;
5299 ignore_music_tokens =
5300 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5301 for (i = 0; i < num_ignore_generic_tokens; i++)
5302 ignore_music_tokens[i] = ignore_generic_tokens[i];
5303 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5305 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5306 image_id_prefix[i] = element_info[i].token_name;
5307 for (i = 0; i < NUM_FONTS; i++)
5308 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5309 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
5311 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5312 sound_id_prefix[i] = element_info[i].token_name;
5313 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5314 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5315 get_string_in_brackets(element_info[i].class_name);
5316 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
5318 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5319 music_id_prefix[i] = music_prefix_info[i].prefix;
5320 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
5322 for (i = 0; i < NUM_ACTIONS; i++)
5323 action_id_suffix[i] = element_action_info[i].suffix;
5324 action_id_suffix[NUM_ACTIONS] = NULL;
5326 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5327 direction_id_suffix[i] = element_direction_info[i].suffix;
5328 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5330 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5331 special_id_suffix[i] = special_suffix_info[i].suffix;
5332 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5334 for (i = 0; i < MAX_LEVELS; i++)
5335 level_id_suffix[i] = get_level_id_suffix(i);
5336 level_id_suffix[MAX_LEVELS] = NULL;
5338 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5339 image_id_prefix, action_id_suffix, direction_id_suffix,
5340 special_id_suffix, ignore_image_tokens);
5341 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5342 sound_id_prefix, action_id_suffix, dummy,
5343 special_id_suffix, ignore_sound_tokens);
5344 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5345 music_id_prefix, special_id_suffix, level_id_suffix,
5346 dummy, ignore_music_tokens);
5349 static void InitMixer()
5357 char *filename_font_initial = NULL;
5358 char *filename_anim_initial = NULL;
5359 Bitmap *bitmap_font_initial = NULL;
5363 /* determine settings for initial font (for displaying startup messages) */
5364 for (i = 0; image_config[i].token != NULL; i++)
5366 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5368 char font_token[128];
5371 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5372 len_font_token = strlen(font_token);
5374 if (strEqual(image_config[i].token, font_token))
5375 filename_font_initial = image_config[i].value;
5376 else if (strlen(image_config[i].token) > len_font_token &&
5377 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5379 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5380 font_initial[j].src_x = atoi(image_config[i].value);
5381 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5382 font_initial[j].src_y = atoi(image_config[i].value);
5383 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5384 font_initial[j].width = atoi(image_config[i].value);
5385 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5386 font_initial[j].height = atoi(image_config[i].value);
5391 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5393 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5394 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5397 if (filename_font_initial == NULL) /* should not happen */
5398 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5400 /* create additional image buffers for double-buffering and cross-fading */
5401 bitmap_db_cross = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5402 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
5403 bitmap_db_panel = CreateBitmap(DXSIZE, DYSIZE, DEFAULT_DEPTH);
5404 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
5406 /* initialize screen properties */
5407 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5408 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5410 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5411 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5412 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5414 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5416 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5417 font_initial[j].bitmap = bitmap_font_initial;
5419 InitFontGraphicInfo();
5421 font_height = getFontHeight(FC_RED);
5424 DrawInitText(getWindowTitleString(), 20, FC_YELLOW);
5426 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
5428 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
5429 DrawInitText(PROGRAM_WEBSITE_STRING, WIN_YSIZE - 20 - font_height, FC_RED);
5431 DrawInitText("Loading graphics", 120, FC_GREEN);
5435 /* initialize busy animation with default values */
5436 int parameter[NUM_GFX_ARGS];
5437 for (i = 0; i < NUM_GFX_ARGS; i++)
5438 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5439 image_config_suffix[i].token,
5440 image_config_suffix[i].type);
5442 for (i = 0; i < NUM_GFX_ARGS; i++)
5443 printf("::: '%s' => %d\n", image_config_suffix[i].token, parameter[i]);
5447 /* determine settings for busy animation (when displaying startup messages) */
5448 for (i = 0; image_config[i].token != NULL; i++)
5450 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5451 int len_anim_token = strlen(anim_token);
5453 if (strEqual(image_config[i].token, anim_token))
5454 filename_anim_initial = image_config[i].value;
5455 else if (strlen(image_config[i].token) > len_anim_token &&
5456 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5459 for (j = 0; image_config_suffix[j].token != NULL; j++)
5461 if (strEqual(&image_config[i].token[len_anim_token],
5462 image_config_suffix[j].token))
5464 get_graphic_parameter_value(image_config[i].value,
5465 image_config_suffix[j].token,
5466 image_config_suffix[j].type);
5469 if (strEqual(&image_config[i].token[len_anim_token], ".x"))
5470 anim_initial.src_x = atoi(image_config[i].value);
5471 else if (strEqual(&image_config[i].token[len_anim_token], ".y"))
5472 anim_initial.src_y = atoi(image_config[i].value);
5473 else if (strEqual(&image_config[i].token[len_anim_token], ".width"))
5474 anim_initial.width = atoi(image_config[i].value);
5475 else if (strEqual(&image_config[i].token[len_anim_token], ".height"))
5476 anim_initial.height = atoi(image_config[i].value);
5477 else if (strEqual(&image_config[i].token[len_anim_token], ".frames"))
5478 anim_initial.anim_frames = atoi(image_config[i].value);
5479 else if (strEqual(&image_config[i].token[len_anim_token],
5480 ".frames_per_line"))
5481 anim_initial.anim_frames_per_line = atoi(image_config[i].value);
5482 else if (strEqual(&image_config[i].token[len_anim_token], ".delay"))
5483 anim_initial.anim_delay = atoi(image_config[i].value);
5488 set_graphic_parameters_ext(0, &anim_initial, parameter, NULL);
5490 if (filename_anim_initial == NULL) /* should not happen */
5491 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5493 anim_initial.bitmap = LoadCustomImage(filename_anim_initial);
5495 init.busy.width = anim_initial.width;
5496 init.busy.height = anim_initial.height;
5498 InitMenuDesignSettings_Static();
5499 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5503 void RedrawBackground()
5505 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
5506 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
5508 redraw_mask = REDRAW_ALL;
5511 void InitGfxBackground()
5515 fieldbuffer = bitmap_db_field;
5516 SetDrawtoField(DRAW_BACKBUFFER);
5519 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5523 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
5524 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
5527 for (x = 0; x < MAX_BUF_XSIZE; x++)
5528 for (y = 0; y < MAX_BUF_YSIZE; y++)
5531 redraw_mask = REDRAW_ALL;
5534 static void InitLevelInfo()
5536 LoadLevelInfo(); /* global level info */
5537 LoadLevelSetup_LastSeries(); /* last played series info */
5538 LoadLevelSetup_SeriesInfo(); /* last played level info */
5541 void InitLevelArtworkInfo()
5543 LoadLevelArtworkInfo();
5546 static void InitImages()
5548 print_timestamp_init("InitImages");
5550 setLevelArtworkDir(artwork.gfx_first);
5553 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5554 leveldir_current->identifier,
5555 artwork.gfx_current_identifier,
5556 artwork.gfx_current->identifier,
5557 leveldir_current->graphics_set,
5558 leveldir_current->graphics_path);
5561 UPDATE_BUSY_STATE();
5563 ReloadCustomImages();
5564 print_timestamp_time("ReloadCustomImages");
5566 UPDATE_BUSY_STATE();
5568 LoadCustomElementDescriptions();
5569 print_timestamp_time("LoadCustomElementDescriptions");
5571 UPDATE_BUSY_STATE();
5573 LoadMenuDesignSettings();
5574 print_timestamp_time("LoadMenuDesignSettings");
5576 UPDATE_BUSY_STATE();
5578 ReinitializeGraphics();
5579 print_timestamp_time("ReinitializeGraphics");
5581 UPDATE_BUSY_STATE();
5583 print_timestamp_done("InitImages");
5586 static void InitSound(char *identifier)
5588 print_timestamp_init("InitSound");
5590 if (identifier == NULL)
5591 identifier = artwork.snd_current->identifier;
5593 /* set artwork path to send it to the sound server process */
5594 setLevelArtworkDir(artwork.snd_first);
5596 InitReloadCustomSounds(identifier);
5597 print_timestamp_time("InitReloadCustomSounds");
5599 ReinitializeSounds();
5600 print_timestamp_time("ReinitializeSounds");
5602 print_timestamp_done("InitSound");
5605 static void InitMusic(char *identifier)
5607 print_timestamp_init("InitMusic");
5609 if (identifier == NULL)
5610 identifier = artwork.mus_current->identifier;
5612 /* set artwork path to send it to the sound server process */
5613 setLevelArtworkDir(artwork.mus_first);
5615 InitReloadCustomMusic(identifier);
5616 print_timestamp_time("InitReloadCustomMusic");
5618 ReinitializeMusic();
5619 print_timestamp_time("ReinitializeMusic");
5621 print_timestamp_done("InitMusic");
5624 void InitNetworkServer()
5626 #if defined(NETWORK_AVALIABLE)
5630 if (!options.network)
5633 #if defined(NETWORK_AVALIABLE)
5634 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5636 if (!ConnectToServer(options.server_host, options.server_port))
5637 Error(ERR_EXIT, "cannot connect to network game server");
5639 SendToServer_PlayerName(setup.player_name);
5640 SendToServer_ProtocolVersion();
5643 SendToServer_NrWanted(nr_wanted);
5647 static char *getNewArtworkIdentifier(int type)
5649 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5650 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5651 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5652 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5653 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5654 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
5655 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5656 char *leveldir_identifier = leveldir_current->identifier;
5658 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
5659 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5661 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
5663 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5664 char *artwork_current_identifier;
5665 char *artwork_new_identifier = NULL; /* default: nothing has changed */
5667 /* leveldir_current may be invalid (level group, parent link) */
5668 if (!validLevelSeries(leveldir_current))
5671 /* 1st step: determine artwork set to be activated in descending order:
5672 --------------------------------------------------------------------
5673 1. setup artwork (when configured to override everything else)
5674 2. artwork set configured in "levelinfo.conf" of current level set
5675 (artwork in level directory will have priority when loading later)
5676 3. artwork in level directory (stored in artwork sub-directory)
5677 4. setup artwork (currently configured in setup menu) */
5679 if (setup_override_artwork)
5680 artwork_current_identifier = setup_artwork_set;
5681 else if (leveldir_artwork_set != NULL)
5682 artwork_current_identifier = leveldir_artwork_set;
5683 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5684 artwork_current_identifier = leveldir_identifier;
5686 artwork_current_identifier = setup_artwork_set;
5689 /* 2nd step: check if it is really needed to reload artwork set
5690 ------------------------------------------------------------ */
5693 if (type == ARTWORK_TYPE_GRAPHICS)
5694 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
5695 artwork_new_identifier,
5696 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5697 artwork_current_identifier,
5698 leveldir_current->graphics_set,
5699 leveldir_current->identifier);
5702 /* ---------- reload if level set and also artwork set has changed ------- */
5703 if (leveldir_current_identifier[type] != leveldir_identifier &&
5704 (last_has_level_artwork_set[type] || has_level_artwork_set))
5705 artwork_new_identifier = artwork_current_identifier;
5707 leveldir_current_identifier[type] = leveldir_identifier;
5708 last_has_level_artwork_set[type] = has_level_artwork_set;
5711 if (type == ARTWORK_TYPE_GRAPHICS)
5712 printf("::: 1: '%s'\n", artwork_new_identifier);
5715 /* ---------- reload if "override artwork" setting has changed ----------- */
5716 if (last_override_level_artwork[type] != setup_override_artwork)
5717 artwork_new_identifier = artwork_current_identifier;
5719 last_override_level_artwork[type] = setup_override_artwork;
5722 if (type == ARTWORK_TYPE_GRAPHICS)
5723 printf("::: 2: '%s'\n", artwork_new_identifier);
5726 /* ---------- reload if current artwork identifier has changed ----------- */
5727 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5728 artwork_current_identifier))
5729 artwork_new_identifier = artwork_current_identifier;
5731 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5734 if (type == ARTWORK_TYPE_GRAPHICS)
5735 printf("::: 3: '%s'\n", artwork_new_identifier);
5738 /* ---------- do not reload directly after starting ---------------------- */
5739 if (!initialized[type])
5740 artwork_new_identifier = NULL;
5742 initialized[type] = TRUE;
5745 if (type == ARTWORK_TYPE_GRAPHICS)
5746 printf("::: 4: '%s'\n", artwork_new_identifier);
5750 if (type == ARTWORK_TYPE_GRAPHICS)
5751 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
5752 artwork.gfx_current_identifier, artwork_current_identifier,
5753 artwork.gfx_current->identifier, leveldir_current->graphics_set,
5754 artwork_new_identifier);
5757 return artwork_new_identifier;
5760 void ReloadCustomArtwork(int force_reload)
5762 int last_game_status = game_status; /* save current game status */
5763 char *gfx_new_identifier;
5764 char *snd_new_identifier;
5765 char *mus_new_identifier;
5766 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5767 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5768 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5769 boolean reload_needed;
5771 force_reload_gfx |= AdjustGraphicsForEMC();
5773 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5774 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5775 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5777 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
5778 snd_new_identifier != NULL || force_reload_snd ||
5779 mus_new_identifier != NULL || force_reload_mus);
5784 print_timestamp_init("ReloadCustomArtwork");
5786 game_status = GAME_MODE_LOADING;
5788 FadeOut(REDRAW_ALL);
5791 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5793 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
5795 print_timestamp_time("ClearRectangle");
5798 printf("::: fading in ... %d\n", fading.fade_mode);
5802 printf("::: done\n");
5805 if (gfx_new_identifier != NULL || force_reload_gfx)
5808 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5809 artwork.gfx_current_identifier,
5811 artwork.gfx_current->identifier,
5812 leveldir_current->graphics_set);
5816 print_timestamp_time("InitImages");
5819 if (snd_new_identifier != NULL || force_reload_snd)
5821 InitSound(snd_new_identifier);
5822 print_timestamp_time("InitSound");
5825 if (mus_new_identifier != NULL || force_reload_mus)
5827 InitMusic(mus_new_identifier);
5828 print_timestamp_time("InitMusic");
5831 game_status = last_game_status; /* restore current game status */
5834 printf("::: FadeOut @ ReloadCustomArtwork ...\n");
5836 FadeOut(REDRAW_ALL);
5838 printf("::: FadeOut @ ReloadCustomArtwork done\n");
5843 /* force redraw of (open or closed) door graphics */
5844 SetDoorState(DOOR_OPEN_ALL);
5845 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5849 FadeSetEnterScreen();
5850 FadeSkipNextFadeOut();
5851 // FadeSetDisabled();
5856 fading = fading_none;
5859 print_timestamp_done("ReloadCustomArtwork");
5862 void KeyboardAutoRepeatOffUnlessAutoplay()
5864 if (global.autoplay_leveldir == NULL)
5865 KeyboardAutoRepeatOff();
5869 /* ========================================================================= */
5871 /* ========================================================================= */
5875 print_timestamp_init("OpenAll");
5877 game_status = GAME_MODE_LOADING;
5879 InitGlobal(); /* initialize some global variables */
5881 if (options.execute_command)
5882 Execute_Command(options.execute_command);
5884 if (options.serveronly)
5886 #if defined(PLATFORM_UNIX)
5887 NetworkServer(options.server_port, options.serveronly);
5889 Error(ERR_WARN, "networking only supported in Unix version");
5892 exit(0); /* never reached, server loops forever */
5899 InitArtworkInfo(); /* needed before loading gfx, sound & music */
5900 InitArtworkConfig(); /* needed before forking sound child process */
5905 InitRND(NEW_RANDOMIZE);
5906 InitSimpleRandom(NEW_RANDOMIZE);
5910 print_timestamp_time("[pre-video]");
5913 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
5915 InitEventFilter(FilterMouseMotionEvents);
5917 InitElementPropertiesStatic();
5918 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5920 print_timestamp_time("[post-video]");
5924 print_timestamp_time("InitGfx");
5927 print_timestamp_time("InitLevelInfo");
5929 InitLevelArtworkInfo();
5930 print_timestamp_time("InitLevelArtworkInfo");
5932 InitImages(); /* needs to know current level directory */
5933 print_timestamp_time("InitImages");
5935 InitSound(NULL); /* needs to know current level directory */
5936 print_timestamp_time("InitSound");
5938 InitMusic(NULL); /* needs to know current level directory */
5939 print_timestamp_time("InitMusic");
5941 InitGfxBackground();
5947 if (global.autoplay_leveldir)
5952 else if (global.convert_leveldir)
5958 game_status = GAME_MODE_MAIN;
5961 FadeSetEnterScreen();
5962 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
5963 FadeSkipNextFadeOut();
5964 // FadeSetDisabled();
5966 fading = fading_none;
5969 print_timestamp_time("[post-artwork]");
5971 print_timestamp_done("OpenAll");
5975 InitNetworkServer();
5978 void CloseAllAndExit(int exit_value)
5983 CloseAudio(); /* called after freeing sounds (needed for SDL) */
5991 #if defined(TARGET_SDL)
5992 if (network_server) /* terminate network server */
5993 SDL_KillThread(server_thread);
5996 CloseVideoDisplay();
5997 ClosePlatformDependentStuff();
5999 if (exit_value != 0)
6000 NotifyUserAboutErrorFile();