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 boolean clipboard_elements_initialized = FALSE;
2610 static int ep_diggable[] =
2615 EL_SP_BUGGY_BASE_ACTIVATING,
2618 EL_INVISIBLE_SAND_ACTIVE,
2621 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2622 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2627 EL_SP_BUGGY_BASE_ACTIVE,
2634 static int ep_collectible_only[] =
2656 EL_DYNABOMB_INCREASE_NUMBER,
2657 EL_DYNABOMB_INCREASE_SIZE,
2658 EL_DYNABOMB_INCREASE_POWER,
2676 /* !!! handle separately !!! */
2677 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2683 static int ep_dont_run_into[] =
2685 /* same elements as in 'ep_dont_touch' */
2691 /* same elements as in 'ep_dont_collide_with' */
2703 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2708 EL_SP_BUGGY_BASE_ACTIVE,
2715 static int ep_dont_collide_with[] =
2717 /* same elements as in 'ep_dont_touch' */
2734 static int ep_dont_touch[] =
2744 static int ep_indestructible[] =
2748 EL_ACID_POOL_TOPLEFT,
2749 EL_ACID_POOL_TOPRIGHT,
2750 EL_ACID_POOL_BOTTOMLEFT,
2751 EL_ACID_POOL_BOTTOM,
2752 EL_ACID_POOL_BOTTOMRIGHT,
2753 EL_SP_HARDWARE_GRAY,
2754 EL_SP_HARDWARE_GREEN,
2755 EL_SP_HARDWARE_BLUE,
2757 EL_SP_HARDWARE_YELLOW,
2758 EL_SP_HARDWARE_BASE_1,
2759 EL_SP_HARDWARE_BASE_2,
2760 EL_SP_HARDWARE_BASE_3,
2761 EL_SP_HARDWARE_BASE_4,
2762 EL_SP_HARDWARE_BASE_5,
2763 EL_SP_HARDWARE_BASE_6,
2764 EL_INVISIBLE_STEELWALL,
2765 EL_INVISIBLE_STEELWALL_ACTIVE,
2766 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2767 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2768 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2769 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2770 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2771 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2772 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2773 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2774 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2775 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2776 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2777 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2779 EL_LIGHT_SWITCH_ACTIVE,
2780 EL_SIGN_EXCLAMATION,
2781 EL_SIGN_RADIOACTIVITY,
2788 EL_SIGN_ENTRY_FORBIDDEN,
2789 EL_SIGN_EMERGENCY_EXIT,
2797 EL_STEEL_EXIT_CLOSED,
2799 EL_EM_STEEL_EXIT_CLOSED,
2800 EL_EM_STEEL_EXIT_OPEN,
2801 EL_DC_STEELWALL_1_LEFT,
2802 EL_DC_STEELWALL_1_RIGHT,
2803 EL_DC_STEELWALL_1_TOP,
2804 EL_DC_STEELWALL_1_BOTTOM,
2805 EL_DC_STEELWALL_1_HORIZONTAL,
2806 EL_DC_STEELWALL_1_VERTICAL,
2807 EL_DC_STEELWALL_1_TOPLEFT,
2808 EL_DC_STEELWALL_1_TOPRIGHT,
2809 EL_DC_STEELWALL_1_BOTTOMLEFT,
2810 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2811 EL_DC_STEELWALL_1_TOPLEFT_2,
2812 EL_DC_STEELWALL_1_TOPRIGHT_2,
2813 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2814 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2815 EL_DC_STEELWALL_2_LEFT,
2816 EL_DC_STEELWALL_2_RIGHT,
2817 EL_DC_STEELWALL_2_TOP,
2818 EL_DC_STEELWALL_2_BOTTOM,
2819 EL_DC_STEELWALL_2_HORIZONTAL,
2820 EL_DC_STEELWALL_2_VERTICAL,
2821 EL_DC_STEELWALL_2_MIDDLE,
2822 EL_DC_STEELWALL_2_SINGLE,
2823 EL_STEELWALL_SLIPPERY,
2837 EL_GATE_1_GRAY_ACTIVE,
2838 EL_GATE_2_GRAY_ACTIVE,
2839 EL_GATE_3_GRAY_ACTIVE,
2840 EL_GATE_4_GRAY_ACTIVE,
2849 EL_EM_GATE_1_GRAY_ACTIVE,
2850 EL_EM_GATE_2_GRAY_ACTIVE,
2851 EL_EM_GATE_3_GRAY_ACTIVE,
2852 EL_EM_GATE_4_GRAY_ACTIVE,
2861 EL_EMC_GATE_5_GRAY_ACTIVE,
2862 EL_EMC_GATE_6_GRAY_ACTIVE,
2863 EL_EMC_GATE_7_GRAY_ACTIVE,
2864 EL_EMC_GATE_8_GRAY_ACTIVE,
2866 EL_DC_GATE_WHITE_GRAY,
2867 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2868 EL_DC_GATE_FAKE_GRAY,
2870 EL_SWITCHGATE_OPENING,
2871 EL_SWITCHGATE_CLOSED,
2872 EL_SWITCHGATE_CLOSING,
2874 EL_DC_SWITCHGATE_SWITCH_UP,
2875 EL_DC_SWITCHGATE_SWITCH_DOWN,
2878 EL_TIMEGATE_OPENING,
2880 EL_TIMEGATE_CLOSING,
2882 EL_DC_TIMEGATE_SWITCH,
2883 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2888 EL_TUBE_VERTICAL_LEFT,
2889 EL_TUBE_VERTICAL_RIGHT,
2890 EL_TUBE_HORIZONTAL_UP,
2891 EL_TUBE_HORIZONTAL_DOWN,
2896 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2897 EL_EXPANDABLE_STEELWALL_VERTICAL,
2898 EL_EXPANDABLE_STEELWALL_ANY,
2903 static int ep_slippery[] =
2917 EL_ROBOT_WHEEL_ACTIVE,
2923 EL_ACID_POOL_TOPLEFT,
2924 EL_ACID_POOL_TOPRIGHT,
2934 EL_STEELWALL_SLIPPERY,
2937 EL_EMC_WALL_SLIPPERY_1,
2938 EL_EMC_WALL_SLIPPERY_2,
2939 EL_EMC_WALL_SLIPPERY_3,
2940 EL_EMC_WALL_SLIPPERY_4,
2942 EL_EMC_MAGIC_BALL_ACTIVE,
2947 static int ep_can_change[] =
2952 static int ep_can_move[] =
2954 /* same elements as in 'pb_can_move_into_acid' */
2977 static int ep_can_fall[] =
2991 EL_QUICKSAND_FAST_FULL,
2993 EL_BD_MAGIC_WALL_FULL,
2994 EL_DC_MAGIC_WALL_FULL,
3008 static int ep_can_smash_player[] =
3034 static int ep_can_smash_enemies[] =
3043 static int ep_can_smash_everything[] =
3052 static int ep_explodes_by_fire[] =
3054 /* same elements as in 'ep_explodes_impact' */
3059 /* same elements as in 'ep_explodes_smashed' */
3069 EL_EM_DYNAMITE_ACTIVE,
3070 EL_DYNABOMB_PLAYER_1_ACTIVE,
3071 EL_DYNABOMB_PLAYER_2_ACTIVE,
3072 EL_DYNABOMB_PLAYER_3_ACTIVE,
3073 EL_DYNABOMB_PLAYER_4_ACTIVE,
3074 EL_DYNABOMB_INCREASE_NUMBER,
3075 EL_DYNABOMB_INCREASE_SIZE,
3076 EL_DYNABOMB_INCREASE_POWER,
3077 EL_SP_DISK_RED_ACTIVE,
3091 static int ep_explodes_smashed[] =
3093 /* same elements as in 'ep_explodes_impact' */
3107 static int ep_explodes_impact[] =
3116 static int ep_walkable_over[] =
3120 EL_SOKOBAN_FIELD_EMPTY,
3126 EL_EM_STEEL_EXIT_OPEN,
3135 EL_GATE_1_GRAY_ACTIVE,
3136 EL_GATE_2_GRAY_ACTIVE,
3137 EL_GATE_3_GRAY_ACTIVE,
3138 EL_GATE_4_GRAY_ACTIVE,
3146 static int ep_walkable_inside[] =
3151 EL_TUBE_VERTICAL_LEFT,
3152 EL_TUBE_VERTICAL_RIGHT,
3153 EL_TUBE_HORIZONTAL_UP,
3154 EL_TUBE_HORIZONTAL_DOWN,
3163 static int ep_walkable_under[] =
3168 static int ep_passable_over[] =
3178 EL_EM_GATE_1_GRAY_ACTIVE,
3179 EL_EM_GATE_2_GRAY_ACTIVE,
3180 EL_EM_GATE_3_GRAY_ACTIVE,
3181 EL_EM_GATE_4_GRAY_ACTIVE,
3190 EL_EMC_GATE_5_GRAY_ACTIVE,
3191 EL_EMC_GATE_6_GRAY_ACTIVE,
3192 EL_EMC_GATE_7_GRAY_ACTIVE,
3193 EL_EMC_GATE_8_GRAY_ACTIVE,
3195 EL_DC_GATE_WHITE_GRAY,
3196 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3203 static int ep_passable_inside[] =
3209 EL_SP_PORT_HORIZONTAL,
3210 EL_SP_PORT_VERTICAL,
3212 EL_SP_GRAVITY_PORT_LEFT,
3213 EL_SP_GRAVITY_PORT_RIGHT,
3214 EL_SP_GRAVITY_PORT_UP,
3215 EL_SP_GRAVITY_PORT_DOWN,
3216 EL_SP_GRAVITY_ON_PORT_LEFT,
3217 EL_SP_GRAVITY_ON_PORT_RIGHT,
3218 EL_SP_GRAVITY_ON_PORT_UP,
3219 EL_SP_GRAVITY_ON_PORT_DOWN,
3220 EL_SP_GRAVITY_OFF_PORT_LEFT,
3221 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3222 EL_SP_GRAVITY_OFF_PORT_UP,
3223 EL_SP_GRAVITY_OFF_PORT_DOWN,
3228 static int ep_passable_under[] =
3233 static int ep_droppable[] =
3238 static int ep_explodes_1x1_old[] =
3243 static int ep_pushable[] =
3255 EL_SOKOBAN_FIELD_FULL,
3264 static int ep_explodes_cross_old[] =
3269 static int ep_protected[] =
3271 /* same elements as in 'ep_walkable_inside' */
3275 EL_TUBE_VERTICAL_LEFT,
3276 EL_TUBE_VERTICAL_RIGHT,
3277 EL_TUBE_HORIZONTAL_UP,
3278 EL_TUBE_HORIZONTAL_DOWN,
3284 /* same elements as in 'ep_passable_over' */
3293 EL_EM_GATE_1_GRAY_ACTIVE,
3294 EL_EM_GATE_2_GRAY_ACTIVE,
3295 EL_EM_GATE_3_GRAY_ACTIVE,
3296 EL_EM_GATE_4_GRAY_ACTIVE,
3305 EL_EMC_GATE_5_GRAY_ACTIVE,
3306 EL_EMC_GATE_6_GRAY_ACTIVE,
3307 EL_EMC_GATE_7_GRAY_ACTIVE,
3308 EL_EMC_GATE_8_GRAY_ACTIVE,
3310 EL_DC_GATE_WHITE_GRAY,
3311 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3315 /* same elements as in 'ep_passable_inside' */
3320 EL_SP_PORT_HORIZONTAL,
3321 EL_SP_PORT_VERTICAL,
3323 EL_SP_GRAVITY_PORT_LEFT,
3324 EL_SP_GRAVITY_PORT_RIGHT,
3325 EL_SP_GRAVITY_PORT_UP,
3326 EL_SP_GRAVITY_PORT_DOWN,
3327 EL_SP_GRAVITY_ON_PORT_LEFT,
3328 EL_SP_GRAVITY_ON_PORT_RIGHT,
3329 EL_SP_GRAVITY_ON_PORT_UP,
3330 EL_SP_GRAVITY_ON_PORT_DOWN,
3331 EL_SP_GRAVITY_OFF_PORT_LEFT,
3332 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3333 EL_SP_GRAVITY_OFF_PORT_UP,
3334 EL_SP_GRAVITY_OFF_PORT_DOWN,
3339 static int ep_throwable[] =
3344 static int ep_can_explode[] =
3346 /* same elements as in 'ep_explodes_impact' */
3351 /* same elements as in 'ep_explodes_smashed' */
3357 /* elements that can explode by explosion or by dragonfire */
3361 EL_EM_DYNAMITE_ACTIVE,
3362 EL_DYNABOMB_PLAYER_1_ACTIVE,
3363 EL_DYNABOMB_PLAYER_2_ACTIVE,
3364 EL_DYNABOMB_PLAYER_3_ACTIVE,
3365 EL_DYNABOMB_PLAYER_4_ACTIVE,
3366 EL_DYNABOMB_INCREASE_NUMBER,
3367 EL_DYNABOMB_INCREASE_SIZE,
3368 EL_DYNABOMB_INCREASE_POWER,
3369 EL_SP_DISK_RED_ACTIVE,
3377 /* elements that can explode only by explosion */
3383 static int ep_gravity_reachable[] =
3389 EL_INVISIBLE_SAND_ACTIVE,
3394 EL_SP_PORT_HORIZONTAL,
3395 EL_SP_PORT_VERTICAL,
3397 EL_SP_GRAVITY_PORT_LEFT,
3398 EL_SP_GRAVITY_PORT_RIGHT,
3399 EL_SP_GRAVITY_PORT_UP,
3400 EL_SP_GRAVITY_PORT_DOWN,
3401 EL_SP_GRAVITY_ON_PORT_LEFT,
3402 EL_SP_GRAVITY_ON_PORT_RIGHT,
3403 EL_SP_GRAVITY_ON_PORT_UP,
3404 EL_SP_GRAVITY_ON_PORT_DOWN,
3405 EL_SP_GRAVITY_OFF_PORT_LEFT,
3406 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3407 EL_SP_GRAVITY_OFF_PORT_UP,
3408 EL_SP_GRAVITY_OFF_PORT_DOWN,
3414 static int ep_player[] =
3421 EL_SOKOBAN_FIELD_PLAYER,
3427 static int ep_can_pass_magic_wall[] =
3441 static int ep_can_pass_dc_magic_wall[] =
3457 static int ep_switchable[] =
3461 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3462 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3463 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3464 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3465 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3466 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3467 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3468 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3469 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3470 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3471 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3472 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3473 EL_SWITCHGATE_SWITCH_UP,
3474 EL_SWITCHGATE_SWITCH_DOWN,
3475 EL_DC_SWITCHGATE_SWITCH_UP,
3476 EL_DC_SWITCHGATE_SWITCH_DOWN,
3478 EL_LIGHT_SWITCH_ACTIVE,
3480 EL_DC_TIMEGATE_SWITCH,
3481 EL_BALLOON_SWITCH_LEFT,
3482 EL_BALLOON_SWITCH_RIGHT,
3483 EL_BALLOON_SWITCH_UP,
3484 EL_BALLOON_SWITCH_DOWN,
3485 EL_BALLOON_SWITCH_ANY,
3486 EL_BALLOON_SWITCH_NONE,
3489 EL_EMC_MAGIC_BALL_SWITCH,
3490 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3495 static int ep_bd_element[] =
3529 static int ep_sp_element[] =
3531 /* should always be valid */
3534 /* standard classic Supaplex elements */
3541 EL_SP_HARDWARE_GRAY,
3549 EL_SP_GRAVITY_PORT_RIGHT,
3550 EL_SP_GRAVITY_PORT_DOWN,
3551 EL_SP_GRAVITY_PORT_LEFT,
3552 EL_SP_GRAVITY_PORT_UP,
3557 EL_SP_PORT_VERTICAL,
3558 EL_SP_PORT_HORIZONTAL,
3564 EL_SP_HARDWARE_BASE_1,
3565 EL_SP_HARDWARE_GREEN,
3566 EL_SP_HARDWARE_BLUE,
3568 EL_SP_HARDWARE_YELLOW,
3569 EL_SP_HARDWARE_BASE_2,
3570 EL_SP_HARDWARE_BASE_3,
3571 EL_SP_HARDWARE_BASE_4,
3572 EL_SP_HARDWARE_BASE_5,
3573 EL_SP_HARDWARE_BASE_6,
3577 /* additional elements that appeared in newer Supaplex levels */
3580 /* additional gravity port elements (not switching, but setting gravity) */
3581 EL_SP_GRAVITY_ON_PORT_LEFT,
3582 EL_SP_GRAVITY_ON_PORT_RIGHT,
3583 EL_SP_GRAVITY_ON_PORT_UP,
3584 EL_SP_GRAVITY_ON_PORT_DOWN,
3585 EL_SP_GRAVITY_OFF_PORT_LEFT,
3586 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3587 EL_SP_GRAVITY_OFF_PORT_UP,
3588 EL_SP_GRAVITY_OFF_PORT_DOWN,
3590 /* more than one Murphy in a level results in an inactive clone */
3593 /* runtime Supaplex elements */
3594 EL_SP_DISK_RED_ACTIVE,
3595 EL_SP_TERMINAL_ACTIVE,
3596 EL_SP_BUGGY_BASE_ACTIVATING,
3597 EL_SP_BUGGY_BASE_ACTIVE,
3604 static int ep_sb_element[] =
3609 EL_SOKOBAN_FIELD_EMPTY,
3610 EL_SOKOBAN_FIELD_FULL,
3611 EL_SOKOBAN_FIELD_PLAYER,
3616 EL_INVISIBLE_STEELWALL,
3621 static int ep_gem[] =
3633 static int ep_food_dark_yamyam[] =
3661 static int ep_food_penguin[] =
3675 static int ep_food_pig[] =
3687 static int ep_historic_wall[] =
3698 EL_GATE_1_GRAY_ACTIVE,
3699 EL_GATE_2_GRAY_ACTIVE,
3700 EL_GATE_3_GRAY_ACTIVE,
3701 EL_GATE_4_GRAY_ACTIVE,
3710 EL_EM_GATE_1_GRAY_ACTIVE,
3711 EL_EM_GATE_2_GRAY_ACTIVE,
3712 EL_EM_GATE_3_GRAY_ACTIVE,
3713 EL_EM_GATE_4_GRAY_ACTIVE,
3720 EL_EXPANDABLE_WALL_HORIZONTAL,
3721 EL_EXPANDABLE_WALL_VERTICAL,
3722 EL_EXPANDABLE_WALL_ANY,
3723 EL_EXPANDABLE_WALL_GROWING,
3724 EL_BD_EXPANDABLE_WALL,
3731 EL_SP_HARDWARE_GRAY,
3732 EL_SP_HARDWARE_GREEN,
3733 EL_SP_HARDWARE_BLUE,
3735 EL_SP_HARDWARE_YELLOW,
3736 EL_SP_HARDWARE_BASE_1,
3737 EL_SP_HARDWARE_BASE_2,
3738 EL_SP_HARDWARE_BASE_3,
3739 EL_SP_HARDWARE_BASE_4,
3740 EL_SP_HARDWARE_BASE_5,
3741 EL_SP_HARDWARE_BASE_6,
3743 EL_SP_TERMINAL_ACTIVE,
3746 EL_INVISIBLE_STEELWALL,
3747 EL_INVISIBLE_STEELWALL_ACTIVE,
3749 EL_INVISIBLE_WALL_ACTIVE,
3750 EL_STEELWALL_SLIPPERY,
3767 static int ep_historic_solid[] =
3771 EL_EXPANDABLE_WALL_HORIZONTAL,
3772 EL_EXPANDABLE_WALL_VERTICAL,
3773 EL_EXPANDABLE_WALL_ANY,
3774 EL_BD_EXPANDABLE_WALL,
3787 EL_QUICKSAND_FILLING,
3788 EL_QUICKSAND_EMPTYING,
3790 EL_MAGIC_WALL_ACTIVE,
3791 EL_MAGIC_WALL_EMPTYING,
3792 EL_MAGIC_WALL_FILLING,
3796 EL_BD_MAGIC_WALL_ACTIVE,
3797 EL_BD_MAGIC_WALL_EMPTYING,
3798 EL_BD_MAGIC_WALL_FULL,
3799 EL_BD_MAGIC_WALL_FILLING,
3800 EL_BD_MAGIC_WALL_DEAD,
3809 EL_SP_TERMINAL_ACTIVE,
3813 EL_INVISIBLE_WALL_ACTIVE,
3814 EL_SWITCHGATE_SWITCH_UP,
3815 EL_SWITCHGATE_SWITCH_DOWN,
3816 EL_DC_SWITCHGATE_SWITCH_UP,
3817 EL_DC_SWITCHGATE_SWITCH_DOWN,
3819 EL_TIMEGATE_SWITCH_ACTIVE,
3820 EL_DC_TIMEGATE_SWITCH,
3821 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3833 /* the following elements are a direct copy of "indestructible" elements,
3834 except "EL_ACID", which is "indestructible", but not "solid"! */
3839 EL_ACID_POOL_TOPLEFT,
3840 EL_ACID_POOL_TOPRIGHT,
3841 EL_ACID_POOL_BOTTOMLEFT,
3842 EL_ACID_POOL_BOTTOM,
3843 EL_ACID_POOL_BOTTOMRIGHT,
3844 EL_SP_HARDWARE_GRAY,
3845 EL_SP_HARDWARE_GREEN,
3846 EL_SP_HARDWARE_BLUE,
3848 EL_SP_HARDWARE_YELLOW,
3849 EL_SP_HARDWARE_BASE_1,
3850 EL_SP_HARDWARE_BASE_2,
3851 EL_SP_HARDWARE_BASE_3,
3852 EL_SP_HARDWARE_BASE_4,
3853 EL_SP_HARDWARE_BASE_5,
3854 EL_SP_HARDWARE_BASE_6,
3855 EL_INVISIBLE_STEELWALL,
3856 EL_INVISIBLE_STEELWALL_ACTIVE,
3857 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3858 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3859 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3860 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3861 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3862 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3863 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3864 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3865 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3866 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3867 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3868 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3870 EL_LIGHT_SWITCH_ACTIVE,
3871 EL_SIGN_EXCLAMATION,
3872 EL_SIGN_RADIOACTIVITY,
3879 EL_SIGN_ENTRY_FORBIDDEN,
3880 EL_SIGN_EMERGENCY_EXIT,
3888 EL_STEEL_EXIT_CLOSED,
3890 EL_DC_STEELWALL_1_LEFT,
3891 EL_DC_STEELWALL_1_RIGHT,
3892 EL_DC_STEELWALL_1_TOP,
3893 EL_DC_STEELWALL_1_BOTTOM,
3894 EL_DC_STEELWALL_1_HORIZONTAL,
3895 EL_DC_STEELWALL_1_VERTICAL,
3896 EL_DC_STEELWALL_1_TOPLEFT,
3897 EL_DC_STEELWALL_1_TOPRIGHT,
3898 EL_DC_STEELWALL_1_BOTTOMLEFT,
3899 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3900 EL_DC_STEELWALL_1_TOPLEFT_2,
3901 EL_DC_STEELWALL_1_TOPRIGHT_2,
3902 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3903 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3904 EL_DC_STEELWALL_2_LEFT,
3905 EL_DC_STEELWALL_2_RIGHT,
3906 EL_DC_STEELWALL_2_TOP,
3907 EL_DC_STEELWALL_2_BOTTOM,
3908 EL_DC_STEELWALL_2_HORIZONTAL,
3909 EL_DC_STEELWALL_2_VERTICAL,
3910 EL_DC_STEELWALL_2_MIDDLE,
3911 EL_DC_STEELWALL_2_SINGLE,
3912 EL_STEELWALL_SLIPPERY,
3926 EL_GATE_1_GRAY_ACTIVE,
3927 EL_GATE_2_GRAY_ACTIVE,
3928 EL_GATE_3_GRAY_ACTIVE,
3929 EL_GATE_4_GRAY_ACTIVE,
3938 EL_EM_GATE_1_GRAY_ACTIVE,
3939 EL_EM_GATE_2_GRAY_ACTIVE,
3940 EL_EM_GATE_3_GRAY_ACTIVE,
3941 EL_EM_GATE_4_GRAY_ACTIVE,
3943 EL_SWITCHGATE_OPENING,
3944 EL_SWITCHGATE_CLOSED,
3945 EL_SWITCHGATE_CLOSING,
3947 EL_TIMEGATE_OPENING,
3949 EL_TIMEGATE_CLOSING,
3953 EL_TUBE_VERTICAL_LEFT,
3954 EL_TUBE_VERTICAL_RIGHT,
3955 EL_TUBE_HORIZONTAL_UP,
3956 EL_TUBE_HORIZONTAL_DOWN,
3965 static int ep_classic_enemy[] =
3982 static int ep_belt[] =
3984 EL_CONVEYOR_BELT_1_LEFT,
3985 EL_CONVEYOR_BELT_1_MIDDLE,
3986 EL_CONVEYOR_BELT_1_RIGHT,
3987 EL_CONVEYOR_BELT_2_LEFT,
3988 EL_CONVEYOR_BELT_2_MIDDLE,
3989 EL_CONVEYOR_BELT_2_RIGHT,
3990 EL_CONVEYOR_BELT_3_LEFT,
3991 EL_CONVEYOR_BELT_3_MIDDLE,
3992 EL_CONVEYOR_BELT_3_RIGHT,
3993 EL_CONVEYOR_BELT_4_LEFT,
3994 EL_CONVEYOR_BELT_4_MIDDLE,
3995 EL_CONVEYOR_BELT_4_RIGHT,
4000 static int ep_belt_active[] =
4002 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
4003 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
4004 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
4005 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
4006 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
4007 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
4008 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
4009 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
4010 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
4011 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
4012 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
4013 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
4018 static int ep_belt_switch[] =
4020 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4021 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4022 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4023 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4024 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4025 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4026 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4027 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4028 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4029 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4030 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4031 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4036 static int ep_tube[] =
4043 EL_TUBE_HORIZONTAL_UP,
4044 EL_TUBE_HORIZONTAL_DOWN,
4046 EL_TUBE_VERTICAL_LEFT,
4047 EL_TUBE_VERTICAL_RIGHT,
4053 static int ep_acid_pool[] =
4055 EL_ACID_POOL_TOPLEFT,
4056 EL_ACID_POOL_TOPRIGHT,
4057 EL_ACID_POOL_BOTTOMLEFT,
4058 EL_ACID_POOL_BOTTOM,
4059 EL_ACID_POOL_BOTTOMRIGHT,
4064 static int ep_keygate[] =
4074 EL_GATE_1_GRAY_ACTIVE,
4075 EL_GATE_2_GRAY_ACTIVE,
4076 EL_GATE_3_GRAY_ACTIVE,
4077 EL_GATE_4_GRAY_ACTIVE,
4086 EL_EM_GATE_1_GRAY_ACTIVE,
4087 EL_EM_GATE_2_GRAY_ACTIVE,
4088 EL_EM_GATE_3_GRAY_ACTIVE,
4089 EL_EM_GATE_4_GRAY_ACTIVE,
4098 EL_EMC_GATE_5_GRAY_ACTIVE,
4099 EL_EMC_GATE_6_GRAY_ACTIVE,
4100 EL_EMC_GATE_7_GRAY_ACTIVE,
4101 EL_EMC_GATE_8_GRAY_ACTIVE,
4103 EL_DC_GATE_WHITE_GRAY,
4104 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4109 static int ep_amoeboid[] =
4121 static int ep_amoebalive[] =
4132 static int ep_has_editor_content[] =
4154 static int ep_can_turn_each_move[] =
4156 /* !!! do something with this one !!! */
4160 static int ep_can_grow[] =
4174 static int ep_active_bomb[] =
4177 EL_EM_DYNAMITE_ACTIVE,
4178 EL_DYNABOMB_PLAYER_1_ACTIVE,
4179 EL_DYNABOMB_PLAYER_2_ACTIVE,
4180 EL_DYNABOMB_PLAYER_3_ACTIVE,
4181 EL_DYNABOMB_PLAYER_4_ACTIVE,
4182 EL_SP_DISK_RED_ACTIVE,
4187 static int ep_inactive[] =
4197 EL_QUICKSAND_FAST_EMPTY,
4220 EL_GATE_1_GRAY_ACTIVE,
4221 EL_GATE_2_GRAY_ACTIVE,
4222 EL_GATE_3_GRAY_ACTIVE,
4223 EL_GATE_4_GRAY_ACTIVE,
4232 EL_EM_GATE_1_GRAY_ACTIVE,
4233 EL_EM_GATE_2_GRAY_ACTIVE,
4234 EL_EM_GATE_3_GRAY_ACTIVE,
4235 EL_EM_GATE_4_GRAY_ACTIVE,
4244 EL_EMC_GATE_5_GRAY_ACTIVE,
4245 EL_EMC_GATE_6_GRAY_ACTIVE,
4246 EL_EMC_GATE_7_GRAY_ACTIVE,
4247 EL_EMC_GATE_8_GRAY_ACTIVE,
4249 EL_DC_GATE_WHITE_GRAY,
4250 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4251 EL_DC_GATE_FAKE_GRAY,
4254 EL_INVISIBLE_STEELWALL,
4262 EL_WALL_EMERALD_YELLOW,
4263 EL_DYNABOMB_INCREASE_NUMBER,
4264 EL_DYNABOMB_INCREASE_SIZE,
4265 EL_DYNABOMB_INCREASE_POWER,
4269 EL_SOKOBAN_FIELD_EMPTY,
4270 EL_SOKOBAN_FIELD_FULL,
4271 EL_WALL_EMERALD_RED,
4272 EL_WALL_EMERALD_PURPLE,
4273 EL_ACID_POOL_TOPLEFT,
4274 EL_ACID_POOL_TOPRIGHT,
4275 EL_ACID_POOL_BOTTOMLEFT,
4276 EL_ACID_POOL_BOTTOM,
4277 EL_ACID_POOL_BOTTOMRIGHT,
4281 EL_BD_MAGIC_WALL_DEAD,
4283 EL_DC_MAGIC_WALL_DEAD,
4284 EL_AMOEBA_TO_DIAMOND,
4292 EL_SP_GRAVITY_PORT_RIGHT,
4293 EL_SP_GRAVITY_PORT_DOWN,
4294 EL_SP_GRAVITY_PORT_LEFT,
4295 EL_SP_GRAVITY_PORT_UP,
4296 EL_SP_PORT_HORIZONTAL,
4297 EL_SP_PORT_VERTICAL,
4308 EL_SP_HARDWARE_GRAY,
4309 EL_SP_HARDWARE_GREEN,
4310 EL_SP_HARDWARE_BLUE,
4312 EL_SP_HARDWARE_YELLOW,
4313 EL_SP_HARDWARE_BASE_1,
4314 EL_SP_HARDWARE_BASE_2,
4315 EL_SP_HARDWARE_BASE_3,
4316 EL_SP_HARDWARE_BASE_4,
4317 EL_SP_HARDWARE_BASE_5,
4318 EL_SP_HARDWARE_BASE_6,
4319 EL_SP_GRAVITY_ON_PORT_LEFT,
4320 EL_SP_GRAVITY_ON_PORT_RIGHT,
4321 EL_SP_GRAVITY_ON_PORT_UP,
4322 EL_SP_GRAVITY_ON_PORT_DOWN,
4323 EL_SP_GRAVITY_OFF_PORT_LEFT,
4324 EL_SP_GRAVITY_OFF_PORT_RIGHT,
4325 EL_SP_GRAVITY_OFF_PORT_UP,
4326 EL_SP_GRAVITY_OFF_PORT_DOWN,
4327 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4328 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4329 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4330 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4331 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4332 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4333 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4334 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4335 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4336 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4337 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4338 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4339 EL_SIGN_EXCLAMATION,
4340 EL_SIGN_RADIOACTIVITY,
4347 EL_SIGN_ENTRY_FORBIDDEN,
4348 EL_SIGN_EMERGENCY_EXIT,
4356 EL_DC_STEELWALL_1_LEFT,
4357 EL_DC_STEELWALL_1_RIGHT,
4358 EL_DC_STEELWALL_1_TOP,
4359 EL_DC_STEELWALL_1_BOTTOM,
4360 EL_DC_STEELWALL_1_HORIZONTAL,
4361 EL_DC_STEELWALL_1_VERTICAL,
4362 EL_DC_STEELWALL_1_TOPLEFT,
4363 EL_DC_STEELWALL_1_TOPRIGHT,
4364 EL_DC_STEELWALL_1_BOTTOMLEFT,
4365 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4366 EL_DC_STEELWALL_1_TOPLEFT_2,
4367 EL_DC_STEELWALL_1_TOPRIGHT_2,
4368 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4369 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4370 EL_DC_STEELWALL_2_LEFT,
4371 EL_DC_STEELWALL_2_RIGHT,
4372 EL_DC_STEELWALL_2_TOP,
4373 EL_DC_STEELWALL_2_BOTTOM,
4374 EL_DC_STEELWALL_2_HORIZONTAL,
4375 EL_DC_STEELWALL_2_VERTICAL,
4376 EL_DC_STEELWALL_2_MIDDLE,
4377 EL_DC_STEELWALL_2_SINGLE,
4378 EL_STEELWALL_SLIPPERY,
4383 EL_EMC_WALL_SLIPPERY_1,
4384 EL_EMC_WALL_SLIPPERY_2,
4385 EL_EMC_WALL_SLIPPERY_3,
4386 EL_EMC_WALL_SLIPPERY_4,
4407 static int ep_em_slippery_wall[] =
4412 static int ep_gfx_crumbled[] =
4423 static int ep_editor_cascade_active[] =
4425 EL_INTERNAL_CASCADE_BD_ACTIVE,
4426 EL_INTERNAL_CASCADE_EM_ACTIVE,
4427 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4428 EL_INTERNAL_CASCADE_RND_ACTIVE,
4429 EL_INTERNAL_CASCADE_SB_ACTIVE,
4430 EL_INTERNAL_CASCADE_SP_ACTIVE,
4431 EL_INTERNAL_CASCADE_DC_ACTIVE,
4432 EL_INTERNAL_CASCADE_DX_ACTIVE,
4433 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4434 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4435 EL_INTERNAL_CASCADE_CE_ACTIVE,
4436 EL_INTERNAL_CASCADE_GE_ACTIVE,
4437 EL_INTERNAL_CASCADE_REF_ACTIVE,
4438 EL_INTERNAL_CASCADE_USER_ACTIVE,
4439 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4444 static int ep_editor_cascade_inactive[] =
4446 EL_INTERNAL_CASCADE_BD,
4447 EL_INTERNAL_CASCADE_EM,
4448 EL_INTERNAL_CASCADE_EMC,
4449 EL_INTERNAL_CASCADE_RND,
4450 EL_INTERNAL_CASCADE_SB,
4451 EL_INTERNAL_CASCADE_SP,
4452 EL_INTERNAL_CASCADE_DC,
4453 EL_INTERNAL_CASCADE_DX,
4454 EL_INTERNAL_CASCADE_CHARS,
4455 EL_INTERNAL_CASCADE_STEEL_CHARS,
4456 EL_INTERNAL_CASCADE_CE,
4457 EL_INTERNAL_CASCADE_GE,
4458 EL_INTERNAL_CASCADE_REF,
4459 EL_INTERNAL_CASCADE_USER,
4460 EL_INTERNAL_CASCADE_DYNAMIC,
4465 static int ep_obsolete[] =
4469 EL_EM_KEY_1_FILE_OBSOLETE,
4470 EL_EM_KEY_2_FILE_OBSOLETE,
4471 EL_EM_KEY_3_FILE_OBSOLETE,
4472 EL_EM_KEY_4_FILE_OBSOLETE,
4473 EL_ENVELOPE_OBSOLETE,
4482 } element_properties[] =
4484 { ep_diggable, EP_DIGGABLE },
4485 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4486 { ep_dont_run_into, EP_DONT_RUN_INTO },
4487 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4488 { ep_dont_touch, EP_DONT_TOUCH },
4489 { ep_indestructible, EP_INDESTRUCTIBLE },
4490 { ep_slippery, EP_SLIPPERY },
4491 { ep_can_change, EP_CAN_CHANGE },
4492 { ep_can_move, EP_CAN_MOVE },
4493 { ep_can_fall, EP_CAN_FALL },
4494 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4495 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4496 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4497 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4498 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4499 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4500 { ep_walkable_over, EP_WALKABLE_OVER },
4501 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4502 { ep_walkable_under, EP_WALKABLE_UNDER },
4503 { ep_passable_over, EP_PASSABLE_OVER },
4504 { ep_passable_inside, EP_PASSABLE_INSIDE },
4505 { ep_passable_under, EP_PASSABLE_UNDER },
4506 { ep_droppable, EP_DROPPABLE },
4507 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4508 { ep_pushable, EP_PUSHABLE },
4509 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4510 { ep_protected, EP_PROTECTED },
4511 { ep_throwable, EP_THROWABLE },
4512 { ep_can_explode, EP_CAN_EXPLODE },
4513 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4515 { ep_player, EP_PLAYER },
4516 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4517 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4518 { ep_switchable, EP_SWITCHABLE },
4519 { ep_bd_element, EP_BD_ELEMENT },
4520 { ep_sp_element, EP_SP_ELEMENT },
4521 { ep_sb_element, EP_SB_ELEMENT },
4523 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4524 { ep_food_penguin, EP_FOOD_PENGUIN },
4525 { ep_food_pig, EP_FOOD_PIG },
4526 { ep_historic_wall, EP_HISTORIC_WALL },
4527 { ep_historic_solid, EP_HISTORIC_SOLID },
4528 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4529 { ep_belt, EP_BELT },
4530 { ep_belt_active, EP_BELT_ACTIVE },
4531 { ep_belt_switch, EP_BELT_SWITCH },
4532 { ep_tube, EP_TUBE },
4533 { ep_acid_pool, EP_ACID_POOL },
4534 { ep_keygate, EP_KEYGATE },
4535 { ep_amoeboid, EP_AMOEBOID },
4536 { ep_amoebalive, EP_AMOEBALIVE },
4537 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4538 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4539 { ep_can_grow, EP_CAN_GROW },
4540 { ep_active_bomb, EP_ACTIVE_BOMB },
4541 { ep_inactive, EP_INACTIVE },
4543 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4545 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4547 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4548 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4550 { ep_obsolete, EP_OBSOLETE },
4557 /* always start with reliable default values (element has no properties) */
4558 /* (but never initialize clipboard elements after the very first time) */
4559 /* (to be able to use clipboard elements between several levels) */
4560 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4561 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4562 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4563 SET_PROPERTY(i, j, FALSE);
4565 /* set all base element properties from above array definitions */
4566 for (i = 0; element_properties[i].elements != NULL; i++)
4567 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4568 SET_PROPERTY((element_properties[i].elements)[j],
4569 element_properties[i].property, TRUE);
4571 /* copy properties to some elements that are only stored in level file */
4572 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4573 for (j = 0; copy_properties[j][0] != -1; j++)
4574 if (HAS_PROPERTY(copy_properties[j][0], i))
4575 for (k = 1; k <= 4; k++)
4576 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4578 /* set static element properties that are not listed in array definitions */
4579 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4580 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4582 clipboard_elements_initialized = TRUE;
4585 void InitElementPropertiesEngine(int engine_version)
4587 static int no_wall_properties[] =
4590 EP_COLLECTIBLE_ONLY,
4592 EP_DONT_COLLIDE_WITH,
4595 EP_CAN_SMASH_PLAYER,
4596 EP_CAN_SMASH_ENEMIES,
4597 EP_CAN_SMASH_EVERYTHING,
4602 EP_FOOD_DARK_YAMYAM,
4618 /* important: after initialization in InitElementPropertiesStatic(), the
4619 elements are not again initialized to a default value; therefore all
4620 changes have to make sure that they leave the element with a defined
4621 property (which means that conditional property changes must be set to
4622 a reliable default value before) */
4624 /* resolve group elements */
4625 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4626 ResolveGroupElement(EL_GROUP_START + i);
4628 /* set all special, combined or engine dependent element properties */
4629 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4631 /* do not change (already initialized) clipboard elements here */
4632 if (IS_CLIPBOARD_ELEMENT(i))
4635 /* ---------- INACTIVE ------------------------------------------------- */
4636 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4637 i <= EL_CHAR_END) ||
4638 (i >= EL_STEEL_CHAR_START &&
4639 i <= EL_STEEL_CHAR_END)));
4641 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4642 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4643 IS_WALKABLE_INSIDE(i) ||
4644 IS_WALKABLE_UNDER(i)));
4646 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4647 IS_PASSABLE_INSIDE(i) ||
4648 IS_PASSABLE_UNDER(i)));
4650 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4651 IS_PASSABLE_OVER(i)));
4653 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4654 IS_PASSABLE_INSIDE(i)));
4656 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4657 IS_PASSABLE_UNDER(i)));
4659 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4662 /* ---------- COLLECTIBLE ---------------------------------------------- */
4663 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4667 /* ---------- SNAPPABLE ------------------------------------------------ */
4668 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4669 IS_COLLECTIBLE(i) ||
4673 /* ---------- WALL ----------------------------------------------------- */
4674 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4676 for (j = 0; no_wall_properties[j] != -1; j++)
4677 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4678 i >= EL_FIRST_RUNTIME_UNREAL)
4679 SET_PROPERTY(i, EP_WALL, FALSE);
4681 if (IS_HISTORIC_WALL(i))
4682 SET_PROPERTY(i, EP_WALL, TRUE);
4684 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4685 if (engine_version < VERSION_IDENT(2,2,0,0))
4686 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4688 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4690 !IS_COLLECTIBLE(i)));
4692 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4693 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4694 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4696 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4697 IS_INDESTRUCTIBLE(i)));
4699 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4701 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4702 else if (engine_version < VERSION_IDENT(2,2,0,0))
4703 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4705 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4709 if (IS_CUSTOM_ELEMENT(i))
4711 /* these are additional properties which are initially false when set */
4713 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4715 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4716 if (DONT_COLLIDE_WITH(i))
4717 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4719 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4720 if (CAN_SMASH_EVERYTHING(i))
4721 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4722 if (CAN_SMASH_ENEMIES(i))
4723 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4726 /* ---------- CAN_SMASH ------------------------------------------------ */
4727 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4728 CAN_SMASH_ENEMIES(i) ||
4729 CAN_SMASH_EVERYTHING(i)));
4731 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4732 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4733 EXPLODES_BY_FIRE(i)));
4735 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4736 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4737 EXPLODES_SMASHED(i)));
4739 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4740 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4741 EXPLODES_IMPACT(i)));
4743 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4744 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4746 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4747 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4748 i == EL_BLACK_ORB));
4750 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4751 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4753 IS_CUSTOM_ELEMENT(i)));
4755 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4756 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4757 i == EL_SP_ELECTRON));
4759 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4760 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4761 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4762 getMoveIntoAcidProperty(&level, i));
4764 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4765 if (MAYBE_DONT_COLLIDE_WITH(i))
4766 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4767 getDontCollideWithProperty(&level, i));
4769 /* ---------- SP_PORT -------------------------------------------------- */
4770 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4771 IS_PASSABLE_INSIDE(i)));
4773 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4774 for (j = 0; j < level.num_android_clone_elements; j++)
4775 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4777 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4779 /* ---------- CAN_CHANGE ----------------------------------------------- */
4780 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4781 for (j = 0; j < element_info[i].num_change_pages; j++)
4782 if (element_info[i].change_page[j].can_change)
4783 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4785 /* ---------- HAS_ACTION ----------------------------------------------- */
4786 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4787 for (j = 0; j < element_info[i].num_change_pages; j++)
4788 if (element_info[i].change_page[j].has_action)
4789 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4791 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4792 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4795 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4797 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4798 element_info[i].crumbled[ACTION_DEFAULT] !=
4799 element_info[i].graphic[ACTION_DEFAULT]);
4801 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
4802 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4803 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
4806 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4807 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4808 IS_EDITOR_CASCADE_INACTIVE(i)));
4811 /* dynamically adjust element properties according to game engine version */
4813 static int ep_em_slippery_wall[] =
4818 EL_EXPANDABLE_WALL_HORIZONTAL,
4819 EL_EXPANDABLE_WALL_VERTICAL,
4820 EL_EXPANDABLE_WALL_ANY,
4821 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4822 EL_EXPANDABLE_STEELWALL_VERTICAL,
4823 EL_EXPANDABLE_STEELWALL_ANY,
4824 EL_EXPANDABLE_STEELWALL_GROWING,
4828 /* special EM style gems behaviour */
4829 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4830 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4831 level.em_slippery_gems);
4833 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4834 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4835 (level.em_slippery_gems &&
4836 engine_version > VERSION_IDENT(2,0,1,0)));
4839 /* this is needed because some graphics depend on element properties */
4840 if (game_status == GAME_MODE_PLAYING)
4841 InitElementGraphicInfo();
4844 void InitElementPropertiesAfterLoading(int engine_version)
4848 /* set some other uninitialized values of custom elements in older levels */
4849 if (engine_version < VERSION_IDENT(3,1,0,0))
4851 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4853 int element = EL_CUSTOM_START + i;
4855 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4857 element_info[element].explosion_delay = 17;
4858 element_info[element].ignition_delay = 8;
4863 static void InitGlobal()
4868 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4870 /* check if element_name_info entry defined for each element in "main.h" */
4871 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4872 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4874 element_info[i].token_name = element_name_info[i].token_name;
4875 element_info[i].class_name = element_name_info[i].class_name;
4876 element_info[i].editor_description= element_name_info[i].editor_description;
4879 printf("%04d: %s\n", i, element_name_info[i].token_name);
4883 /* create hash from image config list */
4884 image_config_hash = newSetupFileHash();
4885 for (i = 0; image_config[i].token != NULL; i++)
4886 setHashEntry(image_config_hash,
4887 image_config[i].token,
4888 image_config[i].value);
4890 /* create hash from element token list */
4891 element_token_hash = newSetupFileHash();
4892 for (i = 0; element_name_info[i].token_name != NULL; i++)
4893 setHashEntry(element_token_hash,
4894 element_name_info[i].token_name,
4897 /* create hash from graphic token list */
4898 graphic_token_hash = newSetupFileHash();
4899 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4900 if (strSuffix(image_config[i].value, ".pcx") ||
4901 strSuffix(image_config[i].value, ".wav") ||
4902 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4903 setHashEntry(graphic_token_hash,
4904 image_config[i].token,
4905 int2str(graphic++, 0));
4907 /* create hash from font token list */
4908 font_token_hash = newSetupFileHash();
4909 for (i = 0; font_info[i].token_name != NULL; i++)
4910 setHashEntry(font_token_hash,
4911 font_info[i].token_name,
4914 /* always start with reliable default values (all elements) */
4915 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4916 ActiveElement[i] = i;
4918 /* now add all entries that have an active state (active elements) */
4919 for (i = 0; element_with_active_state[i].element != -1; i++)
4921 int element = element_with_active_state[i].element;
4922 int element_active = element_with_active_state[i].element_active;
4924 ActiveElement[element] = element_active;
4927 /* always start with reliable default values (all buttons) */
4928 for (i = 0; i < NUM_IMAGE_FILES; i++)
4929 ActiveButton[i] = i;
4931 /* now add all entries that have an active state (active buttons) */
4932 for (i = 0; button_with_active_state[i].button != -1; i++)
4934 int button = button_with_active_state[i].button;
4935 int button_active = button_with_active_state[i].button_active;
4937 ActiveButton[button] = button_active;
4940 /* always start with reliable default values (all fonts) */
4941 for (i = 0; i < NUM_FONTS; i++)
4944 /* now add all entries that have an active state (active fonts) */
4945 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4947 int font = font_with_active_state[i].font_nr;
4948 int font_active = font_with_active_state[i].font_nr_active;
4950 ActiveFont[font] = font_active;
4953 global.autoplay_leveldir = NULL;
4954 global.convert_leveldir = NULL;
4956 global.frames_per_second = 0;
4957 global.fps_slowdown = FALSE;
4958 global.fps_slowdown_factor = 1;
4960 global.border_status = GAME_MODE_MAIN;
4962 global.fading_status = GAME_MODE_MAIN;
4963 global.fading_type = TYPE_ENTER_MENU;
4967 void Execute_Command(char *command)
4971 if (strEqual(command, "print graphicsinfo.conf"))
4973 printf("# You can configure additional/alternative image files here.\n");
4974 printf("# (The entries below are default and therefore commented out.)\n");
4976 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4978 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4981 for (i = 0; image_config[i].token != NULL; i++)
4982 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
4983 image_config[i].value));
4987 else if (strEqual(command, "print soundsinfo.conf"))
4989 printf("# You can configure additional/alternative sound files here.\n");
4990 printf("# (The entries below are default and therefore commented out.)\n");
4992 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4994 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4997 for (i = 0; sound_config[i].token != NULL; i++)
4998 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4999 sound_config[i].value));
5003 else if (strEqual(command, "print musicinfo.conf"))
5005 printf("# You can configure additional/alternative music files here.\n");
5006 printf("# (The entries below are default and therefore commented out.)\n");
5008 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
5010 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5013 for (i = 0; music_config[i].token != NULL; i++)
5014 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
5015 music_config[i].value));
5019 else if (strEqual(command, "print editorsetup.conf"))
5021 printf("# You can configure your personal editor element list here.\n");
5022 printf("# (The entries below are default and therefore commented out.)\n");
5025 /* this is needed to be able to check element list for cascade elements */
5026 InitElementPropertiesStatic();
5027 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5029 PrintEditorElementList();
5033 else if (strEqual(command, "print helpanim.conf"))
5035 printf("# You can configure different element help animations here.\n");
5036 printf("# (The entries below are default and therefore commented out.)\n");
5039 for (i = 0; helpanim_config[i].token != NULL; i++)
5041 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
5042 helpanim_config[i].value));
5044 if (strEqual(helpanim_config[i].token, "end"))
5050 else if (strEqual(command, "print helptext.conf"))
5052 printf("# You can configure different element help text here.\n");
5053 printf("# (The entries below are default and therefore commented out.)\n");
5056 for (i = 0; helptext_config[i].token != NULL; i++)
5057 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
5058 helptext_config[i].value));
5062 else if (strncmp(command, "dump level ", 11) == 0)
5064 char *filename = &command[11];
5066 if (!fileExists(filename))
5067 Error(ERR_EXIT, "cannot open file '%s'", filename);
5069 LoadLevelFromFilename(&level, filename);
5074 else if (strncmp(command, "dump tape ", 10) == 0)
5076 char *filename = &command[10];
5078 if (!fileExists(filename))
5079 Error(ERR_EXIT, "cannot open file '%s'", filename);
5081 LoadTapeFromFilename(filename);
5086 else if (strncmp(command, "autoplay ", 9) == 0)
5088 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
5090 while (*str_ptr != '\0') /* continue parsing string */
5092 /* cut leading whitespace from string, replace it by string terminator */
5093 while (*str_ptr == ' ' || *str_ptr == '\t')
5096 if (*str_ptr == '\0') /* end of string reached */
5099 if (global.autoplay_leveldir == NULL) /* read level set string */
5101 global.autoplay_leveldir = str_ptr;
5102 global.autoplay_all = TRUE; /* default: play all tapes */
5104 for (i = 0; i < MAX_TAPES_PER_SET; i++)
5105 global.autoplay_level[i] = FALSE;
5107 else /* read level number string */
5109 int level_nr = atoi(str_ptr); /* get level_nr value */
5111 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5112 global.autoplay_level[level_nr] = TRUE;
5114 global.autoplay_all = FALSE;
5117 /* advance string pointer to the next whitespace (or end of string) */
5118 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5122 else if (strncmp(command, "convert ", 8) == 0)
5124 char *str_copy = getStringCopy(&command[8]);
5125 char *str_ptr = strchr(str_copy, ' ');
5127 global.convert_leveldir = str_copy;
5128 global.convert_level_nr = -1;
5130 if (str_ptr != NULL) /* level number follows */
5132 *str_ptr++ = '\0'; /* terminate leveldir string */
5133 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
5138 #if defined(TARGET_SDL)
5139 else if (strEqual(command, "SDL_ListModes"))
5144 SDL_Init(SDL_INIT_VIDEO);
5146 /* get available fullscreen/hardware modes */
5147 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
5149 /* check if there are any modes available */
5152 printf("No modes available!\n");
5157 /* check if our resolution is restricted */
5158 if (modes == (SDL_Rect **)-1)
5160 printf("All resolutions available.\n");
5164 printf("Available Modes:\n");
5166 for(i = 0; modes[i]; i++)
5167 printf(" %d x %d\n", modes[i]->w, modes[i]->h);
5177 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
5181 static void InitSetup()
5183 LoadSetup(); /* global setup info */
5185 /* set some options from setup file */
5187 if (setup.options.verbose)
5188 options.verbose = TRUE;
5191 static void InitGameInfo()
5193 game.restart_level = FALSE;
5196 static void InitPlayerInfo()
5200 /* choose default local player */
5201 local_player = &stored_player[0];
5203 for (i = 0; i < MAX_PLAYERS; i++)
5204 stored_player[i].connected = FALSE;
5206 local_player->connected = TRUE;
5209 static void InitArtworkInfo()
5214 static char *get_string_in_brackets(char *string)
5216 char *string_in_brackets = checked_malloc(strlen(string) + 3);
5218 sprintf(string_in_brackets, "[%s]", string);
5220 return string_in_brackets;
5223 static char *get_level_id_suffix(int id_nr)
5225 char *id_suffix = checked_malloc(1 + 3 + 1);
5227 if (id_nr < 0 || id_nr > 999)
5230 sprintf(id_suffix, ".%03d", id_nr);
5236 static char *get_element_class_token(int element)
5238 char *element_class_name = element_info[element].class_name;
5239 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
5241 sprintf(element_class_token, "[%s]", element_class_name);
5243 return element_class_token;
5246 static char *get_action_class_token(int action)
5248 char *action_class_name = &element_action_info[action].suffix[1];
5249 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
5251 sprintf(action_class_token, "[%s]", action_class_name);
5253 return action_class_token;
5257 static void InitArtworkConfig()
5259 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
5260 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
5261 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
5262 static char *action_id_suffix[NUM_ACTIONS + 1];
5263 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5264 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5265 static char *level_id_suffix[MAX_LEVELS + 1];
5266 static char *dummy[1] = { NULL };
5267 static char *ignore_generic_tokens[] =
5273 static char **ignore_image_tokens;
5274 static char **ignore_sound_tokens;
5275 static char **ignore_music_tokens;
5276 int num_ignore_generic_tokens;
5277 int num_ignore_image_tokens;
5278 int num_ignore_sound_tokens;
5279 int num_ignore_music_tokens;
5282 /* dynamically determine list of generic tokens to be ignored */
5283 num_ignore_generic_tokens = 0;
5284 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5285 num_ignore_generic_tokens++;
5287 /* dynamically determine list of image tokens to be ignored */
5288 num_ignore_image_tokens = num_ignore_generic_tokens;
5289 for (i = 0; image_config_vars[i].token != NULL; i++)
5290 num_ignore_image_tokens++;
5291 ignore_image_tokens =
5292 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5293 for (i = 0; i < num_ignore_generic_tokens; i++)
5294 ignore_image_tokens[i] = ignore_generic_tokens[i];
5295 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5296 ignore_image_tokens[num_ignore_generic_tokens + i] =
5297 image_config_vars[i].token;
5298 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5300 /* dynamically determine list of sound tokens to be ignored */
5301 num_ignore_sound_tokens = num_ignore_generic_tokens;
5302 ignore_sound_tokens =
5303 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5304 for (i = 0; i < num_ignore_generic_tokens; i++)
5305 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5306 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5308 /* dynamically determine list of music tokens to be ignored */
5309 num_ignore_music_tokens = num_ignore_generic_tokens;
5310 ignore_music_tokens =
5311 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5312 for (i = 0; i < num_ignore_generic_tokens; i++)
5313 ignore_music_tokens[i] = ignore_generic_tokens[i];
5314 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5316 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5317 image_id_prefix[i] = element_info[i].token_name;
5318 for (i = 0; i < NUM_FONTS; i++)
5319 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5320 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
5322 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5323 sound_id_prefix[i] = element_info[i].token_name;
5324 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5325 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5326 get_string_in_brackets(element_info[i].class_name);
5327 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
5329 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5330 music_id_prefix[i] = music_prefix_info[i].prefix;
5331 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
5333 for (i = 0; i < NUM_ACTIONS; i++)
5334 action_id_suffix[i] = element_action_info[i].suffix;
5335 action_id_suffix[NUM_ACTIONS] = NULL;
5337 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5338 direction_id_suffix[i] = element_direction_info[i].suffix;
5339 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5341 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5342 special_id_suffix[i] = special_suffix_info[i].suffix;
5343 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5345 for (i = 0; i < MAX_LEVELS; i++)
5346 level_id_suffix[i] = get_level_id_suffix(i);
5347 level_id_suffix[MAX_LEVELS] = NULL;
5349 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5350 image_id_prefix, action_id_suffix, direction_id_suffix,
5351 special_id_suffix, ignore_image_tokens);
5352 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5353 sound_id_prefix, action_id_suffix, dummy,
5354 special_id_suffix, ignore_sound_tokens);
5355 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5356 music_id_prefix, special_id_suffix, level_id_suffix,
5357 dummy, ignore_music_tokens);
5360 static void InitMixer()
5368 char *filename_font_initial = NULL;
5369 char *filename_anim_initial = NULL;
5370 Bitmap *bitmap_font_initial = NULL;
5374 /* determine settings for initial font (for displaying startup messages) */
5375 for (i = 0; image_config[i].token != NULL; i++)
5377 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5379 char font_token[128];
5382 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5383 len_font_token = strlen(font_token);
5385 if (strEqual(image_config[i].token, font_token))
5386 filename_font_initial = image_config[i].value;
5387 else if (strlen(image_config[i].token) > len_font_token &&
5388 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5390 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5391 font_initial[j].src_x = atoi(image_config[i].value);
5392 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5393 font_initial[j].src_y = atoi(image_config[i].value);
5394 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5395 font_initial[j].width = atoi(image_config[i].value);
5396 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5397 font_initial[j].height = atoi(image_config[i].value);
5402 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5404 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5405 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5408 if (filename_font_initial == NULL) /* should not happen */
5409 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5411 /* create additional image buffers for double-buffering and cross-fading */
5412 bitmap_db_cross = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5413 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
5414 bitmap_db_panel = CreateBitmap(DXSIZE, DYSIZE, DEFAULT_DEPTH);
5415 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
5417 /* initialize screen properties */
5418 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5419 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5421 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5422 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5423 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5425 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5427 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5428 font_initial[j].bitmap = bitmap_font_initial;
5430 InitFontGraphicInfo();
5432 font_height = getFontHeight(FC_RED);
5435 DrawInitText(getWindowTitleString(), 20, FC_YELLOW);
5437 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
5439 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
5440 DrawInitText(PROGRAM_WEBSITE_STRING, WIN_YSIZE - 20 - font_height, FC_RED);
5442 DrawInitText("Loading graphics", 120, FC_GREEN);
5446 /* initialize busy animation with default values */
5447 int parameter[NUM_GFX_ARGS];
5448 for (i = 0; i < NUM_GFX_ARGS; i++)
5449 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5450 image_config_suffix[i].token,
5451 image_config_suffix[i].type);
5453 for (i = 0; i < NUM_GFX_ARGS; i++)
5454 printf("::: '%s' => %d\n", image_config_suffix[i].token, parameter[i]);
5458 /* determine settings for busy animation (when displaying startup messages) */
5459 for (i = 0; image_config[i].token != NULL; i++)
5461 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5462 int len_anim_token = strlen(anim_token);
5464 if (strEqual(image_config[i].token, anim_token))
5465 filename_anim_initial = image_config[i].value;
5466 else if (strlen(image_config[i].token) > len_anim_token &&
5467 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5470 for (j = 0; image_config_suffix[j].token != NULL; j++)
5472 if (strEqual(&image_config[i].token[len_anim_token],
5473 image_config_suffix[j].token))
5475 get_graphic_parameter_value(image_config[i].value,
5476 image_config_suffix[j].token,
5477 image_config_suffix[j].type);
5480 if (strEqual(&image_config[i].token[len_anim_token], ".x"))
5481 anim_initial.src_x = atoi(image_config[i].value);
5482 else if (strEqual(&image_config[i].token[len_anim_token], ".y"))
5483 anim_initial.src_y = atoi(image_config[i].value);
5484 else if (strEqual(&image_config[i].token[len_anim_token], ".width"))
5485 anim_initial.width = atoi(image_config[i].value);
5486 else if (strEqual(&image_config[i].token[len_anim_token], ".height"))
5487 anim_initial.height = atoi(image_config[i].value);
5488 else if (strEqual(&image_config[i].token[len_anim_token], ".frames"))
5489 anim_initial.anim_frames = atoi(image_config[i].value);
5490 else if (strEqual(&image_config[i].token[len_anim_token],
5491 ".frames_per_line"))
5492 anim_initial.anim_frames_per_line = atoi(image_config[i].value);
5493 else if (strEqual(&image_config[i].token[len_anim_token], ".delay"))
5494 anim_initial.anim_delay = atoi(image_config[i].value);
5499 set_graphic_parameters_ext(0, &anim_initial, parameter, NULL);
5501 if (filename_anim_initial == NULL) /* should not happen */
5502 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5504 anim_initial.bitmap = LoadCustomImage(filename_anim_initial);
5506 init.busy.width = anim_initial.width;
5507 init.busy.height = anim_initial.height;
5509 InitMenuDesignSettings_Static();
5510 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5514 void RedrawBackground()
5516 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
5517 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
5519 redraw_mask = REDRAW_ALL;
5522 void InitGfxBackground()
5526 fieldbuffer = bitmap_db_field;
5527 SetDrawtoField(DRAW_BACKBUFFER);
5530 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5534 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
5535 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
5538 for (x = 0; x < MAX_BUF_XSIZE; x++)
5539 for (y = 0; y < MAX_BUF_YSIZE; y++)
5542 redraw_mask = REDRAW_ALL;
5545 static void InitLevelInfo()
5547 LoadLevelInfo(); /* global level info */
5548 LoadLevelSetup_LastSeries(); /* last played series info */
5549 LoadLevelSetup_SeriesInfo(); /* last played level info */
5552 void InitLevelArtworkInfo()
5554 LoadLevelArtworkInfo();
5557 static void InitImages()
5559 print_timestamp_init("InitImages");
5561 setLevelArtworkDir(artwork.gfx_first);
5564 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5565 leveldir_current->identifier,
5566 artwork.gfx_current_identifier,
5567 artwork.gfx_current->identifier,
5568 leveldir_current->graphics_set,
5569 leveldir_current->graphics_path);
5572 UPDATE_BUSY_STATE();
5574 ReloadCustomImages();
5575 print_timestamp_time("ReloadCustomImages");
5577 UPDATE_BUSY_STATE();
5579 LoadCustomElementDescriptions();
5580 print_timestamp_time("LoadCustomElementDescriptions");
5582 UPDATE_BUSY_STATE();
5584 LoadMenuDesignSettings();
5585 print_timestamp_time("LoadMenuDesignSettings");
5587 UPDATE_BUSY_STATE();
5589 ReinitializeGraphics();
5590 print_timestamp_time("ReinitializeGraphics");
5592 UPDATE_BUSY_STATE();
5594 print_timestamp_done("InitImages");
5597 static void InitSound(char *identifier)
5599 print_timestamp_init("InitSound");
5601 if (identifier == NULL)
5602 identifier = artwork.snd_current->identifier;
5604 /* set artwork path to send it to the sound server process */
5605 setLevelArtworkDir(artwork.snd_first);
5607 InitReloadCustomSounds(identifier);
5608 print_timestamp_time("InitReloadCustomSounds");
5610 ReinitializeSounds();
5611 print_timestamp_time("ReinitializeSounds");
5613 print_timestamp_done("InitSound");
5616 static void InitMusic(char *identifier)
5618 print_timestamp_init("InitMusic");
5620 if (identifier == NULL)
5621 identifier = artwork.mus_current->identifier;
5623 /* set artwork path to send it to the sound server process */
5624 setLevelArtworkDir(artwork.mus_first);
5626 InitReloadCustomMusic(identifier);
5627 print_timestamp_time("InitReloadCustomMusic");
5629 ReinitializeMusic();
5630 print_timestamp_time("ReinitializeMusic");
5632 print_timestamp_done("InitMusic");
5635 void InitNetworkServer()
5637 #if defined(NETWORK_AVALIABLE)
5641 if (!options.network)
5644 #if defined(NETWORK_AVALIABLE)
5645 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5647 if (!ConnectToServer(options.server_host, options.server_port))
5648 Error(ERR_EXIT, "cannot connect to network game server");
5650 SendToServer_PlayerName(setup.player_name);
5651 SendToServer_ProtocolVersion();
5654 SendToServer_NrWanted(nr_wanted);
5658 static char *getNewArtworkIdentifier(int type)
5660 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5661 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5662 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5663 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5664 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5665 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
5666 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5667 char *leveldir_identifier = leveldir_current->identifier;
5669 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
5670 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5672 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
5674 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5675 char *artwork_current_identifier;
5676 char *artwork_new_identifier = NULL; /* default: nothing has changed */
5678 /* leveldir_current may be invalid (level group, parent link) */
5679 if (!validLevelSeries(leveldir_current))
5682 /* 1st step: determine artwork set to be activated in descending order:
5683 --------------------------------------------------------------------
5684 1. setup artwork (when configured to override everything else)
5685 2. artwork set configured in "levelinfo.conf" of current level set
5686 (artwork in level directory will have priority when loading later)
5687 3. artwork in level directory (stored in artwork sub-directory)
5688 4. setup artwork (currently configured in setup menu) */
5690 if (setup_override_artwork)
5691 artwork_current_identifier = setup_artwork_set;
5692 else if (leveldir_artwork_set != NULL)
5693 artwork_current_identifier = leveldir_artwork_set;
5694 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5695 artwork_current_identifier = leveldir_identifier;
5697 artwork_current_identifier = setup_artwork_set;
5700 /* 2nd step: check if it is really needed to reload artwork set
5701 ------------------------------------------------------------ */
5704 if (type == ARTWORK_TYPE_GRAPHICS)
5705 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
5706 artwork_new_identifier,
5707 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5708 artwork_current_identifier,
5709 leveldir_current->graphics_set,
5710 leveldir_current->identifier);
5713 /* ---------- reload if level set and also artwork set has changed ------- */
5714 if (leveldir_current_identifier[type] != leveldir_identifier &&
5715 (last_has_level_artwork_set[type] || has_level_artwork_set))
5716 artwork_new_identifier = artwork_current_identifier;
5718 leveldir_current_identifier[type] = leveldir_identifier;
5719 last_has_level_artwork_set[type] = has_level_artwork_set;
5722 if (type == ARTWORK_TYPE_GRAPHICS)
5723 printf("::: 1: '%s'\n", artwork_new_identifier);
5726 /* ---------- reload if "override artwork" setting has changed ----------- */
5727 if (last_override_level_artwork[type] != setup_override_artwork)
5728 artwork_new_identifier = artwork_current_identifier;
5730 last_override_level_artwork[type] = setup_override_artwork;
5733 if (type == ARTWORK_TYPE_GRAPHICS)
5734 printf("::: 2: '%s'\n", artwork_new_identifier);
5737 /* ---------- reload if current artwork identifier has changed ----------- */
5738 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5739 artwork_current_identifier))
5740 artwork_new_identifier = artwork_current_identifier;
5742 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5745 if (type == ARTWORK_TYPE_GRAPHICS)
5746 printf("::: 3: '%s'\n", artwork_new_identifier);
5749 /* ---------- do not reload directly after starting ---------------------- */
5750 if (!initialized[type])
5751 artwork_new_identifier = NULL;
5753 initialized[type] = TRUE;
5756 if (type == ARTWORK_TYPE_GRAPHICS)
5757 printf("::: 4: '%s'\n", artwork_new_identifier);
5761 if (type == ARTWORK_TYPE_GRAPHICS)
5762 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
5763 artwork.gfx_current_identifier, artwork_current_identifier,
5764 artwork.gfx_current->identifier, leveldir_current->graphics_set,
5765 artwork_new_identifier);
5768 return artwork_new_identifier;
5771 void ReloadCustomArtwork(int force_reload)
5773 int last_game_status = game_status; /* save current game status */
5774 char *gfx_new_identifier;
5775 char *snd_new_identifier;
5776 char *mus_new_identifier;
5777 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5778 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5779 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5780 boolean reload_needed;
5782 force_reload_gfx |= AdjustGraphicsForEMC();
5784 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5785 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5786 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5788 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
5789 snd_new_identifier != NULL || force_reload_snd ||
5790 mus_new_identifier != NULL || force_reload_mus);
5795 print_timestamp_init("ReloadCustomArtwork");
5797 game_status = GAME_MODE_LOADING;
5799 FadeOut(REDRAW_ALL);
5802 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5804 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
5806 print_timestamp_time("ClearRectangle");
5809 printf("::: fading in ... %d\n", fading.fade_mode);
5813 printf("::: done\n");
5816 if (gfx_new_identifier != NULL || force_reload_gfx)
5819 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5820 artwork.gfx_current_identifier,
5822 artwork.gfx_current->identifier,
5823 leveldir_current->graphics_set);
5827 print_timestamp_time("InitImages");
5830 if (snd_new_identifier != NULL || force_reload_snd)
5832 InitSound(snd_new_identifier);
5833 print_timestamp_time("InitSound");
5836 if (mus_new_identifier != NULL || force_reload_mus)
5838 InitMusic(mus_new_identifier);
5839 print_timestamp_time("InitMusic");
5842 game_status = last_game_status; /* restore current game status */
5845 printf("::: ----------------DELAY 1 ...\n");
5850 printf("::: FadeOut @ ReloadCustomArtwork ...\n");
5852 FadeOut(REDRAW_ALL);
5854 printf("::: FadeOut @ ReloadCustomArtwork done\n");
5859 /* force redraw of (open or closed) door graphics */
5860 SetDoorState(DOOR_OPEN_ALL);
5861 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5866 FadeSetEnterScreen();
5867 FadeSkipNextFadeOut();
5868 // FadeSetDisabled();
5873 fading = fading_none;
5878 redraw_mask = REDRAW_ALL;
5881 print_timestamp_done("ReloadCustomArtwork");
5884 void KeyboardAutoRepeatOffUnlessAutoplay()
5886 if (global.autoplay_leveldir == NULL)
5887 KeyboardAutoRepeatOff();
5891 /* ========================================================================= */
5893 /* ========================================================================= */
5897 print_timestamp_init("OpenAll");
5899 game_status = GAME_MODE_LOADING;
5901 InitGlobal(); /* initialize some global variables */
5903 if (options.execute_command)
5904 Execute_Command(options.execute_command);
5906 if (options.serveronly)
5908 #if defined(PLATFORM_UNIX)
5909 NetworkServer(options.server_port, options.serveronly);
5911 Error(ERR_WARN, "networking only supported in Unix version");
5914 exit(0); /* never reached, server loops forever */
5921 InitArtworkInfo(); /* needed before loading gfx, sound & music */
5922 InitArtworkConfig(); /* needed before forking sound child process */
5927 InitRND(NEW_RANDOMIZE);
5928 InitSimpleRandom(NEW_RANDOMIZE);
5932 print_timestamp_time("[pre-video]");
5935 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
5937 InitEventFilter(FilterMouseMotionEvents);
5939 InitElementPropertiesStatic();
5940 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5942 print_timestamp_time("[post-video]");
5946 print_timestamp_time("InitGfx");
5949 print_timestamp_time("InitLevelInfo");
5951 InitLevelArtworkInfo();
5952 print_timestamp_time("InitLevelArtworkInfo");
5954 InitImages(); /* needs to know current level directory */
5955 print_timestamp_time("InitImages");
5957 InitSound(NULL); /* needs to know current level directory */
5958 print_timestamp_time("InitSound");
5960 InitMusic(NULL); /* needs to know current level directory */
5961 print_timestamp_time("InitMusic");
5963 InitGfxBackground();
5969 if (global.autoplay_leveldir)
5974 else if (global.convert_leveldir)
5980 game_status = GAME_MODE_MAIN;
5983 FadeSetEnterScreen();
5984 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
5985 FadeSkipNextFadeOut();
5986 // FadeSetDisabled();
5988 fading = fading_none;
5991 print_timestamp_time("[post-artwork]");
5993 print_timestamp_done("OpenAll");
5997 InitNetworkServer();
6000 void CloseAllAndExit(int exit_value)
6005 CloseAudio(); /* called after freeing sounds (needed for SDL) */
6013 #if defined(TARGET_SDL)
6014 if (network_server) /* terminate network server */
6015 SDL_KillThread(server_thread);
6018 CloseVideoDisplay();
6019 ClosePlatformDependentStuff();
6021 if (exit_value != 0)
6022 NotifyUserAboutErrorFile();