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;
204 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
208 static boolean done = FALSE;
211 printf("::: %d, %d, %d, %d => %d, %d [%d, %d] [%d, %d]\n",
212 init.busy.x, init.busy.y,
213 init.busy.align, init.busy.valign,
215 graphic_info[graphic].width,
216 graphic_info[graphic].height,
217 sync_frame, anim_initial.anim_delay);
223 if (sync_frame % anim_initial.anim_delay == 0)
228 int width = graphic_info[graphic].width;
229 int height = graphic_info[graphic].height;
230 int frame = getGraphicAnimationFrame(graphic, sync_frame);
232 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
233 BlitBitmap(src_bitmap, window, src_x, src_y, width, height, x, y);
235 /* !!! this can only draw TILEX/TILEY size animations !!! */
236 DrawGraphicAnimationExt(window, x, y, graphic, sync_frame, NO_MASKING);
240 graphic_info = graphic_info_last;
247 FreeLevelEditorGadgets();
256 static boolean gadgets_initialized = FALSE;
258 if (gadgets_initialized)
261 CreateLevelEditorGadgets();
265 CreateScreenGadgets();
267 InitGadgetsSoundCallback(PlaySoundActivating, PlaySoundSelecting);
269 gadgets_initialized = TRUE;
272 inline void InitElementSmallImagesScaledUp(int graphic)
275 struct FileInfo *fi = getImageListEntryFromImageID(graphic);
277 printf("::: '%s' -> '%s'\n", fi->token, fi->filename);
280 CreateImageWithSmallImages(graphic, graphic_info[graphic].scale_up_factor);
283 void InitElementSmallImages()
285 static int special_graphics[] =
287 IMG_EDITOR_ELEMENT_BORDER,
288 IMG_EDITOR_ELEMENT_BORDER_INPUT,
289 IMG_EDITOR_CASCADE_LIST,
290 IMG_EDITOR_CASCADE_LIST_ACTIVE,
293 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
294 int num_property_mappings = getImageListPropertyMappingSize();
297 /* initialize normal images from static configuration */
298 for (i = 0; element_to_graphic[i].element > -1; i++)
299 InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
301 /* initialize special images from static configuration */
302 for (i = 0; element_to_special_graphic[i].element > -1; i++)
303 InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
305 /* initialize images from dynamic configuration (may be elements or other) */
306 for (i = 0; i < num_property_mappings; i++)
307 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
309 /* initialize special images from above list (non-element images) */
310 for (i = 0; special_graphics[i] > -1; i++)
311 InitElementSmallImagesScaledUp(special_graphics[i]);
314 void InitScaledImages()
318 /* scale normal images from static configuration, if not already scaled */
319 for (i = 0; i < NUM_IMAGE_FILES; i++)
320 ScaleImage(i, graphic_info[i].scale_up_factor);
324 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
325 void SetBitmaps_EM(Bitmap **em_bitmap)
327 em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
328 em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].bitmap;
333 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
334 void SetBitmaps_SP(Bitmap **sp_bitmap)
336 *sp_bitmap = graphic_info[IMG_SP_OBJECTS].bitmap;
340 static int getFontBitmapID(int font_nr)
344 /* (special case: do not use special font for GAME_MODE_LOADING) */
345 if (game_status >= GAME_MODE_TITLE_INITIAL &&
346 game_status <= GAME_MODE_PSEUDO_PREVIEW)
347 special = game_status;
348 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
349 special = GFX_SPECIAL_ARG_MAIN;
351 else if (game_status == GAME_MODE_PLAYING)
352 special = GFX_SPECIAL_ARG_DOOR;
359 font_info[font_nr].token_name,
360 special_suffix_info[special].suffix);
365 return font_info[font_nr].special_bitmap_id[special];
370 static int getFontFromToken(char *token)
373 char *value = getHashEntry(font_token_hash, token);
380 /* !!! OPTIMIZE THIS BY USING HASH !!! */
381 for (i = 0; i < NUM_FONTS; i++)
382 if (strEqual(token, font_info[i].token_name))
386 /* if font not found, use reliable default value */
387 return FONT_INITIAL_1;
390 void InitFontGraphicInfo()
392 static struct FontBitmapInfo *font_bitmap_info = NULL;
393 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
394 int num_property_mappings = getImageListPropertyMappingSize();
395 int num_font_bitmaps = NUM_FONTS;
398 if (graphic_info == NULL) /* still at startup phase */
400 InitFontInfo(font_initial, NUM_INITIAL_FONTS,
401 getFontBitmapID, getFontFromToken);
406 /* ---------- initialize font graphic definitions ---------- */
408 /* always start with reliable default values (normal font graphics) */
409 for (i = 0; i < NUM_FONTS; i++)
410 font_info[i].graphic = IMG_FONT_INITIAL_1;
412 /* initialize normal font/graphic mapping from static configuration */
413 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
415 int font_nr = font_to_graphic[i].font_nr;
416 int special = font_to_graphic[i].special;
417 int graphic = font_to_graphic[i].graphic;
422 font_info[font_nr].graphic = graphic;
425 /* always start with reliable default values (special font graphics) */
426 for (i = 0; i < NUM_FONTS; i++)
428 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
430 font_info[i].special_graphic[j] = font_info[i].graphic;
431 font_info[i].special_bitmap_id[j] = i;
435 /* initialize special font/graphic mapping from static configuration */
436 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
438 int font_nr = font_to_graphic[i].font_nr;
439 int special = font_to_graphic[i].special;
440 int graphic = font_to_graphic[i].graphic;
441 int base_graphic = font2baseimg(font_nr);
443 if (IS_SPECIAL_GFX_ARG(special))
445 boolean base_redefined =
446 getImageListEntryFromImageID(base_graphic)->redefined;
447 boolean special_redefined =
448 getImageListEntryFromImageID(graphic)->redefined;
449 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
451 /* if the base font ("font.title_1", for example) has been redefined,
452 but not the special font ("font.title_1.LEVELS", for example), do not
453 use an existing (in this case considered obsolete) special font
454 anymore, but use the automatically determined default font */
455 /* special case: cloned special fonts must be explicitly redefined,
456 but are not automatically redefined by redefining base font */
457 if (base_redefined && !special_redefined && !special_cloned)
460 font_info[font_nr].special_graphic[special] = graphic;
461 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
466 /* initialize special font/graphic mapping from dynamic configuration */
467 for (i = 0; i < num_property_mappings; i++)
469 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
470 int special = property_mapping[i].ext3_index;
471 int graphic = property_mapping[i].artwork_index;
476 if (IS_SPECIAL_GFX_ARG(special))
478 font_info[font_nr].special_graphic[special] = graphic;
479 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
484 /* correct special font/graphic mapping for cloned fonts for downwards
485 compatibility of PREVIEW fonts -- this is only needed for implicit
486 redefinition of special font by redefined base font, and only if other
487 fonts are cloned from this special font (like in the "Zelda" level set) */
488 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
490 int font_nr = font_to_graphic[i].font_nr;
491 int special = font_to_graphic[i].special;
492 int graphic = font_to_graphic[i].graphic;
494 if (IS_SPECIAL_GFX_ARG(special))
496 boolean special_redefined =
497 getImageListEntryFromImageID(graphic)->redefined;
498 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
500 if (special_cloned && !special_redefined)
504 for (j = 0; font_to_graphic[j].font_nr > -1; j++)
506 int font_nr2 = font_to_graphic[j].font_nr;
507 int special2 = font_to_graphic[j].special;
508 int graphic2 = font_to_graphic[j].graphic;
510 if (IS_SPECIAL_GFX_ARG(special2) &&
511 graphic2 == graphic_info[graphic].clone_from)
513 font_info[font_nr].special_graphic[special] =
514 font_info[font_nr2].special_graphic[special2];
515 font_info[font_nr].special_bitmap_id[special] =
516 font_info[font_nr2].special_bitmap_id[special2];
523 /* reset non-redefined ".active" font graphics if normal font is redefined */
524 /* (this different treatment is needed because normal and active fonts are
525 independently defined ("active" is not a property of font definitions!) */
526 for (i = 0; i < NUM_FONTS; i++)
528 int font_nr_base = i;
529 int font_nr_active = FONT_ACTIVE(font_nr_base);
531 /* check only those fonts with exist as normal and ".active" variant */
532 if (font_nr_base != font_nr_active)
534 int base_graphic = font_info[font_nr_base].graphic;
535 int active_graphic = font_info[font_nr_active].graphic;
536 boolean base_redefined =
537 getImageListEntryFromImageID(base_graphic)->redefined;
538 boolean active_redefined =
539 getImageListEntryFromImageID(active_graphic)->redefined;
541 /* if the base font ("font.menu_1", for example) has been redefined,
542 but not the active font ("font.menu_1.active", for example), do not
543 use an existing (in this case considered obsolete) active font
544 anymore, but use the automatically determined default font */
545 if (base_redefined && !active_redefined)
546 font_info[font_nr_active].graphic = base_graphic;
548 /* now also check each "special" font (which may be the same as above) */
549 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
551 int base_graphic = font_info[font_nr_base].special_graphic[j];
552 int active_graphic = font_info[font_nr_active].special_graphic[j];
553 boolean base_redefined =
554 getImageListEntryFromImageID(base_graphic)->redefined;
555 boolean active_redefined =
556 getImageListEntryFromImageID(active_graphic)->redefined;
558 /* same as above, but check special graphic definitions, for example:
559 redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN" */
560 if (base_redefined && !active_redefined)
562 font_info[font_nr_active].special_graphic[j] =
563 font_info[font_nr_base].special_graphic[j];
564 font_info[font_nr_active].special_bitmap_id[j] =
565 font_info[font_nr_base].special_bitmap_id[j];
571 /* ---------- initialize font bitmap array ---------- */
573 if (font_bitmap_info != NULL)
574 FreeFontInfo(font_bitmap_info);
577 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
579 /* ---------- initialize font bitmap definitions ---------- */
581 for (i = 0; i < NUM_FONTS; i++)
583 if (i < NUM_INITIAL_FONTS)
585 font_bitmap_info[i] = font_initial[i];
589 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
591 int font_bitmap_id = font_info[i].special_bitmap_id[j];
592 int graphic = font_info[i].special_graphic[j];
594 /* set 'graphic_info' for font entries, if uninitialized (guessed) */
595 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
597 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
598 graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
601 /* copy font relevant information from graphics information */
602 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
603 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
604 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
605 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
606 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
608 font_bitmap_info[font_bitmap_id].draw_xoffset =
609 graphic_info[graphic].draw_xoffset;
610 font_bitmap_info[font_bitmap_id].draw_yoffset =
611 graphic_info[graphic].draw_yoffset;
613 font_bitmap_info[font_bitmap_id].num_chars =
614 graphic_info[graphic].anim_frames;
615 font_bitmap_info[font_bitmap_id].num_chars_per_line =
616 graphic_info[graphic].anim_frames_per_line;
620 InitFontInfo(font_bitmap_info, num_font_bitmaps,
621 getFontBitmapID, getFontFromToken);
624 void InitElementGraphicInfo()
626 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
627 int num_property_mappings = getImageListPropertyMappingSize();
630 if (graphic_info == NULL) /* still at startup phase */
633 /* set values to -1 to identify later as "uninitialized" values */
634 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
636 for (act = 0; act < NUM_ACTIONS; act++)
638 element_info[i].graphic[act] = -1;
639 element_info[i].crumbled[act] = -1;
641 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
643 element_info[i].direction_graphic[act][dir] = -1;
644 element_info[i].direction_crumbled[act][dir] = -1;
651 /* initialize normal element/graphic mapping from static configuration */
652 for (i = 0; element_to_graphic[i].element > -1; i++)
654 int element = element_to_graphic[i].element;
655 int action = element_to_graphic[i].action;
656 int direction = element_to_graphic[i].direction;
657 boolean crumbled = element_to_graphic[i].crumbled;
658 int graphic = element_to_graphic[i].graphic;
659 int base_graphic = el2baseimg(element);
661 if (graphic_info[graphic].bitmap == NULL)
664 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
667 boolean base_redefined =
668 getImageListEntryFromImageID(base_graphic)->redefined;
669 boolean act_dir_redefined =
670 getImageListEntryFromImageID(graphic)->redefined;
672 /* if the base graphic ("emerald", for example) has been redefined,
673 but not the action graphic ("emerald.falling", for example), do not
674 use an existing (in this case considered obsolete) action graphic
675 anymore, but use the automatically determined default graphic */
676 if (base_redefined && !act_dir_redefined)
681 action = ACTION_DEFAULT;
686 element_info[element].direction_crumbled[action][direction] = graphic;
688 element_info[element].crumbled[action] = graphic;
693 element_info[element].direction_graphic[action][direction] = graphic;
695 element_info[element].graphic[action] = graphic;
699 /* initialize normal element/graphic mapping from dynamic configuration */
700 for (i = 0; i < num_property_mappings; i++)
702 int element = property_mapping[i].base_index;
703 int action = property_mapping[i].ext1_index;
704 int direction = property_mapping[i].ext2_index;
705 int special = property_mapping[i].ext3_index;
706 int graphic = property_mapping[i].artwork_index;
707 boolean crumbled = FALSE;
710 if ((element == EL_EM_DYNAMITE ||
711 element == EL_EM_DYNAMITE_ACTIVE) &&
712 action == ACTION_ACTIVE &&
713 (special == GFX_SPECIAL_ARG_EDITOR ||
714 special == GFX_SPECIAL_ARG_PANEL))
715 printf("::: DYNAMIC: %d, %d, %d -> %d\n",
716 element, action, special, graphic);
719 if (special == GFX_SPECIAL_ARG_CRUMBLED)
725 if (graphic_info[graphic].bitmap == NULL)
728 if (element >= MAX_NUM_ELEMENTS || special != -1)
732 action = ACTION_DEFAULT;
737 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
738 element_info[element].direction_crumbled[action][dir] = -1;
741 element_info[element].direction_crumbled[action][direction] = graphic;
743 element_info[element].crumbled[action] = graphic;
748 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
749 element_info[element].direction_graphic[action][dir] = -1;
752 element_info[element].direction_graphic[action][direction] = graphic;
754 element_info[element].graphic[action] = graphic;
758 /* now copy all graphics that are defined to be cloned from other graphics */
759 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
761 int graphic = element_info[i].graphic[ACTION_DEFAULT];
762 int crumbled_like, diggable_like;
767 crumbled_like = graphic_info[graphic].crumbled_like;
768 diggable_like = graphic_info[graphic].diggable_like;
770 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
772 for (act = 0; act < NUM_ACTIONS; act++)
773 element_info[i].crumbled[act] =
774 element_info[crumbled_like].crumbled[act];
775 for (act = 0; act < NUM_ACTIONS; act++)
776 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
777 element_info[i].direction_crumbled[act][dir] =
778 element_info[crumbled_like].direction_crumbled[act][dir];
781 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
783 element_info[i].graphic[ACTION_DIGGING] =
784 element_info[diggable_like].graphic[ACTION_DIGGING];
785 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
786 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
787 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
792 /* set hardcoded definitions for some runtime elements without graphic */
793 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
797 /* set hardcoded definitions for some internal elements without graphic */
798 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
800 if (IS_EDITOR_CASCADE_INACTIVE(i))
801 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
802 else if (IS_EDITOR_CASCADE_ACTIVE(i))
803 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
807 /* now set all undefined/invalid graphics to -1 to set to default after it */
808 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
810 for (act = 0; act < NUM_ACTIONS; act++)
814 graphic = element_info[i].graphic[act];
815 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
816 element_info[i].graphic[act] = -1;
818 graphic = element_info[i].crumbled[act];
819 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
820 element_info[i].crumbled[act] = -1;
822 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
824 graphic = element_info[i].direction_graphic[act][dir];
825 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
826 element_info[i].direction_graphic[act][dir] = -1;
828 graphic = element_info[i].direction_crumbled[act][dir];
829 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
830 element_info[i].direction_crumbled[act][dir] = -1;
837 /* adjust graphics with 2nd tile for movement according to direction
838 (do this before correcting '-1' values to minimize calculations) */
839 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
841 for (act = 0; act < NUM_ACTIONS; act++)
843 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
845 int graphic = element_info[i].direction_graphic[act][dir];
846 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
848 if (act == ACTION_FALLING) /* special case */
849 graphic = element_info[i].graphic[act];
852 graphic_info[graphic].double_movement &&
853 graphic_info[graphic].swap_double_tiles != 0)
855 struct GraphicInfo *g = &graphic_info[graphic];
856 int src_x_front = g->src_x;
857 int src_y_front = g->src_y;
858 int src_x_back = g->src_x + g->offset2_x;
859 int src_y_back = g->src_y + g->offset2_y;
860 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
862 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
863 src_y_front < src_y_back);
864 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
865 boolean swap_movement_tiles_autodetected =
866 (!frames_are_ordered_diagonally &&
867 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
868 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
869 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
870 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
873 /* swap frontside and backside graphic tile coordinates, if needed */
874 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
876 /* get current (wrong) backside tile coordinates */
877 getGraphicSourceExt(graphic, 0, &dummy, &src_x_back, &src_y_back,
880 /* set frontside tile coordinates to backside tile coordinates */
881 g->src_x = src_x_back;
882 g->src_y = src_y_back;
884 /* invert tile offset to point to new backside tile coordinates */
888 /* do not swap front and backside tiles again after correction */
889 g->swap_double_tiles = 0;
898 /* now set all '-1' values to element specific default values */
899 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
901 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
902 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
903 int default_direction_graphic[NUM_DIRECTIONS_FULL];
904 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
906 if (default_graphic == -1)
907 default_graphic = IMG_UNKNOWN;
909 if (default_crumbled == -1)
910 default_crumbled = default_graphic;
912 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
913 if (default_crumbled == -1)
914 default_crumbled = IMG_EMPTY;
917 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
919 default_direction_graphic[dir] =
920 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
921 default_direction_crumbled[dir] =
922 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
924 if (default_direction_graphic[dir] == -1)
925 default_direction_graphic[dir] = default_graphic;
927 if (default_direction_crumbled[dir] == -1)
928 default_direction_crumbled[dir] = default_direction_graphic[dir];
930 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
931 if (default_direction_crumbled[dir] == -1)
932 default_direction_crumbled[dir] = default_crumbled;
936 for (act = 0; act < NUM_ACTIONS; act++)
938 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
939 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
940 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
941 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
942 act == ACTION_TURNING_FROM_RIGHT ||
943 act == ACTION_TURNING_FROM_UP ||
944 act == ACTION_TURNING_FROM_DOWN);
946 /* generic default action graphic (defined by "[default]" directive) */
947 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
948 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
949 int default_remove_graphic = IMG_EMPTY;
951 if (act_remove && default_action_graphic != -1)
952 default_remove_graphic = default_action_graphic;
954 /* look for special default action graphic (classic game specific) */
955 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
956 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
957 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
958 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
959 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
960 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
962 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
963 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
964 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
965 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
966 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
967 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
970 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
971 /* !!! make this better !!! */
972 if (i == EL_EMPTY_SPACE)
974 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
975 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
979 if (default_action_graphic == -1)
980 default_action_graphic = default_graphic;
982 if (default_action_crumbled == -1)
983 default_action_crumbled = default_action_graphic;
985 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
986 if (default_action_crumbled == -1)
987 default_action_crumbled = default_crumbled;
990 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
992 /* use action graphic as the default direction graphic, if undefined */
993 int default_action_direction_graphic = element_info[i].graphic[act];
994 int default_action_direction_crumbled = element_info[i].crumbled[act];
996 /* no graphic for current action -- use default direction graphic */
997 if (default_action_direction_graphic == -1)
998 default_action_direction_graphic =
999 (act_remove ? default_remove_graphic :
1001 element_info[i].direction_graphic[ACTION_TURNING][dir] :
1002 default_action_graphic != default_graphic ?
1003 default_action_graphic :
1004 default_direction_graphic[dir]);
1006 if (element_info[i].direction_graphic[act][dir] == -1)
1007 element_info[i].direction_graphic[act][dir] =
1008 default_action_direction_graphic;
1011 if (default_action_direction_crumbled == -1)
1012 default_action_direction_crumbled =
1013 element_info[i].direction_graphic[act][dir];
1015 if (default_action_direction_crumbled == -1)
1016 default_action_direction_crumbled =
1017 (act_remove ? default_remove_graphic :
1019 element_info[i].direction_crumbled[ACTION_TURNING][dir] :
1020 default_action_crumbled != default_crumbled ?
1021 default_action_crumbled :
1022 default_direction_crumbled[dir]);
1025 if (element_info[i].direction_crumbled[act][dir] == -1)
1026 element_info[i].direction_crumbled[act][dir] =
1027 default_action_direction_crumbled;
1030 /* no graphic for this specific action -- use default action graphic */
1031 if (element_info[i].graphic[act] == -1)
1032 element_info[i].graphic[act] =
1033 (act_remove ? default_remove_graphic :
1034 act_turning ? element_info[i].graphic[ACTION_TURNING] :
1035 default_action_graphic);
1037 if (element_info[i].crumbled[act] == -1)
1038 element_info[i].crumbled[act] = element_info[i].graphic[act];
1040 if (element_info[i].crumbled[act] == -1)
1041 element_info[i].crumbled[act] =
1042 (act_remove ? default_remove_graphic :
1043 act_turning ? element_info[i].crumbled[ACTION_TURNING] :
1044 default_action_crumbled);
1049 UPDATE_BUSY_STATE();
1052 /* !!! THIS ALSO CLEARS SPECIAL FLAGS (AND IS NOT NEEDED ANYWAY) !!! */
1053 /* set animation mode to "none" for each graphic with only 1 frame */
1054 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1056 for (act = 0; act < NUM_ACTIONS; act++)
1058 int graphic = element_info[i].graphic[act];
1059 int crumbled = element_info[i].crumbled[act];
1061 if (graphic_info[graphic].anim_frames == 1)
1062 graphic_info[graphic].anim_mode = ANIM_NONE;
1063 if (graphic_info[crumbled].anim_frames == 1)
1064 graphic_info[crumbled].anim_mode = ANIM_NONE;
1066 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1068 graphic = element_info[i].direction_graphic[act][dir];
1069 crumbled = element_info[i].direction_crumbled[act][dir];
1071 if (graphic_info[graphic].anim_frames == 1)
1072 graphic_info[graphic].anim_mode = ANIM_NONE;
1073 if (graphic_info[crumbled].anim_frames == 1)
1074 graphic_info[crumbled].anim_mode = ANIM_NONE;
1082 if (options.verbose)
1084 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1085 if (element_info[i].graphic[ACTION_DEFAULT] == IMG_UNKNOWN &&
1087 Error(ERR_INFO, "warning: no graphic for element '%s' (%d)",
1088 element_info[i].token_name, i);
1094 void InitElementSpecialGraphicInfo()
1096 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
1097 int num_property_mappings = getImageListPropertyMappingSize();
1100 /* always start with reliable default values */
1101 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1102 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1103 element_info[i].special_graphic[j] =
1104 element_info[i].graphic[ACTION_DEFAULT];
1106 /* initialize special element/graphic mapping from static configuration */
1107 for (i = 0; element_to_special_graphic[i].element > -1; i++)
1109 int element = element_to_special_graphic[i].element;
1110 int special = element_to_special_graphic[i].special;
1111 int graphic = element_to_special_graphic[i].graphic;
1112 int base_graphic = el2baseimg(element);
1113 boolean base_redefined =
1114 getImageListEntryFromImageID(base_graphic)->redefined;
1115 boolean special_redefined =
1116 getImageListEntryFromImageID(graphic)->redefined;
1119 if ((element == EL_EM_DYNAMITE ||
1120 element == EL_EM_DYNAMITE_ACTIVE) &&
1121 (special == GFX_SPECIAL_ARG_EDITOR ||
1122 special == GFX_SPECIAL_ARG_PANEL))
1123 printf("::: SPECIAL STATIC: %d, %d -> %d\n",
1124 element, special, graphic);
1127 /* if the base graphic ("emerald", for example) has been redefined,
1128 but not the special graphic ("emerald.EDITOR", for example), do not
1129 use an existing (in this case considered obsolete) special graphic
1130 anymore, but use the automatically created (down-scaled) graphic */
1131 if (base_redefined && !special_redefined)
1134 element_info[element].special_graphic[special] = graphic;
1137 /* initialize special element/graphic mapping from dynamic configuration */
1138 for (i = 0; i < num_property_mappings; i++)
1140 int element = property_mapping[i].base_index;
1141 int action = property_mapping[i].ext1_index;
1142 int direction = property_mapping[i].ext2_index;
1143 int special = property_mapping[i].ext3_index;
1144 int graphic = property_mapping[i].artwork_index;
1147 if ((element == EL_EM_DYNAMITE ||
1148 element == EL_EM_DYNAMITE_ACTIVE ||
1149 element == EL_CONVEYOR_BELT_1_MIDDLE ||
1150 element == EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE) &&
1151 (special == GFX_SPECIAL_ARG_EDITOR ||
1152 special == GFX_SPECIAL_ARG_PANEL))
1153 printf("::: SPECIAL DYNAMIC: %d, %d -> %d [%d]\n",
1154 element, special, graphic, property_mapping[i].ext1_index);
1158 if (element == EL_CONVEYOR_BELT_1_MIDDLE &&
1159 action == ACTION_ACTIVE)
1161 element = EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE;
1167 if (element == EL_MAGIC_WALL &&
1168 action == ACTION_ACTIVE)
1170 element = EL_MAGIC_WALL_ACTIVE;
1176 /* for action ".active", replace element with active element, if exists */
1177 if (action == ACTION_ACTIVE && element != ELEMENT_ACTIVE(element))
1179 element = ELEMENT_ACTIVE(element);
1184 if (element >= MAX_NUM_ELEMENTS)
1187 /* do not change special graphic if action or direction was specified */
1188 if (action != -1 || direction != -1)
1191 if (IS_SPECIAL_GFX_ARG(special))
1192 element_info[element].special_graphic[special] = graphic;
1195 /* now set all undefined/invalid graphics to default */
1196 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1197 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1198 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
1199 element_info[i].special_graphic[j] =
1200 element_info[i].graphic[ACTION_DEFAULT];
1203 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
1205 if (type != TYPE_ELEMENT && type != TYPE_GRAPHIC)
1206 return get_parameter_value(value_raw, suffix, type);
1208 if (strEqual(value_raw, ARG_UNDEFINED))
1209 return ARG_UNDEFINED_VALUE;
1212 if (type == TYPE_ELEMENT)
1214 char *value = getHashEntry(element_token_hash, value_raw);
1216 return (value != NULL ? atoi(value) : EL_UNDEFINED);
1218 else if (type == TYPE_GRAPHIC)
1220 char *value = getHashEntry(graphic_token_hash, value_raw);
1222 return (value != NULL ? atoi(value) : IMG_UNDEFINED);
1230 /* !!! THIS IS BUGGY !!! NOT SURE IF YOU GET ELEMENT ID OR GRAPHIC ID !!! */
1231 /* !!! (possible reason why ".clone_from" with elements doesn't work) !!! */
1233 /* !!! OPTIMIZE THIS BY USING HASH !!! */
1234 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1235 if (strEqual(element_info[i].token_name, value_raw))
1238 /* !!! OPTIMIZE THIS BY USING HASH !!! */
1239 for (i = 0; image_config[i].token != NULL; i++)
1241 int len_config_value = strlen(image_config[i].value);
1243 if (!strEqual(&image_config[i].value[len_config_value - 4], ".pcx") &&
1244 !strEqual(&image_config[i].value[len_config_value - 4], ".wav") &&
1245 !strEqual(image_config[i].value, UNDEFINED_FILENAME))
1248 if (strEqual(image_config[i].token, value_raw))
1258 static int get_scaled_graphic_width(int graphic)
1260 int original_width = getOriginalImageWidthFromImageID(graphic);
1261 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1263 return original_width * scale_up_factor;
1266 static int get_scaled_graphic_height(int graphic)
1268 int original_height = getOriginalImageHeightFromImageID(graphic);
1269 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1271 return original_height * scale_up_factor;
1274 static void set_graphic_parameters_ext(int graphic, int *parameter,
1277 struct GraphicInfo *g = &graphic_info[graphic];
1278 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1279 int anim_frames_per_line = 1;
1281 /* always start with reliable default values */
1282 g->src_image_width = 0;
1283 g->src_image_height = 0;
1286 g->width = TILEX; /* default for element graphics */
1287 g->height = TILEY; /* default for element graphics */
1288 g->offset_x = 0; /* one or both of these values ... */
1289 g->offset_y = 0; /* ... will be corrected later */
1290 g->offset2_x = 0; /* one or both of these values ... */
1291 g->offset2_y = 0; /* ... will be corrected later */
1292 g->swap_double_tiles = -1; /* auto-detect tile swapping */
1293 g->crumbled_like = -1; /* do not use clone element */
1294 g->diggable_like = -1; /* do not use clone element */
1295 g->border_size = TILEX / 8; /* "CRUMBLED" border size */
1296 g->scale_up_factor = 1; /* default: no scaling up */
1297 g->clone_from = -1; /* do not use clone graphic */
1298 g->anim_delay_fixed = 0;
1299 g->anim_delay_random = 0;
1300 g->post_delay_fixed = 0;
1301 g->post_delay_random = 0;
1302 g->fade_mode = FADE_MODE_DEFAULT;
1306 g->align = ALIGN_CENTER; /* default for title screens */
1307 g->valign = VALIGN_MIDDLE; /* default for title screens */
1308 g->sort_priority = 0; /* default for title screens */
1310 g->bitmap = src_bitmap;
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 */
1321 if (g->use_image_size)
1323 /* set new default bitmap size (with scaling, but without small images) */
1324 g->width = get_scaled_graphic_width(graphic);
1325 g->height = get_scaled_graphic_height(graphic);
1329 /* optional x and y tile position of animation frame sequence */
1330 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1331 g->src_x = parameter[GFX_ARG_XPOS] * TILEX;
1332 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1333 g->src_y = parameter[GFX_ARG_YPOS] * TILEY;
1335 /* optional x and y pixel position of animation frame sequence */
1336 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1337 g->src_x = parameter[GFX_ARG_X];
1338 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1339 g->src_y = parameter[GFX_ARG_Y];
1341 /* optional width and height of each animation frame */
1342 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1343 g->width = parameter[GFX_ARG_WIDTH];
1344 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1345 g->height = parameter[GFX_ARG_HEIGHT];
1348 /* optional zoom factor for scaling up the image to a larger size */
1349 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1350 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1351 if (g->scale_up_factor < 1)
1352 g->scale_up_factor = 1; /* no scaling */
1357 /* get final bitmap size (with scaling, but without small images) */
1358 int src_image_width = get_scaled_graphic_width(graphic);
1359 int src_image_height = get_scaled_graphic_height(graphic);
1361 if (src_image_width == 0 || src_image_height == 0)
1363 /* only happens when loaded outside artwork system (like "global.busy") */
1364 src_image_width = src_bitmap->width;
1365 src_image_height = src_bitmap->height;
1368 anim_frames_per_row = src_image_width / g->width;
1369 anim_frames_per_col = src_image_height / g->height;
1371 g->src_image_width = src_image_width;
1372 g->src_image_height = src_image_height;
1375 /* correct x or y offset dependent of vertical or horizontal frame order */
1376 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1378 g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1379 parameter[GFX_ARG_OFFSET] : g->height);
1380 anim_frames_per_line = anim_frames_per_col;
1382 else /* frames are ordered horizontally */
1384 g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1385 parameter[GFX_ARG_OFFSET] : g->width);
1386 anim_frames_per_line = anim_frames_per_row;
1389 /* optionally, the x and y offset of frames can be specified directly */
1390 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1391 g->offset_x = parameter[GFX_ARG_XOFFSET];
1392 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1393 g->offset_y = parameter[GFX_ARG_YOFFSET];
1395 /* optionally, moving animations may have separate start and end graphics */
1396 g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1398 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1399 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1401 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1402 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1403 g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1404 parameter[GFX_ARG_2ND_OFFSET] : g->height);
1405 else /* frames are ordered horizontally */
1406 g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1407 parameter[GFX_ARG_2ND_OFFSET] : g->width);
1409 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1410 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1411 g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1412 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1413 g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1415 /* optionally, the second movement tile can be specified as start tile */
1416 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1417 g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1419 /* automatically determine correct number of frames, if not defined */
1420 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1421 g->anim_frames = parameter[GFX_ARG_FRAMES];
1422 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1423 g->anim_frames = anim_frames_per_row;
1424 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1425 g->anim_frames = anim_frames_per_col;
1429 if (g->anim_frames == 0) /* frames must be at least 1 */
1432 g->anim_frames_per_line =
1433 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1434 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1436 g->anim_delay = parameter[GFX_ARG_DELAY];
1437 if (g->anim_delay == 0) /* delay must be at least 1 */
1440 g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1442 if (g->anim_frames == 1)
1443 g->anim_mode = ANIM_NONE;
1446 /* automatically determine correct start frame, if not defined */
1447 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1448 g->anim_start_frame = 0;
1449 else if (g->anim_mode & ANIM_REVERSE)
1450 g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1452 g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1454 /* animation synchronized with global frame counter, not move position */
1455 g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1457 /* optional element for cloning crumble graphics */
1458 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1459 g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1461 /* optional element for cloning digging graphics */
1462 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1463 g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1465 /* optional border size for "crumbling" diggable graphics */
1466 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1467 g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1469 /* this is only used for player "boring" and "sleeping" actions */
1470 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1471 g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1472 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1473 g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1474 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1475 g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1476 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1477 g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1479 /* this is only used for toon animations */
1480 g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1481 g->step_delay = parameter[GFX_ARG_STEP_DELAY];
1483 /* this is only used for drawing font characters */
1484 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1485 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1487 /* this is only used for drawing envelope graphics */
1488 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1490 /* optional graphic for cloning all graphics settings */
1491 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1492 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1494 /* optional settings for drawing title screens and title messages */
1495 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1496 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1497 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1498 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1499 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1500 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1501 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1502 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1503 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1504 g->align = parameter[GFX_ARG_ALIGN];
1505 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1506 g->valign = parameter[GFX_ARG_VALIGN];
1507 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1508 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1511 static void set_graphic_parameters(int graphic)
1514 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1515 char **parameter_raw = image->parameter;
1516 Bitmap *src_bitmap = getBitmapFromImageID(graphic);
1517 int parameter[NUM_GFX_ARGS];
1520 /* if fallback to default artwork is done, also use the default parameters */
1521 if (image->fallback_to_default)
1522 parameter_raw = image->default_parameter;
1524 /* get integer values from string parameters */
1525 for (i = 0; i < NUM_GFX_ARGS; i++)
1526 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1527 image_config_suffix[i].token,
1528 image_config_suffix[i].type);
1530 set_graphic_parameters_ext(graphic, parameter, src_bitmap);
1534 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1535 char **parameter_raw = image->parameter;
1536 Bitmap *src_bitmap = getBitmapFromImageID(graphic);
1537 int parameter[NUM_GFX_ARGS];
1538 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1539 int anim_frames_per_line = 1;
1542 /* if fallback to default artwork is done, also use the default parameters */
1543 if (image->fallback_to_default)
1544 parameter_raw = image->default_parameter;
1546 /* get integer values from string parameters */
1547 for (i = 0; i < NUM_GFX_ARGS; i++)
1548 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1549 image_config_suffix[i].token,
1550 image_config_suffix[i].type);
1552 graphic_info[graphic].bitmap = src_bitmap;
1554 /* always start with reliable default values */
1555 graphic_info[graphic].src_image_width = 0;
1556 graphic_info[graphic].src_image_height = 0;
1557 graphic_info[graphic].src_x = 0;
1558 graphic_info[graphic].src_y = 0;
1559 graphic_info[graphic].width = TILEX; /* default for element graphics */
1560 graphic_info[graphic].height = TILEY; /* default for element graphics */
1561 graphic_info[graphic].offset_x = 0; /* one or both of these values ... */
1562 graphic_info[graphic].offset_y = 0; /* ... will be corrected later */
1563 graphic_info[graphic].offset2_x = 0; /* one or both of these values ... */
1564 graphic_info[graphic].offset2_y = 0; /* ... will be corrected later */
1565 graphic_info[graphic].swap_double_tiles = -1; /* auto-detect tile swapping */
1566 graphic_info[graphic].crumbled_like = -1; /* do not use clone element */
1567 graphic_info[graphic].diggable_like = -1; /* do not use clone element */
1568 graphic_info[graphic].border_size = TILEX / 8; /* "CRUMBLED" border size */
1569 graphic_info[graphic].scale_up_factor = 1; /* default: no scaling up */
1570 graphic_info[graphic].clone_from = -1; /* do not use clone graphic */
1571 graphic_info[graphic].anim_delay_fixed = 0;
1572 graphic_info[graphic].anim_delay_random = 0;
1573 graphic_info[graphic].post_delay_fixed = 0;
1574 graphic_info[graphic].post_delay_random = 0;
1575 graphic_info[graphic].fade_mode = FADE_MODE_DEFAULT;
1576 graphic_info[graphic].fade_delay = -1;
1577 graphic_info[graphic].post_delay = -1;
1578 graphic_info[graphic].auto_delay = -1;
1579 graphic_info[graphic].align = ALIGN_CENTER; /* default for title screens */
1580 graphic_info[graphic].valign = VALIGN_MIDDLE; /* default for title screens */
1581 graphic_info[graphic].sort_priority = 0; /* default for title screens */
1584 /* optional zoom factor for scaling up the image to a larger size */
1585 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1586 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1587 if (graphic_info[graphic].scale_up_factor < 1)
1588 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
1592 if (graphic_info[graphic].use_image_size)
1594 /* set new default bitmap size (with scaling, but without small images) */
1595 graphic_info[graphic].width = get_scaled_graphic_width(graphic);
1596 graphic_info[graphic].height = get_scaled_graphic_height(graphic);
1600 /* optional x and y tile position of animation frame sequence */
1601 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1602 graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
1603 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1604 graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
1606 /* optional x and y pixel position of animation frame sequence */
1607 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1608 graphic_info[graphic].src_x = parameter[GFX_ARG_X];
1609 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1610 graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
1612 /* optional width and height of each animation frame */
1613 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1614 graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
1615 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1616 graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
1619 /* optional zoom factor for scaling up the image to a larger size */
1620 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1621 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1622 if (graphic_info[graphic].scale_up_factor < 1)
1623 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
1628 /* get final bitmap size (with scaling, but without small images) */
1629 int src_image_width = get_scaled_graphic_width(graphic);
1630 int src_image_height = get_scaled_graphic_height(graphic);
1632 anim_frames_per_row = src_image_width / graphic_info[graphic].width;
1633 anim_frames_per_col = src_image_height / graphic_info[graphic].height;
1635 graphic_info[graphic].src_image_width = src_image_width;
1636 graphic_info[graphic].src_image_height = src_image_height;
1639 /* correct x or y offset dependent of vertical or horizontal frame order */
1640 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1642 graphic_info[graphic].offset_y =
1643 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1644 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
1645 anim_frames_per_line = anim_frames_per_col;
1647 else /* frames are ordered horizontally */
1649 graphic_info[graphic].offset_x =
1650 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1651 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
1652 anim_frames_per_line = anim_frames_per_row;
1655 /* optionally, the x and y offset of frames can be specified directly */
1656 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1657 graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
1658 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1659 graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
1661 /* optionally, moving animations may have separate start and end graphics */
1662 graphic_info[graphic].double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1664 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1665 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1667 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1668 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1669 graphic_info[graphic].offset2_y =
1670 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1671 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].height);
1672 else /* frames are ordered horizontally */
1673 graphic_info[graphic].offset2_x =
1674 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1675 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].width);
1677 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1678 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1679 graphic_info[graphic].offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1680 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1681 graphic_info[graphic].offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1683 /* optionally, the second movement tile can be specified as start tile */
1684 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1685 graphic_info[graphic].swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1687 /* automatically determine correct number of frames, if not defined */
1688 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1689 graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
1690 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1691 graphic_info[graphic].anim_frames = anim_frames_per_row;
1692 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1693 graphic_info[graphic].anim_frames = anim_frames_per_col;
1695 graphic_info[graphic].anim_frames = 1;
1697 if (graphic_info[graphic].anim_frames == 0) /* frames must be at least 1 */
1698 graphic_info[graphic].anim_frames = 1;
1700 graphic_info[graphic].anim_frames_per_line =
1701 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1702 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1704 graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
1705 if (graphic_info[graphic].anim_delay == 0) /* delay must be at least 1 */
1706 graphic_info[graphic].anim_delay = 1;
1708 graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
1710 if (graphic_info[graphic].anim_frames == 1)
1711 graphic_info[graphic].anim_mode = ANIM_NONE;
1714 /* automatically determine correct start frame, if not defined */
1715 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1716 graphic_info[graphic].anim_start_frame = 0;
1717 else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
1718 graphic_info[graphic].anim_start_frame =
1719 graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1721 graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
1723 /* animation synchronized with global frame counter, not move position */
1724 graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1726 /* optional element for cloning crumble graphics */
1727 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1728 graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1730 /* optional element for cloning digging graphics */
1731 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1732 graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1734 /* optional border size for "crumbling" diggable graphics */
1735 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1736 graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
1738 /* this is only used for player "boring" and "sleeping" actions */
1739 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1740 graphic_info[graphic].anim_delay_fixed =
1741 parameter[GFX_ARG_ANIM_DELAY_FIXED];
1742 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1743 graphic_info[graphic].anim_delay_random =
1744 parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1745 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1746 graphic_info[graphic].post_delay_fixed =
1747 parameter[GFX_ARG_POST_DELAY_FIXED];
1748 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1749 graphic_info[graphic].post_delay_random =
1750 parameter[GFX_ARG_POST_DELAY_RANDOM];
1752 /* this is only used for toon animations */
1753 graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
1754 graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY];
1756 /* this is only used for drawing font characters */
1757 graphic_info[graphic].draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1758 graphic_info[graphic].draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1760 /* this is only used for drawing envelope graphics */
1761 graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1763 /* optional graphic for cloning all graphics settings */
1764 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1765 graphic_info[graphic].clone_from = parameter[GFX_ARG_CLONE_FROM];
1767 /* optional settings for drawing title screens and title messages */
1768 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1769 graphic_info[graphic].fade_mode = parameter[GFX_ARG_FADE_MODE];
1770 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1771 graphic_info[graphic].fade_delay = parameter[GFX_ARG_FADE_DELAY];
1772 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1773 graphic_info[graphic].post_delay = parameter[GFX_ARG_POST_DELAY];
1774 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1775 graphic_info[graphic].auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1776 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1777 graphic_info[graphic].align = parameter[GFX_ARG_ALIGN];
1778 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1779 graphic_info[graphic].valign = parameter[GFX_ARG_VALIGN];
1780 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1781 graphic_info[graphic].sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1784 UPDATE_BUSY_STATE();
1787 static void set_cloned_graphic_parameters(int graphic)
1789 int fallback_graphic = IMG_CHAR_EXCLAM;
1790 int max_num_images = getImageListSize();
1791 int clone_graphic = graphic_info[graphic].clone_from;
1792 int num_references_followed = 1;
1794 while (graphic_info[clone_graphic].clone_from != -1 &&
1795 num_references_followed < max_num_images)
1797 clone_graphic = graphic_info[clone_graphic].clone_from;
1799 num_references_followed++;
1802 if (num_references_followed >= max_num_images)
1804 Error(ERR_INFO_LINE, "-");
1805 Error(ERR_INFO, "warning: error found in config file:");
1806 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1807 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1808 Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1809 Error(ERR_INFO, "custom graphic rejected for this element/action");
1811 if (graphic == fallback_graphic)
1812 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1814 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1815 Error(ERR_INFO_LINE, "-");
1817 graphic_info[graphic] = graphic_info[fallback_graphic];
1821 graphic_info[graphic] = graphic_info[clone_graphic];
1822 graphic_info[graphic].clone_from = clone_graphic;
1826 static void InitGraphicInfo()
1828 int fallback_graphic = IMG_CHAR_EXCLAM;
1829 int num_images = getImageListSize();
1832 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1833 static boolean clipmasks_initialized = FALSE;
1835 XGCValues clip_gc_values;
1836 unsigned long clip_gc_valuemask;
1837 GC copy_clipmask_gc = None;
1840 /* use image size as default values for width and height for these images */
1841 static int full_size_graphics[] =
1846 IMG_BACKGROUND_ENVELOPE_1,
1847 IMG_BACKGROUND_ENVELOPE_2,
1848 IMG_BACKGROUND_ENVELOPE_3,
1849 IMG_BACKGROUND_ENVELOPE_4,
1852 IMG_BACKGROUND_TITLE_INITIAL,
1853 IMG_BACKGROUND_TITLE,
1854 IMG_BACKGROUND_MAIN,
1855 IMG_BACKGROUND_LEVELS,
1856 IMG_BACKGROUND_SCORES,
1857 IMG_BACKGROUND_EDITOR,
1858 IMG_BACKGROUND_INFO,
1859 IMG_BACKGROUND_INFO_ELEMENTS,
1860 IMG_BACKGROUND_INFO_MUSIC,
1861 IMG_BACKGROUND_INFO_CREDITS,
1862 IMG_BACKGROUND_INFO_PROGRAM,
1863 IMG_BACKGROUND_INFO_LEVELSET,
1864 IMG_BACKGROUND_SETUP,
1865 IMG_BACKGROUND_DOOR,
1867 IMG_TITLESCREEN_INITIAL_1,
1868 IMG_TITLESCREEN_INITIAL_2,
1869 IMG_TITLESCREEN_INITIAL_3,
1870 IMG_TITLESCREEN_INITIAL_4,
1871 IMG_TITLESCREEN_INITIAL_5,
1881 checked_free(graphic_info);
1883 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1886 /* initialize "use_image_size" flag with default value */
1887 for (i = 0; i < num_images; i++)
1888 graphic_info[i].use_image_size = FALSE;
1890 /* initialize "use_image_size" flag from static configuration above */
1891 for (i = 0; full_size_graphics[i] != -1; i++)
1892 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1895 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1896 if (clipmasks_initialized)
1898 for (i = 0; i < num_images; i++)
1900 if (graphic_info[i].clip_mask)
1901 XFreePixmap(display, graphic_info[i].clip_mask);
1902 if (graphic_info[i].clip_gc)
1903 XFreeGC(display, graphic_info[i].clip_gc);
1905 graphic_info[i].clip_mask = None;
1906 graphic_info[i].clip_gc = None;
1911 /* first set all graphic paramaters ... */
1912 for (i = 0; i < num_images; i++)
1913 set_graphic_parameters(i);
1915 /* ... then copy these parameters for cloned graphics */
1916 for (i = 0; i < num_images; i++)
1917 if (graphic_info[i].clone_from != -1)
1918 set_cloned_graphic_parameters(i);
1920 for (i = 0; i < num_images; i++)
1925 int first_frame, last_frame;
1926 int src_bitmap_width, src_bitmap_height;
1928 /* now check if no animation frames are outside of the loaded image */
1930 if (graphic_info[i].bitmap == NULL)
1931 continue; /* skip check for optional images that are undefined */
1933 /* get image size (this can differ from the standard element tile size!) */
1934 width = graphic_info[i].width;
1935 height = graphic_info[i].height;
1937 /* get final bitmap size (with scaling, but without small images) */
1938 src_bitmap_width = graphic_info[i].src_image_width;
1939 src_bitmap_height = graphic_info[i].src_image_height;
1941 /* check if first animation frame is inside specified bitmap */
1944 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1947 /* this avoids calculating wrong start position for out-of-bounds frame */
1948 src_x = graphic_info[i].src_x;
1949 src_y = graphic_info[i].src_y;
1952 if (src_x < 0 || src_y < 0 ||
1953 src_x + width > src_bitmap_width ||
1954 src_y + height > src_bitmap_height)
1956 Error(ERR_INFO_LINE, "-");
1957 Error(ERR_INFO, "warning: error found in config file:");
1958 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1959 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1960 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1962 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1963 src_x, src_y, src_bitmap_width, src_bitmap_height);
1964 Error(ERR_INFO, "custom graphic rejected for this element/action");
1966 if (i == fallback_graphic)
1967 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1969 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1970 Error(ERR_INFO_LINE, "-");
1972 graphic_info[i] = graphic_info[fallback_graphic];
1975 /* check if last animation frame is inside specified bitmap */
1977 last_frame = graphic_info[i].anim_frames - 1;
1978 getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1980 if (src_x < 0 || src_y < 0 ||
1981 src_x + width > src_bitmap_width ||
1982 src_y + height > src_bitmap_height)
1984 Error(ERR_INFO_LINE, "-");
1985 Error(ERR_INFO, "warning: error found in config file:");
1986 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1987 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1988 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1990 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1991 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1992 Error(ERR_INFO, "custom graphic rejected for this element/action");
1994 if (i == fallback_graphic)
1995 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1997 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1998 Error(ERR_INFO_LINE, "-");
2000 graphic_info[i] = graphic_info[fallback_graphic];
2003 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
2004 /* currently we only need a tile clip mask from the first frame */
2005 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
2007 if (copy_clipmask_gc == None)
2009 clip_gc_values.graphics_exposures = False;
2010 clip_gc_valuemask = GCGraphicsExposures;
2011 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
2012 clip_gc_valuemask, &clip_gc_values);
2015 graphic_info[i].clip_mask =
2016 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
2018 src_pixmap = src_bitmap->clip_mask;
2019 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
2020 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
2022 clip_gc_values.graphics_exposures = False;
2023 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
2024 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
2026 graphic_info[i].clip_gc =
2027 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
2031 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
2032 if (copy_clipmask_gc)
2033 XFreeGC(display, copy_clipmask_gc);
2035 clipmasks_initialized = TRUE;
2039 static void InitElementSoundInfo()
2041 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
2042 int num_property_mappings = getSoundListPropertyMappingSize();
2045 /* set values to -1 to identify later as "uninitialized" values */
2046 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2047 for (act = 0; act < NUM_ACTIONS; act++)
2048 element_info[i].sound[act] = -1;
2050 /* initialize element/sound mapping from static configuration */
2051 for (i = 0; element_to_sound[i].element > -1; i++)
2053 int element = element_to_sound[i].element;
2054 int action = element_to_sound[i].action;
2055 int sound = element_to_sound[i].sound;
2056 boolean is_class = element_to_sound[i].is_class;
2059 action = ACTION_DEFAULT;
2062 element_info[element].sound[action] = sound;
2064 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2065 if (strEqual(element_info[j].class_name,
2066 element_info[element].class_name))
2067 element_info[j].sound[action] = sound;
2070 /* initialize element class/sound mapping from dynamic configuration */
2071 for (i = 0; i < num_property_mappings; i++)
2073 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
2074 int action = property_mapping[i].ext1_index;
2075 int sound = property_mapping[i].artwork_index;
2077 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
2081 action = ACTION_DEFAULT;
2083 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2084 if (strEqual(element_info[j].class_name,
2085 element_info[element_class].class_name))
2086 element_info[j].sound[action] = sound;
2089 /* initialize element/sound mapping from dynamic configuration */
2090 for (i = 0; i < num_property_mappings; i++)
2092 int element = property_mapping[i].base_index;
2093 int action = property_mapping[i].ext1_index;
2094 int sound = property_mapping[i].artwork_index;
2096 if (element >= MAX_NUM_ELEMENTS)
2100 action = ACTION_DEFAULT;
2102 element_info[element].sound[action] = sound;
2105 /* now set all '-1' values to element specific default values */
2106 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2108 for (act = 0; act < NUM_ACTIONS; act++)
2110 /* generic default action sound (defined by "[default]" directive) */
2111 int default_action_sound = element_info[EL_DEFAULT].sound[act];
2113 /* look for special default action sound (classic game specific) */
2114 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
2115 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
2116 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
2117 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
2118 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
2119 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
2121 /* !!! there's no such thing as a "default action sound" !!! */
2123 /* look for element specific default sound (independent from action) */
2124 if (element_info[i].sound[ACTION_DEFAULT] != -1)
2125 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
2129 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
2130 /* !!! make this better !!! */
2131 if (i == EL_EMPTY_SPACE)
2132 default_action_sound = element_info[EL_DEFAULT].sound[act];
2135 /* no sound for this specific action -- use default action sound */
2136 if (element_info[i].sound[act] == -1)
2137 element_info[i].sound[act] = default_action_sound;
2141 /* copy sound settings to some elements that are only stored in level file
2142 in native R'n'D levels, but are used by game engine in native EM levels */
2143 for (i = 0; copy_properties[i][0] != -1; i++)
2144 for (j = 1; j <= 4; j++)
2145 for (act = 0; act < NUM_ACTIONS; act++)
2146 element_info[copy_properties[i][j]].sound[act] =
2147 element_info[copy_properties[i][0]].sound[act];
2150 static void InitGameModeSoundInfo()
2154 /* set values to -1 to identify later as "uninitialized" values */
2155 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2158 /* initialize gamemode/sound mapping from static configuration */
2159 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
2161 int gamemode = gamemode_to_sound[i].gamemode;
2162 int sound = gamemode_to_sound[i].sound;
2165 gamemode = GAME_MODE_DEFAULT;
2167 menu.sound[gamemode] = sound;
2170 /* now set all '-1' values to levelset specific default values */
2171 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2172 if (menu.sound[i] == -1)
2173 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
2176 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2177 if (menu.sound[i] != -1)
2178 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
2182 static void set_sound_parameters(int sound, char **parameter_raw)
2184 int parameter[NUM_SND_ARGS];
2187 /* get integer values from string parameters */
2188 for (i = 0; i < NUM_SND_ARGS; i++)
2190 get_parameter_value(parameter_raw[i],
2191 sound_config_suffix[i].token,
2192 sound_config_suffix[i].type);
2194 /* explicit loop mode setting in configuration overrides default value */
2195 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2196 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
2198 /* sound volume to change the original volume when loading the sound file */
2199 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
2201 /* sound priority to give certain sounds a higher or lower priority */
2202 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
2205 static void InitSoundInfo()
2207 int *sound_effect_properties;
2208 int num_sounds = getSoundListSize();
2211 checked_free(sound_info);
2213 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
2214 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
2216 /* initialize sound effect for all elements to "no sound" */
2217 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2218 for (j = 0; j < NUM_ACTIONS; j++)
2219 element_info[i].sound[j] = SND_UNDEFINED;
2221 for (i = 0; i < num_sounds; i++)
2223 struct FileInfo *sound = getSoundListEntry(i);
2224 int len_effect_text = strlen(sound->token);
2226 sound_effect_properties[i] = ACTION_OTHER;
2227 sound_info[i].loop = FALSE; /* default: play sound only once */
2230 printf("::: sound %d: '%s'\n", i, sound->token);
2233 /* determine all loop sounds and identify certain sound classes */
2235 for (j = 0; element_action_info[j].suffix; j++)
2237 int len_action_text = strlen(element_action_info[j].suffix);
2239 if (len_action_text < len_effect_text &&
2240 strEqual(&sound->token[len_effect_text - len_action_text],
2241 element_action_info[j].suffix))
2243 sound_effect_properties[i] = element_action_info[j].value;
2244 sound_info[i].loop = element_action_info[j].is_loop_sound;
2250 /* associate elements and some selected sound actions */
2252 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2254 if (element_info[j].class_name)
2256 int len_class_text = strlen(element_info[j].class_name);
2258 if (len_class_text + 1 < len_effect_text &&
2259 strncmp(sound->token,
2260 element_info[j].class_name, len_class_text) == 0 &&
2261 sound->token[len_class_text] == '.')
2263 int sound_action_value = sound_effect_properties[i];
2265 element_info[j].sound[sound_action_value] = i;
2270 set_sound_parameters(i, sound->parameter);
2273 free(sound_effect_properties);
2276 static void InitGameModeMusicInfo()
2278 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
2279 int num_property_mappings = getMusicListPropertyMappingSize();
2280 int default_levelset_music = -1;
2283 /* set values to -1 to identify later as "uninitialized" values */
2284 for (i = 0; i < MAX_LEVELS; i++)
2285 levelset.music[i] = -1;
2286 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2289 /* initialize gamemode/music mapping from static configuration */
2290 for (i = 0; gamemode_to_music[i].music > -1; i++)
2292 int gamemode = gamemode_to_music[i].gamemode;
2293 int music = gamemode_to_music[i].music;
2296 printf("::: gamemode == %d, music == %d\n", gamemode, music);
2300 gamemode = GAME_MODE_DEFAULT;
2302 menu.music[gamemode] = music;
2305 /* initialize gamemode/music mapping from dynamic configuration */
2306 for (i = 0; i < num_property_mappings; i++)
2308 int prefix = property_mapping[i].base_index;
2309 int gamemode = property_mapping[i].ext1_index;
2310 int level = property_mapping[i].ext2_index;
2311 int music = property_mapping[i].artwork_index;
2314 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
2315 prefix, gamemode, level, music);
2318 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
2322 gamemode = GAME_MODE_DEFAULT;
2324 /* level specific music only allowed for in-game music */
2325 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
2326 gamemode = GAME_MODE_PLAYING;
2331 default_levelset_music = music;
2334 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
2335 levelset.music[level] = music;
2336 if (gamemode != GAME_MODE_PLAYING)
2337 menu.music[gamemode] = music;
2340 /* now set all '-1' values to menu specific default values */
2341 /* (undefined values of "levelset.music[]" might stay at "-1" to
2342 allow dynamic selection of music files from music directory!) */
2343 for (i = 0; i < MAX_LEVELS; i++)
2344 if (levelset.music[i] == -1)
2345 levelset.music[i] = default_levelset_music;
2346 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2347 if (menu.music[i] == -1)
2348 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
2351 for (i = 0; i < MAX_LEVELS; i++)
2352 if (levelset.music[i] != -1)
2353 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
2354 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2355 if (menu.music[i] != -1)
2356 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
2360 static void set_music_parameters(int music, char **parameter_raw)
2362 int parameter[NUM_MUS_ARGS];
2365 /* get integer values from string parameters */
2366 for (i = 0; i < NUM_MUS_ARGS; i++)
2368 get_parameter_value(parameter_raw[i],
2369 music_config_suffix[i].token,
2370 music_config_suffix[i].type);
2372 /* explicit loop mode setting in configuration overrides default value */
2373 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2374 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
2377 static void InitMusicInfo()
2379 int num_music = getMusicListSize();
2382 checked_free(music_info);
2384 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
2386 for (i = 0; i < num_music; i++)
2388 struct FileInfo *music = getMusicListEntry(i);
2389 int len_music_text = strlen(music->token);
2391 music_info[i].loop = TRUE; /* default: play music in loop mode */
2393 /* determine all loop music */
2395 for (j = 0; music_prefix_info[j].prefix; j++)
2397 int len_prefix_text = strlen(music_prefix_info[j].prefix);
2399 if (len_prefix_text < len_music_text &&
2400 strncmp(music->token,
2401 music_prefix_info[j].prefix, len_prefix_text) == 0)
2403 music_info[i].loop = music_prefix_info[j].is_loop_music;
2409 set_music_parameters(i, music->parameter);
2413 static void ReinitializeGraphics()
2415 print_timestamp_init("ReinitializeGraphics");
2417 InitGraphicInfo(); /* graphic properties mapping */
2418 print_timestamp_time("InitGraphicInfo");
2419 InitElementGraphicInfo(); /* element game graphic mapping */
2420 print_timestamp_time("InitElementGraphicInfo");
2421 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
2422 print_timestamp_time("InitElementSpecialGraphicInfo");
2424 InitElementSmallImages(); /* scale elements to all needed sizes */
2425 print_timestamp_time("InitElementSmallImages");
2426 InitScaledImages(); /* scale all other images, if needed */
2427 print_timestamp_time("InitScaledImages");
2428 InitFontGraphicInfo(); /* initialize text drawing functions */
2429 print_timestamp_time("InitFontGraphicInfo");
2431 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
2432 print_timestamp_time("InitGraphicInfo_EM");
2434 SetMainBackgroundImage(IMG_BACKGROUND);
2435 print_timestamp_time("SetMainBackgroundImage");
2436 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2437 print_timestamp_time("SetDoorBackgroundImage");
2440 print_timestamp_time("InitGadgets");
2442 print_timestamp_time("InitToons");
2444 print_timestamp_done("ReinitializeGraphics");
2447 static void ReinitializeSounds()
2449 InitSoundInfo(); /* sound properties mapping */
2450 InitElementSoundInfo(); /* element game sound mapping */
2451 InitGameModeSoundInfo(); /* game mode sound mapping */
2453 InitPlayLevelSound(); /* internal game sound settings */
2456 static void ReinitializeMusic()
2458 InitMusicInfo(); /* music properties mapping */
2459 InitGameModeMusicInfo(); /* game mode music mapping */
2462 static int get_special_property_bit(int element, int property_bit_nr)
2464 struct PropertyBitInfo
2470 static struct PropertyBitInfo pb_can_move_into_acid[] =
2472 /* the player may be able fall into acid when gravity is activated */
2477 { EL_SP_MURPHY, 0 },
2478 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2480 /* all elements that can move may be able to also move into acid */
2483 { EL_BUG_RIGHT, 1 },
2486 { EL_SPACESHIP, 2 },
2487 { EL_SPACESHIP_LEFT, 2 },
2488 { EL_SPACESHIP_RIGHT, 2 },
2489 { EL_SPACESHIP_UP, 2 },
2490 { EL_SPACESHIP_DOWN, 2 },
2491 { EL_BD_BUTTERFLY, 3 },
2492 { EL_BD_BUTTERFLY_LEFT, 3 },
2493 { EL_BD_BUTTERFLY_RIGHT, 3 },
2494 { EL_BD_BUTTERFLY_UP, 3 },
2495 { EL_BD_BUTTERFLY_DOWN, 3 },
2496 { EL_BD_FIREFLY, 4 },
2497 { EL_BD_FIREFLY_LEFT, 4 },
2498 { EL_BD_FIREFLY_RIGHT, 4 },
2499 { EL_BD_FIREFLY_UP, 4 },
2500 { EL_BD_FIREFLY_DOWN, 4 },
2502 { EL_YAMYAM_LEFT, 5 },
2503 { EL_YAMYAM_RIGHT, 5 },
2504 { EL_YAMYAM_UP, 5 },
2505 { EL_YAMYAM_DOWN, 5 },
2506 { EL_DARK_YAMYAM, 6 },
2509 { EL_PACMAN_LEFT, 8 },
2510 { EL_PACMAN_RIGHT, 8 },
2511 { EL_PACMAN_UP, 8 },
2512 { EL_PACMAN_DOWN, 8 },
2514 { EL_MOLE_LEFT, 9 },
2515 { EL_MOLE_RIGHT, 9 },
2517 { EL_MOLE_DOWN, 9 },
2521 { EL_SATELLITE, 13 },
2522 { EL_SP_SNIKSNAK, 14 },
2523 { EL_SP_ELECTRON, 15 },
2526 { EL_EMC_ANDROID, 18 },
2531 static struct PropertyBitInfo pb_dont_collide_with[] =
2533 { EL_SP_SNIKSNAK, 0 },
2534 { EL_SP_ELECTRON, 1 },
2542 struct PropertyBitInfo *pb_info;
2545 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2546 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2551 struct PropertyBitInfo *pb_info = NULL;
2554 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2555 if (pb_definition[i].bit_nr == property_bit_nr)
2556 pb_info = pb_definition[i].pb_info;
2558 if (pb_info == NULL)
2561 for (i = 0; pb_info[i].element != -1; i++)
2562 if (pb_info[i].element == element)
2563 return pb_info[i].bit_nr;
2568 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2569 boolean property_value)
2571 int bit_nr = get_special_property_bit(element, property_bit_nr);
2576 *bitfield |= (1 << bit_nr);
2578 *bitfield &= ~(1 << bit_nr);
2582 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2584 int bit_nr = get_special_property_bit(element, property_bit_nr);
2587 return ((*bitfield & (1 << bit_nr)) != 0);
2592 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2594 static int group_nr;
2595 static struct ElementGroupInfo *group;
2596 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2599 if (actual_group == NULL) /* not yet initialized */
2602 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
2604 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2605 group_element - EL_GROUP_START + 1);
2607 /* replace element which caused too deep recursion by question mark */
2608 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2613 if (recursion_depth == 0) /* initialization */
2615 group = actual_group;
2616 group_nr = GROUP_NR(group_element);
2618 group->num_elements_resolved = 0;
2619 group->choice_pos = 0;
2621 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2622 element_info[i].in_group[group_nr] = FALSE;
2625 for (i = 0; i < actual_group->num_elements; i++)
2627 int element = actual_group->element[i];
2629 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2632 if (IS_GROUP_ELEMENT(element))
2633 ResolveGroupElementExt(element, recursion_depth + 1);
2636 group->element_resolved[group->num_elements_resolved++] = element;
2637 element_info[element].in_group[group_nr] = TRUE;
2642 void ResolveGroupElement(int group_element)
2644 ResolveGroupElementExt(group_element, 0);
2647 void InitElementPropertiesStatic()
2649 static boolean clipboard_elements_initialized = FALSE;
2651 static int ep_diggable[] =
2656 EL_SP_BUGGY_BASE_ACTIVATING,
2659 EL_INVISIBLE_SAND_ACTIVE,
2662 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2663 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2668 EL_SP_BUGGY_BASE_ACTIVE,
2675 static int ep_collectible_only[] =
2697 EL_DYNABOMB_INCREASE_NUMBER,
2698 EL_DYNABOMB_INCREASE_SIZE,
2699 EL_DYNABOMB_INCREASE_POWER,
2717 /* !!! handle separately !!! */
2718 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2724 static int ep_dont_run_into[] =
2726 /* same elements as in 'ep_dont_touch' */
2732 /* same elements as in 'ep_dont_collide_with' */
2744 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2749 EL_SP_BUGGY_BASE_ACTIVE,
2756 static int ep_dont_collide_with[] =
2758 /* same elements as in 'ep_dont_touch' */
2775 static int ep_dont_touch[] =
2785 static int ep_indestructible[] =
2789 EL_ACID_POOL_TOPLEFT,
2790 EL_ACID_POOL_TOPRIGHT,
2791 EL_ACID_POOL_BOTTOMLEFT,
2792 EL_ACID_POOL_BOTTOM,
2793 EL_ACID_POOL_BOTTOMRIGHT,
2794 EL_SP_HARDWARE_GRAY,
2795 EL_SP_HARDWARE_GREEN,
2796 EL_SP_HARDWARE_BLUE,
2798 EL_SP_HARDWARE_YELLOW,
2799 EL_SP_HARDWARE_BASE_1,
2800 EL_SP_HARDWARE_BASE_2,
2801 EL_SP_HARDWARE_BASE_3,
2802 EL_SP_HARDWARE_BASE_4,
2803 EL_SP_HARDWARE_BASE_5,
2804 EL_SP_HARDWARE_BASE_6,
2805 EL_INVISIBLE_STEELWALL,
2806 EL_INVISIBLE_STEELWALL_ACTIVE,
2807 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2808 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2809 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2810 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2811 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2812 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2813 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2814 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2815 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2816 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2817 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2818 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2820 EL_LIGHT_SWITCH_ACTIVE,
2821 EL_SIGN_EXCLAMATION,
2822 EL_SIGN_RADIOACTIVITY,
2829 EL_SIGN_ENTRY_FORBIDDEN,
2830 EL_SIGN_EMERGENCY_EXIT,
2838 EL_STEEL_EXIT_CLOSED,
2840 EL_STEEL_EXIT_OPENING,
2841 EL_STEEL_EXIT_CLOSING,
2842 EL_EM_STEEL_EXIT_CLOSED,
2843 EL_EM_STEEL_EXIT_OPEN,
2844 EL_EM_STEEL_EXIT_OPENING,
2845 EL_EM_STEEL_EXIT_CLOSING,
2846 EL_DC_STEELWALL_1_LEFT,
2847 EL_DC_STEELWALL_1_RIGHT,
2848 EL_DC_STEELWALL_1_TOP,
2849 EL_DC_STEELWALL_1_BOTTOM,
2850 EL_DC_STEELWALL_1_HORIZONTAL,
2851 EL_DC_STEELWALL_1_VERTICAL,
2852 EL_DC_STEELWALL_1_TOPLEFT,
2853 EL_DC_STEELWALL_1_TOPRIGHT,
2854 EL_DC_STEELWALL_1_BOTTOMLEFT,
2855 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2856 EL_DC_STEELWALL_1_TOPLEFT_2,
2857 EL_DC_STEELWALL_1_TOPRIGHT_2,
2858 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2859 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2860 EL_DC_STEELWALL_2_LEFT,
2861 EL_DC_STEELWALL_2_RIGHT,
2862 EL_DC_STEELWALL_2_TOP,
2863 EL_DC_STEELWALL_2_BOTTOM,
2864 EL_DC_STEELWALL_2_HORIZONTAL,
2865 EL_DC_STEELWALL_2_VERTICAL,
2866 EL_DC_STEELWALL_2_MIDDLE,
2867 EL_DC_STEELWALL_2_SINGLE,
2868 EL_STEELWALL_SLIPPERY,
2882 EL_GATE_1_GRAY_ACTIVE,
2883 EL_GATE_2_GRAY_ACTIVE,
2884 EL_GATE_3_GRAY_ACTIVE,
2885 EL_GATE_4_GRAY_ACTIVE,
2894 EL_EM_GATE_1_GRAY_ACTIVE,
2895 EL_EM_GATE_2_GRAY_ACTIVE,
2896 EL_EM_GATE_3_GRAY_ACTIVE,
2897 EL_EM_GATE_4_GRAY_ACTIVE,
2906 EL_EMC_GATE_5_GRAY_ACTIVE,
2907 EL_EMC_GATE_6_GRAY_ACTIVE,
2908 EL_EMC_GATE_7_GRAY_ACTIVE,
2909 EL_EMC_GATE_8_GRAY_ACTIVE,
2911 EL_DC_GATE_WHITE_GRAY,
2912 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2913 EL_DC_GATE_FAKE_GRAY,
2915 EL_SWITCHGATE_OPENING,
2916 EL_SWITCHGATE_CLOSED,
2917 EL_SWITCHGATE_CLOSING,
2919 EL_DC_SWITCHGATE_SWITCH_UP,
2920 EL_DC_SWITCHGATE_SWITCH_DOWN,
2923 EL_TIMEGATE_OPENING,
2925 EL_TIMEGATE_CLOSING,
2927 EL_DC_TIMEGATE_SWITCH,
2928 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2933 EL_TUBE_VERTICAL_LEFT,
2934 EL_TUBE_VERTICAL_RIGHT,
2935 EL_TUBE_HORIZONTAL_UP,
2936 EL_TUBE_HORIZONTAL_DOWN,
2941 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2942 EL_EXPANDABLE_STEELWALL_VERTICAL,
2943 EL_EXPANDABLE_STEELWALL_ANY,
2948 static int ep_slippery[] =
2962 EL_ROBOT_WHEEL_ACTIVE,
2968 EL_ACID_POOL_TOPLEFT,
2969 EL_ACID_POOL_TOPRIGHT,
2979 EL_STEELWALL_SLIPPERY,
2982 EL_EMC_WALL_SLIPPERY_1,
2983 EL_EMC_WALL_SLIPPERY_2,
2984 EL_EMC_WALL_SLIPPERY_3,
2985 EL_EMC_WALL_SLIPPERY_4,
2987 EL_EMC_MAGIC_BALL_ACTIVE,
2992 static int ep_can_change[] =
2997 static int ep_can_move[] =
2999 /* same elements as in 'pb_can_move_into_acid' */
3022 static int ep_can_fall[] =
3036 EL_QUICKSAND_FAST_FULL,
3038 EL_BD_MAGIC_WALL_FULL,
3039 EL_DC_MAGIC_WALL_FULL,
3053 static int ep_can_smash_player[] =
3079 static int ep_can_smash_enemies[] =
3088 static int ep_can_smash_everything[] =
3097 static int ep_explodes_by_fire[] =
3099 /* same elements as in 'ep_explodes_impact' */
3104 /* same elements as in 'ep_explodes_smashed' */
3114 EL_EM_DYNAMITE_ACTIVE,
3115 EL_DYNABOMB_PLAYER_1_ACTIVE,
3116 EL_DYNABOMB_PLAYER_2_ACTIVE,
3117 EL_DYNABOMB_PLAYER_3_ACTIVE,
3118 EL_DYNABOMB_PLAYER_4_ACTIVE,
3119 EL_DYNABOMB_INCREASE_NUMBER,
3120 EL_DYNABOMB_INCREASE_SIZE,
3121 EL_DYNABOMB_INCREASE_POWER,
3122 EL_SP_DISK_RED_ACTIVE,
3136 static int ep_explodes_smashed[] =
3138 /* same elements as in 'ep_explodes_impact' */
3152 static int ep_explodes_impact[] =
3161 static int ep_walkable_over[] =
3165 EL_SOKOBAN_FIELD_EMPTY,
3174 EL_EM_STEEL_EXIT_OPEN,
3176 EL_EM_STEEL_EXIT_OPENING,
3186 EL_GATE_1_GRAY_ACTIVE,
3187 EL_GATE_2_GRAY_ACTIVE,
3188 EL_GATE_3_GRAY_ACTIVE,
3189 EL_GATE_4_GRAY_ACTIVE,
3197 static int ep_walkable_inside[] =
3202 EL_TUBE_VERTICAL_LEFT,
3203 EL_TUBE_VERTICAL_RIGHT,
3204 EL_TUBE_HORIZONTAL_UP,
3205 EL_TUBE_HORIZONTAL_DOWN,
3214 static int ep_walkable_under[] =
3219 static int ep_passable_over[] =
3229 EL_EM_GATE_1_GRAY_ACTIVE,
3230 EL_EM_GATE_2_GRAY_ACTIVE,
3231 EL_EM_GATE_3_GRAY_ACTIVE,
3232 EL_EM_GATE_4_GRAY_ACTIVE,
3241 EL_EMC_GATE_5_GRAY_ACTIVE,
3242 EL_EMC_GATE_6_GRAY_ACTIVE,
3243 EL_EMC_GATE_7_GRAY_ACTIVE,
3244 EL_EMC_GATE_8_GRAY_ACTIVE,
3246 EL_DC_GATE_WHITE_GRAY,
3247 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3254 static int ep_passable_inside[] =
3260 EL_SP_PORT_HORIZONTAL,
3261 EL_SP_PORT_VERTICAL,
3263 EL_SP_GRAVITY_PORT_LEFT,
3264 EL_SP_GRAVITY_PORT_RIGHT,
3265 EL_SP_GRAVITY_PORT_UP,
3266 EL_SP_GRAVITY_PORT_DOWN,
3267 EL_SP_GRAVITY_ON_PORT_LEFT,
3268 EL_SP_GRAVITY_ON_PORT_RIGHT,
3269 EL_SP_GRAVITY_ON_PORT_UP,
3270 EL_SP_GRAVITY_ON_PORT_DOWN,
3271 EL_SP_GRAVITY_OFF_PORT_LEFT,
3272 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3273 EL_SP_GRAVITY_OFF_PORT_UP,
3274 EL_SP_GRAVITY_OFF_PORT_DOWN,
3279 static int ep_passable_under[] =
3284 static int ep_droppable[] =
3289 static int ep_explodes_1x1_old[] =
3294 static int ep_pushable[] =
3306 EL_SOKOBAN_FIELD_FULL,
3315 static int ep_explodes_cross_old[] =
3320 static int ep_protected[] =
3322 /* same elements as in 'ep_walkable_inside' */
3326 EL_TUBE_VERTICAL_LEFT,
3327 EL_TUBE_VERTICAL_RIGHT,
3328 EL_TUBE_HORIZONTAL_UP,
3329 EL_TUBE_HORIZONTAL_DOWN,
3335 /* same elements as in 'ep_passable_over' */
3344 EL_EM_GATE_1_GRAY_ACTIVE,
3345 EL_EM_GATE_2_GRAY_ACTIVE,
3346 EL_EM_GATE_3_GRAY_ACTIVE,
3347 EL_EM_GATE_4_GRAY_ACTIVE,
3356 EL_EMC_GATE_5_GRAY_ACTIVE,
3357 EL_EMC_GATE_6_GRAY_ACTIVE,
3358 EL_EMC_GATE_7_GRAY_ACTIVE,
3359 EL_EMC_GATE_8_GRAY_ACTIVE,
3361 EL_DC_GATE_WHITE_GRAY,
3362 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3366 /* same elements as in 'ep_passable_inside' */
3371 EL_SP_PORT_HORIZONTAL,
3372 EL_SP_PORT_VERTICAL,
3374 EL_SP_GRAVITY_PORT_LEFT,
3375 EL_SP_GRAVITY_PORT_RIGHT,
3376 EL_SP_GRAVITY_PORT_UP,
3377 EL_SP_GRAVITY_PORT_DOWN,
3378 EL_SP_GRAVITY_ON_PORT_LEFT,
3379 EL_SP_GRAVITY_ON_PORT_RIGHT,
3380 EL_SP_GRAVITY_ON_PORT_UP,
3381 EL_SP_GRAVITY_ON_PORT_DOWN,
3382 EL_SP_GRAVITY_OFF_PORT_LEFT,
3383 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3384 EL_SP_GRAVITY_OFF_PORT_UP,
3385 EL_SP_GRAVITY_OFF_PORT_DOWN,
3390 static int ep_throwable[] =
3395 static int ep_can_explode[] =
3397 /* same elements as in 'ep_explodes_impact' */
3402 /* same elements as in 'ep_explodes_smashed' */
3408 /* elements that can explode by explosion or by dragonfire */
3412 EL_EM_DYNAMITE_ACTIVE,
3413 EL_DYNABOMB_PLAYER_1_ACTIVE,
3414 EL_DYNABOMB_PLAYER_2_ACTIVE,
3415 EL_DYNABOMB_PLAYER_3_ACTIVE,
3416 EL_DYNABOMB_PLAYER_4_ACTIVE,
3417 EL_DYNABOMB_INCREASE_NUMBER,
3418 EL_DYNABOMB_INCREASE_SIZE,
3419 EL_DYNABOMB_INCREASE_POWER,
3420 EL_SP_DISK_RED_ACTIVE,
3428 /* elements that can explode only by explosion */
3434 static int ep_gravity_reachable[] =
3440 EL_INVISIBLE_SAND_ACTIVE,
3445 EL_SP_PORT_HORIZONTAL,
3446 EL_SP_PORT_VERTICAL,
3448 EL_SP_GRAVITY_PORT_LEFT,
3449 EL_SP_GRAVITY_PORT_RIGHT,
3450 EL_SP_GRAVITY_PORT_UP,
3451 EL_SP_GRAVITY_PORT_DOWN,
3452 EL_SP_GRAVITY_ON_PORT_LEFT,
3453 EL_SP_GRAVITY_ON_PORT_RIGHT,
3454 EL_SP_GRAVITY_ON_PORT_UP,
3455 EL_SP_GRAVITY_ON_PORT_DOWN,
3456 EL_SP_GRAVITY_OFF_PORT_LEFT,
3457 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3458 EL_SP_GRAVITY_OFF_PORT_UP,
3459 EL_SP_GRAVITY_OFF_PORT_DOWN,
3465 static int ep_player[] =
3472 EL_SOKOBAN_FIELD_PLAYER,
3478 static int ep_can_pass_magic_wall[] =
3492 static int ep_can_pass_dc_magic_wall[] =
3508 static int ep_switchable[] =
3512 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3513 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3514 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3515 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3516 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3517 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3518 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3519 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3520 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3521 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3522 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3523 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3524 EL_SWITCHGATE_SWITCH_UP,
3525 EL_SWITCHGATE_SWITCH_DOWN,
3526 EL_DC_SWITCHGATE_SWITCH_UP,
3527 EL_DC_SWITCHGATE_SWITCH_DOWN,
3529 EL_LIGHT_SWITCH_ACTIVE,
3531 EL_DC_TIMEGATE_SWITCH,
3532 EL_BALLOON_SWITCH_LEFT,
3533 EL_BALLOON_SWITCH_RIGHT,
3534 EL_BALLOON_SWITCH_UP,
3535 EL_BALLOON_SWITCH_DOWN,
3536 EL_BALLOON_SWITCH_ANY,
3537 EL_BALLOON_SWITCH_NONE,
3540 EL_EMC_MAGIC_BALL_SWITCH,
3541 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3546 static int ep_bd_element[] =
3580 static int ep_sp_element[] =
3582 /* should always be valid */
3585 /* standard classic Supaplex elements */
3592 EL_SP_HARDWARE_GRAY,
3600 EL_SP_GRAVITY_PORT_RIGHT,
3601 EL_SP_GRAVITY_PORT_DOWN,
3602 EL_SP_GRAVITY_PORT_LEFT,
3603 EL_SP_GRAVITY_PORT_UP,
3608 EL_SP_PORT_VERTICAL,
3609 EL_SP_PORT_HORIZONTAL,
3615 EL_SP_HARDWARE_BASE_1,
3616 EL_SP_HARDWARE_GREEN,
3617 EL_SP_HARDWARE_BLUE,
3619 EL_SP_HARDWARE_YELLOW,
3620 EL_SP_HARDWARE_BASE_2,
3621 EL_SP_HARDWARE_BASE_3,
3622 EL_SP_HARDWARE_BASE_4,
3623 EL_SP_HARDWARE_BASE_5,
3624 EL_SP_HARDWARE_BASE_6,
3628 /* additional elements that appeared in newer Supaplex levels */
3631 /* additional gravity port elements (not switching, but setting gravity) */
3632 EL_SP_GRAVITY_ON_PORT_LEFT,
3633 EL_SP_GRAVITY_ON_PORT_RIGHT,
3634 EL_SP_GRAVITY_ON_PORT_UP,
3635 EL_SP_GRAVITY_ON_PORT_DOWN,
3636 EL_SP_GRAVITY_OFF_PORT_LEFT,
3637 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3638 EL_SP_GRAVITY_OFF_PORT_UP,
3639 EL_SP_GRAVITY_OFF_PORT_DOWN,
3641 /* more than one Murphy in a level results in an inactive clone */
3644 /* runtime Supaplex elements */
3645 EL_SP_DISK_RED_ACTIVE,
3646 EL_SP_TERMINAL_ACTIVE,
3647 EL_SP_BUGGY_BASE_ACTIVATING,
3648 EL_SP_BUGGY_BASE_ACTIVE,
3655 static int ep_sb_element[] =
3660 EL_SOKOBAN_FIELD_EMPTY,
3661 EL_SOKOBAN_FIELD_FULL,
3662 EL_SOKOBAN_FIELD_PLAYER,
3667 EL_INVISIBLE_STEELWALL,
3672 static int ep_gem[] =
3684 static int ep_food_dark_yamyam[] =
3712 static int ep_food_penguin[] =
3726 static int ep_food_pig[] =
3738 static int ep_historic_wall[] =
3749 EL_GATE_1_GRAY_ACTIVE,
3750 EL_GATE_2_GRAY_ACTIVE,
3751 EL_GATE_3_GRAY_ACTIVE,
3752 EL_GATE_4_GRAY_ACTIVE,
3761 EL_EM_GATE_1_GRAY_ACTIVE,
3762 EL_EM_GATE_2_GRAY_ACTIVE,
3763 EL_EM_GATE_3_GRAY_ACTIVE,
3764 EL_EM_GATE_4_GRAY_ACTIVE,
3771 EL_EXPANDABLE_WALL_HORIZONTAL,
3772 EL_EXPANDABLE_WALL_VERTICAL,
3773 EL_EXPANDABLE_WALL_ANY,
3774 EL_EXPANDABLE_WALL_GROWING,
3775 EL_BD_EXPANDABLE_WALL,
3782 EL_SP_HARDWARE_GRAY,
3783 EL_SP_HARDWARE_GREEN,
3784 EL_SP_HARDWARE_BLUE,
3786 EL_SP_HARDWARE_YELLOW,
3787 EL_SP_HARDWARE_BASE_1,
3788 EL_SP_HARDWARE_BASE_2,
3789 EL_SP_HARDWARE_BASE_3,
3790 EL_SP_HARDWARE_BASE_4,
3791 EL_SP_HARDWARE_BASE_5,
3792 EL_SP_HARDWARE_BASE_6,
3794 EL_SP_TERMINAL_ACTIVE,
3797 EL_INVISIBLE_STEELWALL,
3798 EL_INVISIBLE_STEELWALL_ACTIVE,
3800 EL_INVISIBLE_WALL_ACTIVE,
3801 EL_STEELWALL_SLIPPERY,
3818 static int ep_historic_solid[] =
3822 EL_EXPANDABLE_WALL_HORIZONTAL,
3823 EL_EXPANDABLE_WALL_VERTICAL,
3824 EL_EXPANDABLE_WALL_ANY,
3825 EL_BD_EXPANDABLE_WALL,
3838 EL_QUICKSAND_FILLING,
3839 EL_QUICKSAND_EMPTYING,
3841 EL_MAGIC_WALL_ACTIVE,
3842 EL_MAGIC_WALL_EMPTYING,
3843 EL_MAGIC_WALL_FILLING,
3847 EL_BD_MAGIC_WALL_ACTIVE,
3848 EL_BD_MAGIC_WALL_EMPTYING,
3849 EL_BD_MAGIC_WALL_FULL,
3850 EL_BD_MAGIC_WALL_FILLING,
3851 EL_BD_MAGIC_WALL_DEAD,
3860 EL_SP_TERMINAL_ACTIVE,
3864 EL_INVISIBLE_WALL_ACTIVE,
3865 EL_SWITCHGATE_SWITCH_UP,
3866 EL_SWITCHGATE_SWITCH_DOWN,
3867 EL_DC_SWITCHGATE_SWITCH_UP,
3868 EL_DC_SWITCHGATE_SWITCH_DOWN,
3870 EL_TIMEGATE_SWITCH_ACTIVE,
3871 EL_DC_TIMEGATE_SWITCH,
3872 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3884 /* the following elements are a direct copy of "indestructible" elements,
3885 except "EL_ACID", which is "indestructible", but not "solid"! */
3890 EL_ACID_POOL_TOPLEFT,
3891 EL_ACID_POOL_TOPRIGHT,
3892 EL_ACID_POOL_BOTTOMLEFT,
3893 EL_ACID_POOL_BOTTOM,
3894 EL_ACID_POOL_BOTTOMRIGHT,
3895 EL_SP_HARDWARE_GRAY,
3896 EL_SP_HARDWARE_GREEN,
3897 EL_SP_HARDWARE_BLUE,
3899 EL_SP_HARDWARE_YELLOW,
3900 EL_SP_HARDWARE_BASE_1,
3901 EL_SP_HARDWARE_BASE_2,
3902 EL_SP_HARDWARE_BASE_3,
3903 EL_SP_HARDWARE_BASE_4,
3904 EL_SP_HARDWARE_BASE_5,
3905 EL_SP_HARDWARE_BASE_6,
3906 EL_INVISIBLE_STEELWALL,
3907 EL_INVISIBLE_STEELWALL_ACTIVE,
3908 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3909 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3910 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3911 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3912 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3913 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3914 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3915 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3916 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3917 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3918 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3919 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3921 EL_LIGHT_SWITCH_ACTIVE,
3922 EL_SIGN_EXCLAMATION,
3923 EL_SIGN_RADIOACTIVITY,
3930 EL_SIGN_ENTRY_FORBIDDEN,
3931 EL_SIGN_EMERGENCY_EXIT,
3939 EL_STEEL_EXIT_CLOSED,
3941 EL_DC_STEELWALL_1_LEFT,
3942 EL_DC_STEELWALL_1_RIGHT,
3943 EL_DC_STEELWALL_1_TOP,
3944 EL_DC_STEELWALL_1_BOTTOM,
3945 EL_DC_STEELWALL_1_HORIZONTAL,
3946 EL_DC_STEELWALL_1_VERTICAL,
3947 EL_DC_STEELWALL_1_TOPLEFT,
3948 EL_DC_STEELWALL_1_TOPRIGHT,
3949 EL_DC_STEELWALL_1_BOTTOMLEFT,
3950 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3951 EL_DC_STEELWALL_1_TOPLEFT_2,
3952 EL_DC_STEELWALL_1_TOPRIGHT_2,
3953 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3954 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3955 EL_DC_STEELWALL_2_LEFT,
3956 EL_DC_STEELWALL_2_RIGHT,
3957 EL_DC_STEELWALL_2_TOP,
3958 EL_DC_STEELWALL_2_BOTTOM,
3959 EL_DC_STEELWALL_2_HORIZONTAL,
3960 EL_DC_STEELWALL_2_VERTICAL,
3961 EL_DC_STEELWALL_2_MIDDLE,
3962 EL_DC_STEELWALL_2_SINGLE,
3963 EL_STEELWALL_SLIPPERY,
3977 EL_GATE_1_GRAY_ACTIVE,
3978 EL_GATE_2_GRAY_ACTIVE,
3979 EL_GATE_3_GRAY_ACTIVE,
3980 EL_GATE_4_GRAY_ACTIVE,
3989 EL_EM_GATE_1_GRAY_ACTIVE,
3990 EL_EM_GATE_2_GRAY_ACTIVE,
3991 EL_EM_GATE_3_GRAY_ACTIVE,
3992 EL_EM_GATE_4_GRAY_ACTIVE,
3994 EL_SWITCHGATE_OPENING,
3995 EL_SWITCHGATE_CLOSED,
3996 EL_SWITCHGATE_CLOSING,
3998 EL_TIMEGATE_OPENING,
4000 EL_TIMEGATE_CLOSING,
4004 EL_TUBE_VERTICAL_LEFT,
4005 EL_TUBE_VERTICAL_RIGHT,
4006 EL_TUBE_HORIZONTAL_UP,
4007 EL_TUBE_HORIZONTAL_DOWN,
4016 static int ep_classic_enemy[] =
4033 static int ep_belt[] =
4035 EL_CONVEYOR_BELT_1_LEFT,
4036 EL_CONVEYOR_BELT_1_MIDDLE,
4037 EL_CONVEYOR_BELT_1_RIGHT,
4038 EL_CONVEYOR_BELT_2_LEFT,
4039 EL_CONVEYOR_BELT_2_MIDDLE,
4040 EL_CONVEYOR_BELT_2_RIGHT,
4041 EL_CONVEYOR_BELT_3_LEFT,
4042 EL_CONVEYOR_BELT_3_MIDDLE,
4043 EL_CONVEYOR_BELT_3_RIGHT,
4044 EL_CONVEYOR_BELT_4_LEFT,
4045 EL_CONVEYOR_BELT_4_MIDDLE,
4046 EL_CONVEYOR_BELT_4_RIGHT,
4051 static int ep_belt_active[] =
4053 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
4054 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
4055 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
4056 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
4057 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
4058 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
4059 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
4060 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
4061 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
4062 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
4063 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
4064 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
4069 static int ep_belt_switch[] =
4071 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4072 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4073 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4074 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4075 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4076 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4077 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4078 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4079 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4080 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4081 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4082 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4087 static int ep_tube[] =
4094 EL_TUBE_HORIZONTAL_UP,
4095 EL_TUBE_HORIZONTAL_DOWN,
4097 EL_TUBE_VERTICAL_LEFT,
4098 EL_TUBE_VERTICAL_RIGHT,
4104 static int ep_acid_pool[] =
4106 EL_ACID_POOL_TOPLEFT,
4107 EL_ACID_POOL_TOPRIGHT,
4108 EL_ACID_POOL_BOTTOMLEFT,
4109 EL_ACID_POOL_BOTTOM,
4110 EL_ACID_POOL_BOTTOMRIGHT,
4115 static int ep_keygate[] =
4125 EL_GATE_1_GRAY_ACTIVE,
4126 EL_GATE_2_GRAY_ACTIVE,
4127 EL_GATE_3_GRAY_ACTIVE,
4128 EL_GATE_4_GRAY_ACTIVE,
4137 EL_EM_GATE_1_GRAY_ACTIVE,
4138 EL_EM_GATE_2_GRAY_ACTIVE,
4139 EL_EM_GATE_3_GRAY_ACTIVE,
4140 EL_EM_GATE_4_GRAY_ACTIVE,
4149 EL_EMC_GATE_5_GRAY_ACTIVE,
4150 EL_EMC_GATE_6_GRAY_ACTIVE,
4151 EL_EMC_GATE_7_GRAY_ACTIVE,
4152 EL_EMC_GATE_8_GRAY_ACTIVE,
4154 EL_DC_GATE_WHITE_GRAY,
4155 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4160 static int ep_amoeboid[] =
4172 static int ep_amoebalive[] =
4183 static int ep_has_editor_content[] =
4189 EL_SOKOBAN_FIELD_PLAYER,
4206 static int ep_can_turn_each_move[] =
4208 /* !!! do something with this one !!! */
4212 static int ep_can_grow[] =
4226 static int ep_active_bomb[] =
4229 EL_EM_DYNAMITE_ACTIVE,
4230 EL_DYNABOMB_PLAYER_1_ACTIVE,
4231 EL_DYNABOMB_PLAYER_2_ACTIVE,
4232 EL_DYNABOMB_PLAYER_3_ACTIVE,
4233 EL_DYNABOMB_PLAYER_4_ACTIVE,
4234 EL_SP_DISK_RED_ACTIVE,
4239 static int ep_inactive[] =
4249 EL_QUICKSAND_FAST_EMPTY,
4272 EL_GATE_1_GRAY_ACTIVE,
4273 EL_GATE_2_GRAY_ACTIVE,
4274 EL_GATE_3_GRAY_ACTIVE,
4275 EL_GATE_4_GRAY_ACTIVE,
4284 EL_EM_GATE_1_GRAY_ACTIVE,
4285 EL_EM_GATE_2_GRAY_ACTIVE,
4286 EL_EM_GATE_3_GRAY_ACTIVE,
4287 EL_EM_GATE_4_GRAY_ACTIVE,
4296 EL_EMC_GATE_5_GRAY_ACTIVE,
4297 EL_EMC_GATE_6_GRAY_ACTIVE,
4298 EL_EMC_GATE_7_GRAY_ACTIVE,
4299 EL_EMC_GATE_8_GRAY_ACTIVE,
4301 EL_DC_GATE_WHITE_GRAY,
4302 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4303 EL_DC_GATE_FAKE_GRAY,
4306 EL_INVISIBLE_STEELWALL,
4314 EL_WALL_EMERALD_YELLOW,
4315 EL_DYNABOMB_INCREASE_NUMBER,
4316 EL_DYNABOMB_INCREASE_SIZE,
4317 EL_DYNABOMB_INCREASE_POWER,
4321 EL_SOKOBAN_FIELD_EMPTY,
4322 EL_SOKOBAN_FIELD_FULL,
4323 EL_WALL_EMERALD_RED,
4324 EL_WALL_EMERALD_PURPLE,
4325 EL_ACID_POOL_TOPLEFT,
4326 EL_ACID_POOL_TOPRIGHT,
4327 EL_ACID_POOL_BOTTOMLEFT,
4328 EL_ACID_POOL_BOTTOM,
4329 EL_ACID_POOL_BOTTOMRIGHT,
4333 EL_BD_MAGIC_WALL_DEAD,
4335 EL_DC_MAGIC_WALL_DEAD,
4336 EL_AMOEBA_TO_DIAMOND,
4344 EL_SP_GRAVITY_PORT_RIGHT,
4345 EL_SP_GRAVITY_PORT_DOWN,
4346 EL_SP_GRAVITY_PORT_LEFT,
4347 EL_SP_GRAVITY_PORT_UP,
4348 EL_SP_PORT_HORIZONTAL,
4349 EL_SP_PORT_VERTICAL,
4360 EL_SP_HARDWARE_GRAY,
4361 EL_SP_HARDWARE_GREEN,
4362 EL_SP_HARDWARE_BLUE,
4364 EL_SP_HARDWARE_YELLOW,
4365 EL_SP_HARDWARE_BASE_1,
4366 EL_SP_HARDWARE_BASE_2,
4367 EL_SP_HARDWARE_BASE_3,
4368 EL_SP_HARDWARE_BASE_4,
4369 EL_SP_HARDWARE_BASE_5,
4370 EL_SP_HARDWARE_BASE_6,
4371 EL_SP_GRAVITY_ON_PORT_LEFT,
4372 EL_SP_GRAVITY_ON_PORT_RIGHT,
4373 EL_SP_GRAVITY_ON_PORT_UP,
4374 EL_SP_GRAVITY_ON_PORT_DOWN,
4375 EL_SP_GRAVITY_OFF_PORT_LEFT,
4376 EL_SP_GRAVITY_OFF_PORT_RIGHT,
4377 EL_SP_GRAVITY_OFF_PORT_UP,
4378 EL_SP_GRAVITY_OFF_PORT_DOWN,
4379 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4380 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4381 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4382 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4383 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4384 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4385 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4386 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4387 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4388 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4389 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4390 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4391 EL_SIGN_EXCLAMATION,
4392 EL_SIGN_RADIOACTIVITY,
4399 EL_SIGN_ENTRY_FORBIDDEN,
4400 EL_SIGN_EMERGENCY_EXIT,
4408 EL_DC_STEELWALL_1_LEFT,
4409 EL_DC_STEELWALL_1_RIGHT,
4410 EL_DC_STEELWALL_1_TOP,
4411 EL_DC_STEELWALL_1_BOTTOM,
4412 EL_DC_STEELWALL_1_HORIZONTAL,
4413 EL_DC_STEELWALL_1_VERTICAL,
4414 EL_DC_STEELWALL_1_TOPLEFT,
4415 EL_DC_STEELWALL_1_TOPRIGHT,
4416 EL_DC_STEELWALL_1_BOTTOMLEFT,
4417 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4418 EL_DC_STEELWALL_1_TOPLEFT_2,
4419 EL_DC_STEELWALL_1_TOPRIGHT_2,
4420 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4421 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4422 EL_DC_STEELWALL_2_LEFT,
4423 EL_DC_STEELWALL_2_RIGHT,
4424 EL_DC_STEELWALL_2_TOP,
4425 EL_DC_STEELWALL_2_BOTTOM,
4426 EL_DC_STEELWALL_2_HORIZONTAL,
4427 EL_DC_STEELWALL_2_VERTICAL,
4428 EL_DC_STEELWALL_2_MIDDLE,
4429 EL_DC_STEELWALL_2_SINGLE,
4430 EL_STEELWALL_SLIPPERY,
4435 EL_EMC_WALL_SLIPPERY_1,
4436 EL_EMC_WALL_SLIPPERY_2,
4437 EL_EMC_WALL_SLIPPERY_3,
4438 EL_EMC_WALL_SLIPPERY_4,
4459 static int ep_em_slippery_wall[] =
4464 static int ep_gfx_crumbled[] =
4475 static int ep_editor_cascade_active[] =
4477 EL_INTERNAL_CASCADE_BD_ACTIVE,
4478 EL_INTERNAL_CASCADE_EM_ACTIVE,
4479 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4480 EL_INTERNAL_CASCADE_RND_ACTIVE,
4481 EL_INTERNAL_CASCADE_SB_ACTIVE,
4482 EL_INTERNAL_CASCADE_SP_ACTIVE,
4483 EL_INTERNAL_CASCADE_DC_ACTIVE,
4484 EL_INTERNAL_CASCADE_DX_ACTIVE,
4485 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4486 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4487 EL_INTERNAL_CASCADE_CE_ACTIVE,
4488 EL_INTERNAL_CASCADE_GE_ACTIVE,
4489 EL_INTERNAL_CASCADE_REF_ACTIVE,
4490 EL_INTERNAL_CASCADE_USER_ACTIVE,
4491 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4496 static int ep_editor_cascade_inactive[] =
4498 EL_INTERNAL_CASCADE_BD,
4499 EL_INTERNAL_CASCADE_EM,
4500 EL_INTERNAL_CASCADE_EMC,
4501 EL_INTERNAL_CASCADE_RND,
4502 EL_INTERNAL_CASCADE_SB,
4503 EL_INTERNAL_CASCADE_SP,
4504 EL_INTERNAL_CASCADE_DC,
4505 EL_INTERNAL_CASCADE_DX,
4506 EL_INTERNAL_CASCADE_CHARS,
4507 EL_INTERNAL_CASCADE_STEEL_CHARS,
4508 EL_INTERNAL_CASCADE_CE,
4509 EL_INTERNAL_CASCADE_GE,
4510 EL_INTERNAL_CASCADE_REF,
4511 EL_INTERNAL_CASCADE_USER,
4512 EL_INTERNAL_CASCADE_DYNAMIC,
4517 static int ep_obsolete[] =
4521 EL_EM_KEY_1_FILE_OBSOLETE,
4522 EL_EM_KEY_2_FILE_OBSOLETE,
4523 EL_EM_KEY_3_FILE_OBSOLETE,
4524 EL_EM_KEY_4_FILE_OBSOLETE,
4525 EL_ENVELOPE_OBSOLETE,
4534 } element_properties[] =
4536 { ep_diggable, EP_DIGGABLE },
4537 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4538 { ep_dont_run_into, EP_DONT_RUN_INTO },
4539 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4540 { ep_dont_touch, EP_DONT_TOUCH },
4541 { ep_indestructible, EP_INDESTRUCTIBLE },
4542 { ep_slippery, EP_SLIPPERY },
4543 { ep_can_change, EP_CAN_CHANGE },
4544 { ep_can_move, EP_CAN_MOVE },
4545 { ep_can_fall, EP_CAN_FALL },
4546 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4547 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4548 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4549 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4550 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4551 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4552 { ep_walkable_over, EP_WALKABLE_OVER },
4553 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4554 { ep_walkable_under, EP_WALKABLE_UNDER },
4555 { ep_passable_over, EP_PASSABLE_OVER },
4556 { ep_passable_inside, EP_PASSABLE_INSIDE },
4557 { ep_passable_under, EP_PASSABLE_UNDER },
4558 { ep_droppable, EP_DROPPABLE },
4559 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4560 { ep_pushable, EP_PUSHABLE },
4561 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4562 { ep_protected, EP_PROTECTED },
4563 { ep_throwable, EP_THROWABLE },
4564 { ep_can_explode, EP_CAN_EXPLODE },
4565 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4567 { ep_player, EP_PLAYER },
4568 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4569 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4570 { ep_switchable, EP_SWITCHABLE },
4571 { ep_bd_element, EP_BD_ELEMENT },
4572 { ep_sp_element, EP_SP_ELEMENT },
4573 { ep_sb_element, EP_SB_ELEMENT },
4575 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4576 { ep_food_penguin, EP_FOOD_PENGUIN },
4577 { ep_food_pig, EP_FOOD_PIG },
4578 { ep_historic_wall, EP_HISTORIC_WALL },
4579 { ep_historic_solid, EP_HISTORIC_SOLID },
4580 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4581 { ep_belt, EP_BELT },
4582 { ep_belt_active, EP_BELT_ACTIVE },
4583 { ep_belt_switch, EP_BELT_SWITCH },
4584 { ep_tube, EP_TUBE },
4585 { ep_acid_pool, EP_ACID_POOL },
4586 { ep_keygate, EP_KEYGATE },
4587 { ep_amoeboid, EP_AMOEBOID },
4588 { ep_amoebalive, EP_AMOEBALIVE },
4589 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4590 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4591 { ep_can_grow, EP_CAN_GROW },
4592 { ep_active_bomb, EP_ACTIVE_BOMB },
4593 { ep_inactive, EP_INACTIVE },
4595 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4597 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4599 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4600 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4602 { ep_obsolete, EP_OBSOLETE },
4609 /* always start with reliable default values (element has no properties) */
4610 /* (but never initialize clipboard elements after the very first time) */
4611 /* (to be able to use clipboard elements between several levels) */
4612 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4613 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4614 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4615 SET_PROPERTY(i, j, FALSE);
4617 /* set all base element properties from above array definitions */
4618 for (i = 0; element_properties[i].elements != NULL; i++)
4619 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4620 SET_PROPERTY((element_properties[i].elements)[j],
4621 element_properties[i].property, TRUE);
4623 /* copy properties to some elements that are only stored in level file */
4624 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4625 for (j = 0; copy_properties[j][0] != -1; j++)
4626 if (HAS_PROPERTY(copy_properties[j][0], i))
4627 for (k = 1; k <= 4; k++)
4628 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4630 /* set static element properties that are not listed in array definitions */
4631 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4632 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4634 clipboard_elements_initialized = TRUE;
4637 void InitElementPropertiesEngine(int engine_version)
4639 static int no_wall_properties[] =
4642 EP_COLLECTIBLE_ONLY,
4644 EP_DONT_COLLIDE_WITH,
4647 EP_CAN_SMASH_PLAYER,
4648 EP_CAN_SMASH_ENEMIES,
4649 EP_CAN_SMASH_EVERYTHING,
4654 EP_FOOD_DARK_YAMYAM,
4670 /* important: after initialization in InitElementPropertiesStatic(), the
4671 elements are not again initialized to a default value; therefore all
4672 changes have to make sure that they leave the element with a defined
4673 property (which means that conditional property changes must be set to
4674 a reliable default value before) */
4676 /* resolve group elements */
4677 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4678 ResolveGroupElement(EL_GROUP_START + i);
4680 /* set all special, combined or engine dependent element properties */
4681 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4683 /* do not change (already initialized) clipboard elements here */
4684 if (IS_CLIPBOARD_ELEMENT(i))
4687 /* ---------- INACTIVE ------------------------------------------------- */
4688 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4689 i <= EL_CHAR_END) ||
4690 (i >= EL_STEEL_CHAR_START &&
4691 i <= EL_STEEL_CHAR_END)));
4693 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4694 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4695 IS_WALKABLE_INSIDE(i) ||
4696 IS_WALKABLE_UNDER(i)));
4698 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4699 IS_PASSABLE_INSIDE(i) ||
4700 IS_PASSABLE_UNDER(i)));
4702 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4703 IS_PASSABLE_OVER(i)));
4705 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4706 IS_PASSABLE_INSIDE(i)));
4708 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4709 IS_PASSABLE_UNDER(i)));
4711 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4714 /* ---------- COLLECTIBLE ---------------------------------------------- */
4715 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4719 /* ---------- SNAPPABLE ------------------------------------------------ */
4720 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4721 IS_COLLECTIBLE(i) ||
4725 /* ---------- WALL ----------------------------------------------------- */
4726 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4728 for (j = 0; no_wall_properties[j] != -1; j++)
4729 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4730 i >= EL_FIRST_RUNTIME_UNREAL)
4731 SET_PROPERTY(i, EP_WALL, FALSE);
4733 if (IS_HISTORIC_WALL(i))
4734 SET_PROPERTY(i, EP_WALL, TRUE);
4736 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4737 if (engine_version < VERSION_IDENT(2,2,0,0))
4738 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4740 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4742 !IS_COLLECTIBLE(i)));
4744 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4745 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4746 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4748 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4749 IS_INDESTRUCTIBLE(i)));
4751 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4753 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4754 else if (engine_version < VERSION_IDENT(2,2,0,0))
4755 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4757 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4761 if (IS_CUSTOM_ELEMENT(i))
4763 /* these are additional properties which are initially false when set */
4765 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4767 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4768 if (DONT_COLLIDE_WITH(i))
4769 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4771 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4772 if (CAN_SMASH_EVERYTHING(i))
4773 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4774 if (CAN_SMASH_ENEMIES(i))
4775 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4778 /* ---------- CAN_SMASH ------------------------------------------------ */
4779 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4780 CAN_SMASH_ENEMIES(i) ||
4781 CAN_SMASH_EVERYTHING(i)));
4783 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4784 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4785 EXPLODES_BY_FIRE(i)));
4787 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4788 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4789 EXPLODES_SMASHED(i)));
4791 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4792 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4793 EXPLODES_IMPACT(i)));
4795 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4796 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4798 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4799 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4800 i == EL_BLACK_ORB));
4802 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4803 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4805 IS_CUSTOM_ELEMENT(i)));
4807 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4808 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4809 i == EL_SP_ELECTRON));
4811 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4812 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4813 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4814 getMoveIntoAcidProperty(&level, i));
4816 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4817 if (MAYBE_DONT_COLLIDE_WITH(i))
4818 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4819 getDontCollideWithProperty(&level, i));
4821 /* ---------- SP_PORT -------------------------------------------------- */
4822 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4823 IS_PASSABLE_INSIDE(i)));
4825 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4826 for (j = 0; j < level.num_android_clone_elements; j++)
4827 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4829 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4831 /* ---------- CAN_CHANGE ----------------------------------------------- */
4832 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4833 for (j = 0; j < element_info[i].num_change_pages; j++)
4834 if (element_info[i].change_page[j].can_change)
4835 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4837 /* ---------- HAS_ACTION ----------------------------------------------- */
4838 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4839 for (j = 0; j < element_info[i].num_change_pages; j++)
4840 if (element_info[i].change_page[j].has_action)
4841 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4843 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4844 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4847 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4849 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4850 element_info[i].crumbled[ACTION_DEFAULT] !=
4851 element_info[i].graphic[ACTION_DEFAULT]);
4853 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
4854 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4855 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
4858 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4859 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4860 IS_EDITOR_CASCADE_INACTIVE(i)));
4863 /* dynamically adjust element properties according to game engine version */
4865 static int ep_em_slippery_wall[] =
4870 EL_EXPANDABLE_WALL_HORIZONTAL,
4871 EL_EXPANDABLE_WALL_VERTICAL,
4872 EL_EXPANDABLE_WALL_ANY,
4873 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4874 EL_EXPANDABLE_STEELWALL_VERTICAL,
4875 EL_EXPANDABLE_STEELWALL_ANY,
4876 EL_EXPANDABLE_STEELWALL_GROWING,
4880 static int ep_em_explodes_by_fire[] =
4883 EL_EM_DYNAMITE_ACTIVE,
4888 /* special EM style gems behaviour */
4889 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4890 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4891 level.em_slippery_gems);
4893 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4894 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4895 (level.em_slippery_gems &&
4896 engine_version > VERSION_IDENT(2,0,1,0)));
4898 /* special EM style explosion behaviour regarding chain reactions */
4899 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4900 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4901 level.em_explodes_by_fire);
4904 /* this is needed because some graphics depend on element properties */
4905 if (game_status == GAME_MODE_PLAYING)
4906 InitElementGraphicInfo();
4909 void InitElementPropertiesAfterLoading(int engine_version)
4913 /* set some other uninitialized values of custom elements in older levels */
4914 if (engine_version < VERSION_IDENT(3,1,0,0))
4916 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4918 int element = EL_CUSTOM_START + i;
4920 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4922 element_info[element].explosion_delay = 17;
4923 element_info[element].ignition_delay = 8;
4928 void InitElementPropertiesGfxElement()
4932 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4934 struct ElementInfo *ei = &element_info[i];
4936 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4940 static void InitGlobal()
4945 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4947 /* check if element_name_info entry defined for each element in "main.h" */
4948 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4949 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4951 element_info[i].token_name = element_name_info[i].token_name;
4952 element_info[i].class_name = element_name_info[i].class_name;
4953 element_info[i].editor_description= element_name_info[i].editor_description;
4956 printf("%04d: %s\n", i, element_name_info[i].token_name);
4960 /* create hash from image config list */
4961 image_config_hash = newSetupFileHash();
4962 for (i = 0; image_config[i].token != NULL; i++)
4963 setHashEntry(image_config_hash,
4964 image_config[i].token,
4965 image_config[i].value);
4967 /* create hash from element token list */
4968 element_token_hash = newSetupFileHash();
4969 for (i = 0; element_name_info[i].token_name != NULL; i++)
4970 setHashEntry(element_token_hash,
4971 element_name_info[i].token_name,
4974 /* create hash from graphic token list */
4975 graphic_token_hash = newSetupFileHash();
4976 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4977 if (strSuffix(image_config[i].value, ".pcx") ||
4978 strSuffix(image_config[i].value, ".wav") ||
4979 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4980 setHashEntry(graphic_token_hash,
4981 image_config[i].token,
4982 int2str(graphic++, 0));
4984 /* create hash from font token list */
4985 font_token_hash = newSetupFileHash();
4986 for (i = 0; font_info[i].token_name != NULL; i++)
4987 setHashEntry(font_token_hash,
4988 font_info[i].token_name,
4991 /* always start with reliable default values (all elements) */
4992 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4993 ActiveElement[i] = i;
4995 /* now add all entries that have an active state (active elements) */
4996 for (i = 0; element_with_active_state[i].element != -1; i++)
4998 int element = element_with_active_state[i].element;
4999 int element_active = element_with_active_state[i].element_active;
5001 ActiveElement[element] = element_active;
5004 /* always start with reliable default values (all buttons) */
5005 for (i = 0; i < NUM_IMAGE_FILES; i++)
5006 ActiveButton[i] = i;
5008 /* now add all entries that have an active state (active buttons) */
5009 for (i = 0; button_with_active_state[i].button != -1; i++)
5011 int button = button_with_active_state[i].button;
5012 int button_active = button_with_active_state[i].button_active;
5014 ActiveButton[button] = button_active;
5017 /* always start with reliable default values (all fonts) */
5018 for (i = 0; i < NUM_FONTS; i++)
5021 /* now add all entries that have an active state (active fonts) */
5022 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
5024 int font = font_with_active_state[i].font_nr;
5025 int font_active = font_with_active_state[i].font_nr_active;
5027 ActiveFont[font] = font_active;
5030 global.autoplay_leveldir = NULL;
5031 global.convert_leveldir = NULL;
5032 global.create_images_dir = NULL;
5034 global.frames_per_second = 0;
5035 global.fps_slowdown = FALSE;
5036 global.fps_slowdown_factor = 1;
5038 global.border_status = GAME_MODE_MAIN;
5040 global.fading_status = GAME_MODE_MAIN;
5041 global.fading_type = TYPE_ENTER_MENU;
5045 void Execute_Command(char *command)
5049 if (strEqual(command, "print graphicsinfo.conf"))
5051 printf("# You can configure additional/alternative image files here.\n");
5052 printf("# (The entries below are default and therefore commented out.)\n");
5054 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
5056 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5059 for (i = 0; image_config[i].token != NULL; i++)
5060 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
5061 image_config[i].value));
5065 else if (strEqual(command, "print soundsinfo.conf"))
5067 printf("# You can configure additional/alternative sound files here.\n");
5068 printf("# (The entries below are default and therefore commented out.)\n");
5070 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
5072 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5075 for (i = 0; sound_config[i].token != NULL; i++)
5076 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
5077 sound_config[i].value));
5081 else if (strEqual(command, "print musicinfo.conf"))
5083 printf("# You can configure additional/alternative music files here.\n");
5084 printf("# (The entries below are default and therefore commented out.)\n");
5086 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
5088 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5091 for (i = 0; music_config[i].token != NULL; i++)
5092 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
5093 music_config[i].value));
5097 else if (strEqual(command, "print editorsetup.conf"))
5099 printf("# You can configure your personal editor element list here.\n");
5100 printf("# (The entries below are default and therefore commented out.)\n");
5103 /* this is needed to be able to check element list for cascade elements */
5104 InitElementPropertiesStatic();
5105 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5107 PrintEditorElementList();
5111 else if (strEqual(command, "print helpanim.conf"))
5113 printf("# You can configure different element help animations here.\n");
5114 printf("# (The entries below are default and therefore commented out.)\n");
5117 for (i = 0; helpanim_config[i].token != NULL; i++)
5119 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
5120 helpanim_config[i].value));
5122 if (strEqual(helpanim_config[i].token, "end"))
5128 else if (strEqual(command, "print helptext.conf"))
5130 printf("# You can configure different element help text here.\n");
5131 printf("# (The entries below are default and therefore commented out.)\n");
5134 for (i = 0; helptext_config[i].token != NULL; i++)
5135 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
5136 helptext_config[i].value));
5140 else if (strPrefix(command, "dump level "))
5142 char *filename = &command[11];
5144 if (!fileExists(filename))
5145 Error(ERR_EXIT, "cannot open file '%s'", filename);
5147 LoadLevelFromFilename(&level, filename);
5152 else if (strPrefix(command, "dump tape "))
5154 char *filename = &command[10];
5156 if (!fileExists(filename))
5157 Error(ERR_EXIT, "cannot open file '%s'", filename);
5159 LoadTapeFromFilename(filename);
5164 else if (strPrefix(command, "autoplay "))
5166 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
5168 while (*str_ptr != '\0') /* continue parsing string */
5170 /* cut leading whitespace from string, replace it by string terminator */
5171 while (*str_ptr == ' ' || *str_ptr == '\t')
5174 if (*str_ptr == '\0') /* end of string reached */
5177 if (global.autoplay_leveldir == NULL) /* read level set string */
5179 global.autoplay_leveldir = str_ptr;
5180 global.autoplay_all = TRUE; /* default: play all tapes */
5182 for (i = 0; i < MAX_TAPES_PER_SET; i++)
5183 global.autoplay_level[i] = FALSE;
5185 else /* read level number string */
5187 int level_nr = atoi(str_ptr); /* get level_nr value */
5189 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5190 global.autoplay_level[level_nr] = TRUE;
5192 global.autoplay_all = FALSE;
5195 /* advance string pointer to the next whitespace (or end of string) */
5196 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5200 else if (strPrefix(command, "convert "))
5202 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
5203 char *str_ptr = strchr(str_copy, ' ');
5205 global.convert_leveldir = str_copy;
5206 global.convert_level_nr = -1;
5208 if (str_ptr != NULL) /* level number follows */
5210 *str_ptr++ = '\0'; /* terminate leveldir string */
5211 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
5214 else if (strPrefix(command, "create images "))
5216 #if defined(TARGET_SDL)
5217 global.create_images_dir = getStringCopy(&command[14]);
5219 if (access(global.create_images_dir, W_OK) != 0)
5220 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
5221 global.create_images_dir);
5223 Error(ERR_EXIT, "command only available for SDL target");
5228 #if defined(TARGET_SDL)
5229 else if (strEqual(command, "SDL_ListModes"))
5234 SDL_Init(SDL_INIT_VIDEO);
5236 /* get available fullscreen/hardware modes */
5237 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
5239 /* check if there are any modes available */
5242 printf("No modes available!\n");
5247 /* check if our resolution is restricted */
5248 if (modes == (SDL_Rect **)-1)
5250 printf("All resolutions available.\n");
5254 printf("Available Modes:\n");
5256 for(i = 0; modes[i]; i++)
5257 printf(" %d x %d\n", modes[i]->w, modes[i]->h);
5267 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
5271 static void InitSetup()
5273 LoadSetup(); /* global setup info */
5275 /* set some options from setup file */
5277 if (setup.options.verbose)
5278 options.verbose = TRUE;
5281 static void InitGameInfo()
5283 game.restart_level = FALSE;
5286 static void InitPlayerInfo()
5290 /* choose default local player */
5291 local_player = &stored_player[0];
5293 for (i = 0; i < MAX_PLAYERS; i++)
5294 stored_player[i].connected = FALSE;
5296 local_player->connected = TRUE;
5299 static void InitArtworkInfo()
5304 static char *get_string_in_brackets(char *string)
5306 char *string_in_brackets = checked_malloc(strlen(string) + 3);
5308 sprintf(string_in_brackets, "[%s]", string);
5310 return string_in_brackets;
5313 static char *get_level_id_suffix(int id_nr)
5315 char *id_suffix = checked_malloc(1 + 3 + 1);
5317 if (id_nr < 0 || id_nr > 999)
5320 sprintf(id_suffix, ".%03d", id_nr);
5326 static char *get_element_class_token(int element)
5328 char *element_class_name = element_info[element].class_name;
5329 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
5331 sprintf(element_class_token, "[%s]", element_class_name);
5333 return element_class_token;
5336 static char *get_action_class_token(int action)
5338 char *action_class_name = &element_action_info[action].suffix[1];
5339 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
5341 sprintf(action_class_token, "[%s]", action_class_name);
5343 return action_class_token;
5347 static void InitArtworkConfig()
5349 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
5350 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
5351 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
5352 static char *action_id_suffix[NUM_ACTIONS + 1];
5353 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5354 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5355 static char *level_id_suffix[MAX_LEVELS + 1];
5356 static char *dummy[1] = { NULL };
5357 static char *ignore_generic_tokens[] =
5363 static char **ignore_image_tokens;
5364 static char **ignore_sound_tokens;
5365 static char **ignore_music_tokens;
5366 int num_ignore_generic_tokens;
5367 int num_ignore_image_tokens;
5368 int num_ignore_sound_tokens;
5369 int num_ignore_music_tokens;
5372 /* dynamically determine list of generic tokens to be ignored */
5373 num_ignore_generic_tokens = 0;
5374 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5375 num_ignore_generic_tokens++;
5377 /* dynamically determine list of image tokens to be ignored */
5378 num_ignore_image_tokens = num_ignore_generic_tokens;
5379 for (i = 0; image_config_vars[i].token != NULL; i++)
5380 num_ignore_image_tokens++;
5381 ignore_image_tokens =
5382 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5383 for (i = 0; i < num_ignore_generic_tokens; i++)
5384 ignore_image_tokens[i] = ignore_generic_tokens[i];
5385 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5386 ignore_image_tokens[num_ignore_generic_tokens + i] =
5387 image_config_vars[i].token;
5388 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5390 /* dynamically determine list of sound tokens to be ignored */
5391 num_ignore_sound_tokens = num_ignore_generic_tokens;
5392 ignore_sound_tokens =
5393 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5394 for (i = 0; i < num_ignore_generic_tokens; i++)
5395 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5396 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5398 /* dynamically determine list of music tokens to be ignored */
5399 num_ignore_music_tokens = num_ignore_generic_tokens;
5400 ignore_music_tokens =
5401 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5402 for (i = 0; i < num_ignore_generic_tokens; i++)
5403 ignore_music_tokens[i] = ignore_generic_tokens[i];
5404 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5406 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5407 image_id_prefix[i] = element_info[i].token_name;
5408 for (i = 0; i < NUM_FONTS; i++)
5409 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5410 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
5412 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5413 sound_id_prefix[i] = element_info[i].token_name;
5414 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5415 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5416 get_string_in_brackets(element_info[i].class_name);
5417 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
5419 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5420 music_id_prefix[i] = music_prefix_info[i].prefix;
5421 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
5423 for (i = 0; i < NUM_ACTIONS; i++)
5424 action_id_suffix[i] = element_action_info[i].suffix;
5425 action_id_suffix[NUM_ACTIONS] = NULL;
5427 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5428 direction_id_suffix[i] = element_direction_info[i].suffix;
5429 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5431 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5432 special_id_suffix[i] = special_suffix_info[i].suffix;
5433 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5435 for (i = 0; i < MAX_LEVELS; i++)
5436 level_id_suffix[i] = get_level_id_suffix(i);
5437 level_id_suffix[MAX_LEVELS] = NULL;
5439 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5440 image_id_prefix, action_id_suffix, direction_id_suffix,
5441 special_id_suffix, ignore_image_tokens);
5442 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5443 sound_id_prefix, action_id_suffix, dummy,
5444 special_id_suffix, ignore_sound_tokens);
5445 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5446 music_id_prefix, special_id_suffix, level_id_suffix,
5447 dummy, ignore_music_tokens);
5450 static void InitMixer()
5459 struct GraphicInfo *graphic_info_last = graphic_info;
5460 char *filename_font_initial = NULL;
5461 char *filename_anim_initial = NULL;
5462 Bitmap *bitmap_font_initial = NULL;
5466 /* determine settings for initial font (for displaying startup messages) */
5467 for (i = 0; image_config[i].token != NULL; i++)
5469 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5471 char font_token[128];
5474 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5475 len_font_token = strlen(font_token);
5477 if (strEqual(image_config[i].token, font_token))
5478 filename_font_initial = image_config[i].value;
5479 else if (strlen(image_config[i].token) > len_font_token &&
5480 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5482 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5483 font_initial[j].src_x = atoi(image_config[i].value);
5484 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5485 font_initial[j].src_y = atoi(image_config[i].value);
5486 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5487 font_initial[j].width = atoi(image_config[i].value);
5488 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5489 font_initial[j].height = atoi(image_config[i].value);
5494 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5496 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5497 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5500 if (filename_font_initial == NULL) /* should not happen */
5501 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5503 /* create additional image buffers for double-buffering and cross-fading */
5504 bitmap_db_cross = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5505 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
5506 bitmap_db_panel = CreateBitmap(DXSIZE, DYSIZE, DEFAULT_DEPTH);
5507 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
5508 bitmap_db_toons = CreateBitmap(FULL_SXSIZE, FULL_SYSIZE, DEFAULT_DEPTH);
5510 /* initialize screen properties */
5511 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5512 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5514 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5515 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5516 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5517 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5518 InitGfxCustomArtworkInfo();
5520 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5522 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5523 font_initial[j].bitmap = bitmap_font_initial;
5525 InitFontGraphicInfo();
5527 font_height = getFontHeight(FC_RED);
5530 DrawInitText(getWindowTitleString(), 20, FC_YELLOW);
5532 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
5534 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
5535 DrawInitText(PROGRAM_WEBSITE_STRING, WIN_YSIZE - 20 - font_height, FC_RED);
5537 DrawInitText("Loading graphics", 120, FC_GREEN);
5541 /* initialize busy animation with default values */
5542 int parameter[NUM_GFX_ARGS];
5543 for (i = 0; i < NUM_GFX_ARGS; i++)
5544 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5545 image_config_suffix[i].token,
5546 image_config_suffix[i].type);
5548 for (i = 0; i < NUM_GFX_ARGS; i++)
5549 printf("::: '%s' => %d\n", image_config_suffix[i].token, parameter[i]);
5553 /* determine settings for busy animation (when displaying startup messages) */
5554 for (i = 0; image_config[i].token != NULL; i++)
5556 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5557 int len_anim_token = strlen(anim_token);
5559 if (strEqual(image_config[i].token, anim_token))
5560 filename_anim_initial = image_config[i].value;
5561 else if (strlen(image_config[i].token) > len_anim_token &&
5562 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5565 for (j = 0; image_config_suffix[j].token != NULL; j++)
5567 if (strEqual(&image_config[i].token[len_anim_token],
5568 image_config_suffix[j].token))
5570 get_graphic_parameter_value(image_config[i].value,
5571 image_config_suffix[j].token,
5572 image_config_suffix[j].type);
5575 if (strEqual(&image_config[i].token[len_anim_token], ".x"))
5576 anim_initial.src_x = atoi(image_config[i].value);
5577 else if (strEqual(&image_config[i].token[len_anim_token], ".y"))
5578 anim_initial.src_y = atoi(image_config[i].value);
5579 else if (strEqual(&image_config[i].token[len_anim_token], ".width"))
5580 anim_initial.width = atoi(image_config[i].value);
5581 else if (strEqual(&image_config[i].token[len_anim_token], ".height"))
5582 anim_initial.height = atoi(image_config[i].value);
5583 else if (strEqual(&image_config[i].token[len_anim_token], ".frames"))
5584 anim_initial.anim_frames = atoi(image_config[i].value);
5585 else if (strEqual(&image_config[i].token[len_anim_token],
5586 ".frames_per_line"))
5587 anim_initial.anim_frames_per_line = atoi(image_config[i].value);
5588 else if (strEqual(&image_config[i].token[len_anim_token], ".delay"))
5589 anim_initial.anim_delay = atoi(image_config[i].value);
5594 #if defined(CREATE_SPECIAL_EDITION_RND_JUE)
5595 filename_anim_initial = "loading.pcx";
5597 parameter[GFX_ARG_X] = 0;
5598 parameter[GFX_ARG_Y] = 0;
5599 parameter[GFX_ARG_WIDTH] = 128;
5600 parameter[GFX_ARG_HEIGHT] = 40;
5601 parameter[GFX_ARG_FRAMES] = 32;
5602 parameter[GFX_ARG_DELAY] = 4;
5603 parameter[GFX_ARG_FRAMES_PER_LINE] = ARG_UNDEFINED_VALUE;
5606 if (filename_anim_initial == NULL) /* should not happen */
5607 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5609 anim_initial.bitmap = LoadCustomImage(filename_anim_initial);
5611 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
5613 set_graphic_parameters_ext(0, parameter, anim_initial.bitmap);
5616 printf("::: INIT_GFX: anim_frames_per_line == %d [%d / %d] [%d, %d]\n",
5617 graphic_info[0].anim_frames_per_line,
5618 get_scaled_graphic_width(0),
5619 graphic_info[0].width,
5620 getOriginalImageWidthFromImageID(0),
5621 graphic_info[0].scale_up_factor);
5624 graphic_info = graphic_info_last;
5626 init.busy.width = anim_initial.width;
5627 init.busy.height = anim_initial.height;
5629 InitMenuDesignSettings_Static();
5630 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5634 void RedrawBackground()
5636 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
5637 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
5639 redraw_mask = REDRAW_ALL;
5642 void InitGfxBackground()
5646 fieldbuffer = bitmap_db_field;
5647 SetDrawtoField(DRAW_BACKBUFFER);
5650 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5654 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
5655 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
5658 for (x = 0; x < MAX_BUF_XSIZE; x++)
5659 for (y = 0; y < MAX_BUF_YSIZE; y++)
5662 redraw_mask = REDRAW_ALL;
5665 static void InitLevelInfo()
5667 LoadLevelInfo(); /* global level info */
5668 LoadLevelSetup_LastSeries(); /* last played series info */
5669 LoadLevelSetup_SeriesInfo(); /* last played level info */
5672 static void InitLevelArtworkInfo()
5674 LoadLevelArtworkInfo();
5677 static void InitImages()
5679 print_timestamp_init("InitImages");
5682 printf("::: leveldir_current->identifier == '%s'\n",
5683 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5684 printf("::: leveldir_current->graphics_path == '%s'\n",
5685 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5686 printf("::: leveldir_current->graphics_set == '%s'\n",
5687 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5688 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5689 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5692 setLevelArtworkDir(artwork.gfx_first);
5695 printf("::: leveldir_current->identifier == '%s'\n",
5696 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5697 printf("::: leveldir_current->graphics_path == '%s'\n",
5698 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5699 printf("::: leveldir_current->graphics_set == '%s'\n",
5700 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5701 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5702 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5706 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5707 leveldir_current->identifier,
5708 artwork.gfx_current_identifier,
5709 artwork.gfx_current->identifier,
5710 leveldir_current->graphics_set,
5711 leveldir_current->graphics_path);
5714 UPDATE_BUSY_STATE();
5716 ReloadCustomImages();
5717 print_timestamp_time("ReloadCustomImages");
5719 UPDATE_BUSY_STATE();
5721 LoadCustomElementDescriptions();
5722 print_timestamp_time("LoadCustomElementDescriptions");
5724 UPDATE_BUSY_STATE();
5726 LoadMenuDesignSettings();
5727 print_timestamp_time("LoadMenuDesignSettings");
5729 UPDATE_BUSY_STATE();
5731 ReinitializeGraphics();
5732 print_timestamp_time("ReinitializeGraphics");
5734 UPDATE_BUSY_STATE();
5736 print_timestamp_done("InitImages");
5739 static void InitSound(char *identifier)
5741 print_timestamp_init("InitSound");
5743 if (identifier == NULL)
5744 identifier = artwork.snd_current->identifier;
5746 /* set artwork path to send it to the sound server process */
5747 setLevelArtworkDir(artwork.snd_first);
5749 InitReloadCustomSounds(identifier);
5750 print_timestamp_time("InitReloadCustomSounds");
5752 ReinitializeSounds();
5753 print_timestamp_time("ReinitializeSounds");
5755 print_timestamp_done("InitSound");
5758 static void InitMusic(char *identifier)
5760 print_timestamp_init("InitMusic");
5762 if (identifier == NULL)
5763 identifier = artwork.mus_current->identifier;
5765 /* set artwork path to send it to the sound server process */
5766 setLevelArtworkDir(artwork.mus_first);
5768 InitReloadCustomMusic(identifier);
5769 print_timestamp_time("InitReloadCustomMusic");
5771 ReinitializeMusic();
5772 print_timestamp_time("ReinitializeMusic");
5774 print_timestamp_done("InitMusic");
5777 void InitNetworkServer()
5779 #if defined(NETWORK_AVALIABLE)
5783 if (!options.network)
5786 #if defined(NETWORK_AVALIABLE)
5787 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5789 if (!ConnectToServer(options.server_host, options.server_port))
5790 Error(ERR_EXIT, "cannot connect to network game server");
5792 SendToServer_PlayerName(setup.player_name);
5793 SendToServer_ProtocolVersion();
5796 SendToServer_NrWanted(nr_wanted);
5800 static boolean CheckArtworkConfigForCustomElements(char *filename)
5802 SetupFileHash *setup_file_hash;
5803 boolean redefined_ce_found = FALSE;
5805 /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */
5807 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5809 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5811 char *token = HASH_ITERATION_TOKEN(itr);
5813 if (strPrefix(token, "custom_"))
5815 redefined_ce_found = TRUE;
5820 END_HASH_ITERATION(setup_file_hash, itr)
5822 freeSetupFileHash(setup_file_hash);
5825 return redefined_ce_found;
5828 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5830 char *filename_base, *filename_local;
5831 boolean redefined_ce_found = FALSE;
5833 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5836 printf("::: leveldir_current->identifier == '%s'\n",
5837 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5838 printf("::: leveldir_current->graphics_path == '%s'\n",
5839 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5840 printf("::: leveldir_current->graphics_set == '%s'\n",
5841 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5842 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5843 leveldir_current == NULL ? "[NULL]" :
5844 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5847 /* first look for special artwork configured in level series config */
5848 filename_base = getCustomArtworkLevelConfigFilename(type);
5851 printf("::: filename_base == '%s'\n", filename_base);
5854 if (fileExists(filename_base))
5855 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5857 filename_local = getCustomArtworkConfigFilename(type);
5860 printf("::: filename_local == '%s'\n", filename_local);
5863 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5864 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5867 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5870 return redefined_ce_found;
5873 static void InitOverrideArtwork()
5875 boolean redefined_ce_found = FALSE;
5877 /* to check if this level set redefines any CEs, do not use overriding */
5878 gfx.override_level_graphics = FALSE;
5879 gfx.override_level_sounds = FALSE;
5880 gfx.override_level_music = FALSE;
5882 /* now check if this level set has definitions for custom elements */
5883 if (setup.override_level_graphics == AUTO ||
5884 setup.override_level_sounds == AUTO ||
5885 setup.override_level_music == AUTO)
5886 redefined_ce_found =
5887 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5888 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5889 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5892 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5895 if (redefined_ce_found)
5897 /* this level set has CE definitions: change "AUTO" to "FALSE" */
5898 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5899 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
5900 gfx.override_level_music = (setup.override_level_music == TRUE);
5904 /* this level set has no CE definitions: change "AUTO" to "TRUE" */
5905 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5906 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
5907 gfx.override_level_music = (setup.override_level_music != FALSE);
5911 printf("::: => %d, %d, %d\n",
5912 gfx.override_level_graphics,
5913 gfx.override_level_sounds,
5914 gfx.override_level_music);
5918 static char *getNewArtworkIdentifier(int type)
5920 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5921 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5922 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5923 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5924 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5926 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5928 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
5930 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5931 char *leveldir_identifier = leveldir_current->identifier;
5933 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
5934 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5936 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
5938 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5939 char *artwork_current_identifier;
5940 char *artwork_new_identifier = NULL; /* default: nothing has changed */
5942 /* leveldir_current may be invalid (level group, parent link) */
5943 if (!validLevelSeries(leveldir_current))
5946 /* 1st step: determine artwork set to be activated in descending order:
5947 --------------------------------------------------------------------
5948 1. setup artwork (when configured to override everything else)
5949 2. artwork set configured in "levelinfo.conf" of current level set
5950 (artwork in level directory will have priority when loading later)
5951 3. artwork in level directory (stored in artwork sub-directory)
5952 4. setup artwork (currently configured in setup menu) */
5954 if (setup_override_artwork)
5955 artwork_current_identifier = setup_artwork_set;
5956 else if (leveldir_artwork_set != NULL)
5957 artwork_current_identifier = leveldir_artwork_set;
5958 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5959 artwork_current_identifier = leveldir_identifier;
5961 artwork_current_identifier = setup_artwork_set;
5964 /* 2nd step: check if it is really needed to reload artwork set
5965 ------------------------------------------------------------ */
5968 if (type == ARTWORK_TYPE_GRAPHICS)
5969 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
5970 artwork_new_identifier,
5971 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5972 artwork_current_identifier,
5973 leveldir_current->graphics_set,
5974 leveldir_current->identifier);
5977 /* ---------- reload if level set and also artwork set has changed ------- */
5978 if (leveldir_current_identifier[type] != leveldir_identifier &&
5979 (last_has_level_artwork_set[type] || has_level_artwork_set))
5980 artwork_new_identifier = artwork_current_identifier;
5982 leveldir_current_identifier[type] = leveldir_identifier;
5983 last_has_level_artwork_set[type] = has_level_artwork_set;
5986 if (type == ARTWORK_TYPE_GRAPHICS)
5987 printf("::: 1: '%s'\n", artwork_new_identifier);
5990 /* ---------- reload if "override artwork" setting has changed ----------- */
5991 if (last_override_level_artwork[type] != setup_override_artwork)
5992 artwork_new_identifier = artwork_current_identifier;
5994 last_override_level_artwork[type] = setup_override_artwork;
5997 if (type == ARTWORK_TYPE_GRAPHICS)
5998 printf("::: 2: '%s'\n", artwork_new_identifier);
6001 /* ---------- reload if current artwork identifier has changed ----------- */
6002 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
6003 artwork_current_identifier))
6004 artwork_new_identifier = artwork_current_identifier;
6006 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
6009 if (type == ARTWORK_TYPE_GRAPHICS)
6010 printf("::: 3: '%s'\n", artwork_new_identifier);
6013 /* ---------- do not reload directly after starting ---------------------- */
6014 if (!initialized[type])
6015 artwork_new_identifier = NULL;
6017 initialized[type] = TRUE;
6020 if (type == ARTWORK_TYPE_GRAPHICS)
6021 printf("::: 4: '%s'\n", artwork_new_identifier);
6025 if (type == ARTWORK_TYPE_GRAPHICS)
6026 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
6027 artwork.gfx_current_identifier, artwork_current_identifier,
6028 artwork.gfx_current->identifier, leveldir_current->graphics_set,
6029 artwork_new_identifier);
6032 return artwork_new_identifier;
6035 void ReloadCustomArtwork(int force_reload)
6037 int last_game_status = game_status; /* save current game status */
6038 char *gfx_new_identifier;
6039 char *snd_new_identifier;
6040 char *mus_new_identifier;
6041 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
6042 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
6043 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
6044 boolean reload_needed;
6046 InitOverrideArtwork();
6048 force_reload_gfx |= AdjustGraphicsForEMC();
6050 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
6051 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
6052 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
6054 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
6055 snd_new_identifier != NULL || force_reload_snd ||
6056 mus_new_identifier != NULL || force_reload_mus);
6061 print_timestamp_init("ReloadCustomArtwork");
6063 game_status = GAME_MODE_LOADING;
6065 FadeOut(REDRAW_ALL);
6068 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6070 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
6072 print_timestamp_time("ClearRectangle");
6075 printf("::: fading in ... %d\n", fading.fade_mode);
6079 printf("::: done\n");
6082 if (gfx_new_identifier != NULL || force_reload_gfx)
6085 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
6086 artwork.gfx_current_identifier,
6088 artwork.gfx_current->identifier,
6089 leveldir_current->graphics_set);
6093 print_timestamp_time("InitImages");
6096 if (snd_new_identifier != NULL || force_reload_snd)
6098 InitSound(snd_new_identifier);
6099 print_timestamp_time("InitSound");
6102 if (mus_new_identifier != NULL || force_reload_mus)
6104 InitMusic(mus_new_identifier);
6105 print_timestamp_time("InitMusic");
6108 game_status = last_game_status; /* restore current game status */
6111 printf("::: ----------------DELAY 1 ...\n");
6116 printf("::: FadeOut @ ReloadCustomArtwork ...\n");
6118 FadeOut(REDRAW_ALL);
6120 printf("::: FadeOut @ ReloadCustomArtwork done\n");
6125 /* force redraw of (open or closed) door graphics */
6126 SetDoorState(DOOR_OPEN_ALL);
6127 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
6132 FadeSetEnterScreen();
6133 FadeSkipNextFadeOut();
6134 // FadeSetDisabled();
6139 fading = fading_none;
6144 redraw_mask = REDRAW_ALL;
6147 print_timestamp_done("ReloadCustomArtwork");
6150 void KeyboardAutoRepeatOffUnlessAutoplay()
6152 if (global.autoplay_leveldir == NULL)
6153 KeyboardAutoRepeatOff();
6157 /* ========================================================================= */
6159 /* ========================================================================= */
6163 print_timestamp_init("OpenAll");
6165 game_status = GAME_MODE_LOADING;
6167 InitGlobal(); /* initialize some global variables */
6169 if (options.execute_command)
6170 Execute_Command(options.execute_command);
6172 if (options.serveronly)
6174 #if defined(PLATFORM_UNIX)
6175 NetworkServer(options.server_port, options.serveronly);
6177 Error(ERR_WARN, "networking only supported in Unix version");
6180 exit(0); /* never reached, server loops forever */
6187 InitArtworkInfo(); /* needed before loading gfx, sound & music */
6188 InitArtworkConfig(); /* needed before forking sound child process */
6193 InitRND(NEW_RANDOMIZE);
6194 InitSimpleRandom(NEW_RANDOMIZE);
6198 print_timestamp_time("[pre-video]");
6201 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
6203 InitEventFilter(FilterMouseMotionEvents);
6205 InitElementPropertiesStatic();
6206 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
6207 InitElementPropertiesGfxElement();
6209 print_timestamp_time("[post-video]");
6213 print_timestamp_time("InitGfx");
6216 print_timestamp_time("InitLevelInfo");
6218 InitLevelArtworkInfo();
6219 print_timestamp_time("InitLevelArtworkInfo");
6221 InitOverrideArtwork(); /* needs to know current level directory */
6222 print_timestamp_time("InitOverrideArtwork");
6224 InitImages(); /* needs to know current level directory */
6225 print_timestamp_time("InitImages");
6227 InitSound(NULL); /* needs to know current level directory */
6228 print_timestamp_time("InitSound");
6230 InitMusic(NULL); /* needs to know current level directory */
6231 print_timestamp_time("InitMusic");
6233 InitGfxBackground();
6243 if (global.autoplay_leveldir)
6248 else if (global.convert_leveldir)
6253 else if (global.create_images_dir)
6255 CreateLevelSketchImages();
6259 game_status = GAME_MODE_MAIN;
6262 FadeSetEnterScreen();
6263 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
6264 FadeSkipNextFadeOut();
6265 // FadeSetDisabled();
6267 fading = fading_none;
6270 print_timestamp_time("[post-artwork]");
6272 print_timestamp_done("OpenAll");
6276 InitNetworkServer();
6279 void CloseAllAndExit(int exit_value)
6284 CloseAudio(); /* called after freeing sounds (needed for SDL) */
6296 #if defined(TARGET_SDL)
6297 if (network_server) /* terminate network server */
6298 SDL_KillThread(server_thread);
6301 CloseVideoDisplay();
6302 ClosePlatformDependentStuff();
6304 if (exit_value != 0)
6305 NotifyUserAboutErrorFile();