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 10
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->style = STYLE_DEFAULT;
1312 g->bitmap = src_bitmap;
1315 /* optional zoom factor for scaling up the image to a larger size */
1316 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1317 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1318 if (g->scale_up_factor < 1)
1319 g->scale_up_factor = 1; /* no scaling */
1323 if (g->use_image_size)
1325 /* set new default bitmap size (with scaling, but without small images) */
1326 g->width = get_scaled_graphic_width(graphic);
1327 g->height = get_scaled_graphic_height(graphic);
1331 /* optional x and y tile position of animation frame sequence */
1332 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1333 g->src_x = parameter[GFX_ARG_XPOS] * TILEX;
1334 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1335 g->src_y = parameter[GFX_ARG_YPOS] * TILEY;
1337 /* optional x and y pixel position of animation frame sequence */
1338 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1339 g->src_x = parameter[GFX_ARG_X];
1340 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1341 g->src_y = parameter[GFX_ARG_Y];
1343 /* optional width and height of each animation frame */
1344 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1345 g->width = parameter[GFX_ARG_WIDTH];
1346 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1347 g->height = parameter[GFX_ARG_HEIGHT];
1350 /* optional zoom factor for scaling up the image to a larger size */
1351 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1352 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1353 if (g->scale_up_factor < 1)
1354 g->scale_up_factor = 1; /* no scaling */
1359 /* get final bitmap size (with scaling, but without small images) */
1360 int src_image_width = get_scaled_graphic_width(graphic);
1361 int src_image_height = get_scaled_graphic_height(graphic);
1363 if (src_image_width == 0 || src_image_height == 0)
1365 /* only happens when loaded outside artwork system (like "global.busy") */
1366 src_image_width = src_bitmap->width;
1367 src_image_height = src_bitmap->height;
1370 anim_frames_per_row = src_image_width / g->width;
1371 anim_frames_per_col = src_image_height / g->height;
1373 g->src_image_width = src_image_width;
1374 g->src_image_height = src_image_height;
1377 /* correct x or y offset dependent of vertical or horizontal frame order */
1378 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1380 g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1381 parameter[GFX_ARG_OFFSET] : g->height);
1382 anim_frames_per_line = anim_frames_per_col;
1384 else /* frames are ordered horizontally */
1386 g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1387 parameter[GFX_ARG_OFFSET] : g->width);
1388 anim_frames_per_line = anim_frames_per_row;
1391 /* optionally, the x and y offset of frames can be specified directly */
1392 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1393 g->offset_x = parameter[GFX_ARG_XOFFSET];
1394 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1395 g->offset_y = parameter[GFX_ARG_YOFFSET];
1397 /* optionally, moving animations may have separate start and end graphics */
1398 g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1400 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1401 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1403 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1404 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1405 g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1406 parameter[GFX_ARG_2ND_OFFSET] : g->height);
1407 else /* frames are ordered horizontally */
1408 g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1409 parameter[GFX_ARG_2ND_OFFSET] : g->width);
1411 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1412 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1413 g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1414 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1415 g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1417 /* optionally, the second movement tile can be specified as start tile */
1418 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1419 g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1421 /* automatically determine correct number of frames, if not defined */
1422 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1423 g->anim_frames = parameter[GFX_ARG_FRAMES];
1424 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1425 g->anim_frames = anim_frames_per_row;
1426 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1427 g->anim_frames = anim_frames_per_col;
1431 if (g->anim_frames == 0) /* frames must be at least 1 */
1434 g->anim_frames_per_line =
1435 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1436 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1438 g->anim_delay = parameter[GFX_ARG_DELAY];
1439 if (g->anim_delay == 0) /* delay must be at least 1 */
1442 g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1444 if (g->anim_frames == 1)
1445 g->anim_mode = ANIM_NONE;
1448 /* automatically determine correct start frame, if not defined */
1449 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1450 g->anim_start_frame = 0;
1451 else if (g->anim_mode & ANIM_REVERSE)
1452 g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1454 g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1456 /* animation synchronized with global frame counter, not move position */
1457 g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1459 /* optional element for cloning crumble graphics */
1460 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1461 g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1463 /* optional element for cloning digging graphics */
1464 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1465 g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1467 /* optional border size for "crumbling" diggable graphics */
1468 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1469 g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1471 /* this is only used for player "boring" and "sleeping" actions */
1472 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1473 g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1474 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1475 g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1476 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1477 g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1478 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1479 g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1481 /* this is only used for toon animations */
1482 g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1483 g->step_delay = parameter[GFX_ARG_STEP_DELAY];
1485 /* this is only used for drawing font characters */
1486 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1487 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1489 /* this is only used for drawing envelope graphics */
1490 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1492 /* optional graphic for cloning all graphics settings */
1493 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1494 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1496 /* optional settings for drawing title screens and title messages */
1497 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1498 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1499 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1500 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1501 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1502 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1503 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1504 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1505 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1506 g->align = parameter[GFX_ARG_ALIGN];
1507 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1508 g->valign = parameter[GFX_ARG_VALIGN];
1509 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1510 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1512 if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
1513 g->class = parameter[GFX_ARG_CLASS];
1514 if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
1515 g->style = parameter[GFX_ARG_STYLE];
1518 static void set_graphic_parameters(int graphic)
1521 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1522 char **parameter_raw = image->parameter;
1523 Bitmap *src_bitmap = getBitmapFromImageID(graphic);
1524 int parameter[NUM_GFX_ARGS];
1527 /* if fallback to default artwork is done, also use the default parameters */
1528 if (image->fallback_to_default)
1529 parameter_raw = image->default_parameter;
1531 /* get integer values from string parameters */
1532 for (i = 0; i < NUM_GFX_ARGS; i++)
1533 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1534 image_config_suffix[i].token,
1535 image_config_suffix[i].type);
1537 set_graphic_parameters_ext(graphic, parameter, src_bitmap);
1541 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1542 char **parameter_raw = image->parameter;
1543 Bitmap *src_bitmap = getBitmapFromImageID(graphic);
1544 int parameter[NUM_GFX_ARGS];
1545 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1546 int anim_frames_per_line = 1;
1549 /* if fallback to default artwork is done, also use the default parameters */
1550 if (image->fallback_to_default)
1551 parameter_raw = image->default_parameter;
1553 /* get integer values from string parameters */
1554 for (i = 0; i < NUM_GFX_ARGS; i++)
1555 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1556 image_config_suffix[i].token,
1557 image_config_suffix[i].type);
1559 graphic_info[graphic].bitmap = src_bitmap;
1561 /* always start with reliable default values */
1562 graphic_info[graphic].src_image_width = 0;
1563 graphic_info[graphic].src_image_height = 0;
1564 graphic_info[graphic].src_x = 0;
1565 graphic_info[graphic].src_y = 0;
1566 graphic_info[graphic].width = TILEX; /* default for element graphics */
1567 graphic_info[graphic].height = TILEY; /* default for element graphics */
1568 graphic_info[graphic].offset_x = 0; /* one or both of these values ... */
1569 graphic_info[graphic].offset_y = 0; /* ... will be corrected later */
1570 graphic_info[graphic].offset2_x = 0; /* one or both of these values ... */
1571 graphic_info[graphic].offset2_y = 0; /* ... will be corrected later */
1572 graphic_info[graphic].swap_double_tiles = -1; /* auto-detect tile swapping */
1573 graphic_info[graphic].crumbled_like = -1; /* do not use clone element */
1574 graphic_info[graphic].diggable_like = -1; /* do not use clone element */
1575 graphic_info[graphic].border_size = TILEX / 8; /* "CRUMBLED" border size */
1576 graphic_info[graphic].scale_up_factor = 1; /* default: no scaling up */
1577 graphic_info[graphic].clone_from = -1; /* do not use clone graphic */
1578 graphic_info[graphic].anim_delay_fixed = 0;
1579 graphic_info[graphic].anim_delay_random = 0;
1580 graphic_info[graphic].post_delay_fixed = 0;
1581 graphic_info[graphic].post_delay_random = 0;
1582 graphic_info[graphic].fade_mode = FADE_MODE_DEFAULT;
1583 graphic_info[graphic].fade_delay = -1;
1584 graphic_info[graphic].post_delay = -1;
1585 graphic_info[graphic].auto_delay = -1;
1586 graphic_info[graphic].align = ALIGN_CENTER; /* default for title screens */
1587 graphic_info[graphic].valign = VALIGN_MIDDLE; /* default for title screens */
1588 graphic_info[graphic].sort_priority = 0; /* default for title screens */
1591 /* optional zoom factor for scaling up the image to a larger size */
1592 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1593 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1594 if (graphic_info[graphic].scale_up_factor < 1)
1595 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
1599 if (graphic_info[graphic].use_image_size)
1601 /* set new default bitmap size (with scaling, but without small images) */
1602 graphic_info[graphic].width = get_scaled_graphic_width(graphic);
1603 graphic_info[graphic].height = get_scaled_graphic_height(graphic);
1607 /* optional x and y tile position of animation frame sequence */
1608 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1609 graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
1610 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1611 graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
1613 /* optional x and y pixel position of animation frame sequence */
1614 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1615 graphic_info[graphic].src_x = parameter[GFX_ARG_X];
1616 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1617 graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
1619 /* optional width and height of each animation frame */
1620 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1621 graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
1622 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1623 graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
1626 /* optional zoom factor for scaling up the image to a larger size */
1627 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1628 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1629 if (graphic_info[graphic].scale_up_factor < 1)
1630 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
1635 /* get final bitmap size (with scaling, but without small images) */
1636 int src_image_width = get_scaled_graphic_width(graphic);
1637 int src_image_height = get_scaled_graphic_height(graphic);
1639 anim_frames_per_row = src_image_width / graphic_info[graphic].width;
1640 anim_frames_per_col = src_image_height / graphic_info[graphic].height;
1642 graphic_info[graphic].src_image_width = src_image_width;
1643 graphic_info[graphic].src_image_height = src_image_height;
1646 /* correct x or y offset dependent of vertical or horizontal frame order */
1647 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1649 graphic_info[graphic].offset_y =
1650 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1651 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
1652 anim_frames_per_line = anim_frames_per_col;
1654 else /* frames are ordered horizontally */
1656 graphic_info[graphic].offset_x =
1657 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1658 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
1659 anim_frames_per_line = anim_frames_per_row;
1662 /* optionally, the x and y offset of frames can be specified directly */
1663 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1664 graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
1665 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1666 graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
1668 /* optionally, moving animations may have separate start and end graphics */
1669 graphic_info[graphic].double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1671 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1672 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1674 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1675 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1676 graphic_info[graphic].offset2_y =
1677 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1678 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].height);
1679 else /* frames are ordered horizontally */
1680 graphic_info[graphic].offset2_x =
1681 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1682 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].width);
1684 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1685 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1686 graphic_info[graphic].offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1687 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1688 graphic_info[graphic].offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1690 /* optionally, the second movement tile can be specified as start tile */
1691 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1692 graphic_info[graphic].swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1694 /* automatically determine correct number of frames, if not defined */
1695 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1696 graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
1697 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1698 graphic_info[graphic].anim_frames = anim_frames_per_row;
1699 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1700 graphic_info[graphic].anim_frames = anim_frames_per_col;
1702 graphic_info[graphic].anim_frames = 1;
1704 if (graphic_info[graphic].anim_frames == 0) /* frames must be at least 1 */
1705 graphic_info[graphic].anim_frames = 1;
1707 graphic_info[graphic].anim_frames_per_line =
1708 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1709 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1711 graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
1712 if (graphic_info[graphic].anim_delay == 0) /* delay must be at least 1 */
1713 graphic_info[graphic].anim_delay = 1;
1715 graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
1717 if (graphic_info[graphic].anim_frames == 1)
1718 graphic_info[graphic].anim_mode = ANIM_NONE;
1721 /* automatically determine correct start frame, if not defined */
1722 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1723 graphic_info[graphic].anim_start_frame = 0;
1724 else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
1725 graphic_info[graphic].anim_start_frame =
1726 graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1728 graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
1730 /* animation synchronized with global frame counter, not move position */
1731 graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1733 /* optional element for cloning crumble graphics */
1734 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1735 graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1737 /* optional element for cloning digging graphics */
1738 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1739 graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1741 /* optional border size for "crumbling" diggable graphics */
1742 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1743 graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
1745 /* this is only used for player "boring" and "sleeping" actions */
1746 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1747 graphic_info[graphic].anim_delay_fixed =
1748 parameter[GFX_ARG_ANIM_DELAY_FIXED];
1749 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1750 graphic_info[graphic].anim_delay_random =
1751 parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1752 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1753 graphic_info[graphic].post_delay_fixed =
1754 parameter[GFX_ARG_POST_DELAY_FIXED];
1755 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1756 graphic_info[graphic].post_delay_random =
1757 parameter[GFX_ARG_POST_DELAY_RANDOM];
1759 /* this is only used for toon animations */
1760 graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
1761 graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY];
1763 /* this is only used for drawing font characters */
1764 graphic_info[graphic].draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1765 graphic_info[graphic].draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1767 /* this is only used for drawing envelope graphics */
1768 graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1770 /* optional graphic for cloning all graphics settings */
1771 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1772 graphic_info[graphic].clone_from = parameter[GFX_ARG_CLONE_FROM];
1774 /* optional settings for drawing title screens and title messages */
1775 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1776 graphic_info[graphic].fade_mode = parameter[GFX_ARG_FADE_MODE];
1777 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1778 graphic_info[graphic].fade_delay = parameter[GFX_ARG_FADE_DELAY];
1779 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1780 graphic_info[graphic].post_delay = parameter[GFX_ARG_POST_DELAY];
1781 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1782 graphic_info[graphic].auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1783 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1784 graphic_info[graphic].align = parameter[GFX_ARG_ALIGN];
1785 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1786 graphic_info[graphic].valign = parameter[GFX_ARG_VALIGN];
1787 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1788 graphic_info[graphic].sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1791 UPDATE_BUSY_STATE();
1794 static void set_cloned_graphic_parameters(int graphic)
1796 int fallback_graphic = IMG_CHAR_EXCLAM;
1797 int max_num_images = getImageListSize();
1798 int clone_graphic = graphic_info[graphic].clone_from;
1799 int num_references_followed = 1;
1801 while (graphic_info[clone_graphic].clone_from != -1 &&
1802 num_references_followed < max_num_images)
1804 clone_graphic = graphic_info[clone_graphic].clone_from;
1806 num_references_followed++;
1809 if (num_references_followed >= max_num_images)
1811 Error(ERR_INFO_LINE, "-");
1812 Error(ERR_INFO, "warning: error found in config file:");
1813 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1814 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1815 Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1816 Error(ERR_INFO, "custom graphic rejected for this element/action");
1818 if (graphic == fallback_graphic)
1819 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1821 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1822 Error(ERR_INFO_LINE, "-");
1824 graphic_info[graphic] = graphic_info[fallback_graphic];
1828 graphic_info[graphic] = graphic_info[clone_graphic];
1829 graphic_info[graphic].clone_from = clone_graphic;
1833 static void InitGraphicInfo()
1835 int fallback_graphic = IMG_CHAR_EXCLAM;
1836 int num_images = getImageListSize();
1839 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1840 static boolean clipmasks_initialized = FALSE;
1842 XGCValues clip_gc_values;
1843 unsigned long clip_gc_valuemask;
1844 GC copy_clipmask_gc = None;
1847 /* use image size as default values for width and height for these images */
1848 static int full_size_graphics[] =
1853 IMG_BACKGROUND_ENVELOPE_1,
1854 IMG_BACKGROUND_ENVELOPE_2,
1855 IMG_BACKGROUND_ENVELOPE_3,
1856 IMG_BACKGROUND_ENVELOPE_4,
1859 IMG_BACKGROUND_TITLE_INITIAL,
1860 IMG_BACKGROUND_TITLE,
1861 IMG_BACKGROUND_MAIN,
1862 IMG_BACKGROUND_LEVELS,
1863 IMG_BACKGROUND_SCORES,
1864 IMG_BACKGROUND_EDITOR,
1865 IMG_BACKGROUND_INFO,
1866 IMG_BACKGROUND_INFO_ELEMENTS,
1867 IMG_BACKGROUND_INFO_MUSIC,
1868 IMG_BACKGROUND_INFO_CREDITS,
1869 IMG_BACKGROUND_INFO_PROGRAM,
1870 IMG_BACKGROUND_INFO_LEVELSET,
1871 IMG_BACKGROUND_SETUP,
1872 IMG_BACKGROUND_DOOR,
1874 IMG_TITLESCREEN_INITIAL_1,
1875 IMG_TITLESCREEN_INITIAL_2,
1876 IMG_TITLESCREEN_INITIAL_3,
1877 IMG_TITLESCREEN_INITIAL_4,
1878 IMG_TITLESCREEN_INITIAL_5,
1888 checked_free(graphic_info);
1890 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1893 /* initialize "use_image_size" flag with default value */
1894 for (i = 0; i < num_images; i++)
1895 graphic_info[i].use_image_size = FALSE;
1897 /* initialize "use_image_size" flag from static configuration above */
1898 for (i = 0; full_size_graphics[i] != -1; i++)
1899 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1902 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1903 if (clipmasks_initialized)
1905 for (i = 0; i < num_images; i++)
1907 if (graphic_info[i].clip_mask)
1908 XFreePixmap(display, graphic_info[i].clip_mask);
1909 if (graphic_info[i].clip_gc)
1910 XFreeGC(display, graphic_info[i].clip_gc);
1912 graphic_info[i].clip_mask = None;
1913 graphic_info[i].clip_gc = None;
1918 /* first set all graphic paramaters ... */
1919 for (i = 0; i < num_images; i++)
1920 set_graphic_parameters(i);
1922 /* ... then copy these parameters for cloned graphics */
1923 for (i = 0; i < num_images; i++)
1924 if (graphic_info[i].clone_from != -1)
1925 set_cloned_graphic_parameters(i);
1927 for (i = 0; i < num_images; i++)
1932 int first_frame, last_frame;
1933 int src_bitmap_width, src_bitmap_height;
1935 /* now check if no animation frames are outside of the loaded image */
1937 if (graphic_info[i].bitmap == NULL)
1938 continue; /* skip check for optional images that are undefined */
1940 /* get image size (this can differ from the standard element tile size!) */
1941 width = graphic_info[i].width;
1942 height = graphic_info[i].height;
1944 /* get final bitmap size (with scaling, but without small images) */
1945 src_bitmap_width = graphic_info[i].src_image_width;
1946 src_bitmap_height = graphic_info[i].src_image_height;
1948 /* check if first animation frame is inside specified bitmap */
1951 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1954 /* this avoids calculating wrong start position for out-of-bounds frame */
1955 src_x = graphic_info[i].src_x;
1956 src_y = graphic_info[i].src_y;
1959 if (src_x < 0 || src_y < 0 ||
1960 src_x + width > src_bitmap_width ||
1961 src_y + height > src_bitmap_height)
1963 Error(ERR_INFO_LINE, "-");
1964 Error(ERR_INFO, "warning: error found in config file:");
1965 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1966 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1967 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1969 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1970 src_x, src_y, src_bitmap_width, src_bitmap_height);
1971 Error(ERR_INFO, "custom graphic rejected for this element/action");
1973 if (i == fallback_graphic)
1974 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1976 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1977 Error(ERR_INFO_LINE, "-");
1979 graphic_info[i] = graphic_info[fallback_graphic];
1982 /* check if last animation frame is inside specified bitmap */
1984 last_frame = graphic_info[i].anim_frames - 1;
1985 getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1987 if (src_x < 0 || src_y < 0 ||
1988 src_x + width > src_bitmap_width ||
1989 src_y + height > src_bitmap_height)
1991 Error(ERR_INFO_LINE, "-");
1992 Error(ERR_INFO, "warning: error found in config file:");
1993 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1994 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1995 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1997 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1998 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1999 Error(ERR_INFO, "custom graphic rejected for this element/action");
2001 if (i == fallback_graphic)
2002 Error(ERR_EXIT, "fatal error: no fallback graphic available");
2004 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
2005 Error(ERR_INFO_LINE, "-");
2007 graphic_info[i] = graphic_info[fallback_graphic];
2010 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
2011 /* currently we only need a tile clip mask from the first frame */
2012 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
2014 if (copy_clipmask_gc == None)
2016 clip_gc_values.graphics_exposures = False;
2017 clip_gc_valuemask = GCGraphicsExposures;
2018 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
2019 clip_gc_valuemask, &clip_gc_values);
2022 graphic_info[i].clip_mask =
2023 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
2025 src_pixmap = src_bitmap->clip_mask;
2026 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
2027 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
2029 clip_gc_values.graphics_exposures = False;
2030 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
2031 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
2033 graphic_info[i].clip_gc =
2034 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
2038 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
2039 if (copy_clipmask_gc)
2040 XFreeGC(display, copy_clipmask_gc);
2042 clipmasks_initialized = TRUE;
2046 static void InitElementSoundInfo()
2048 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
2049 int num_property_mappings = getSoundListPropertyMappingSize();
2052 /* set values to -1 to identify later as "uninitialized" values */
2053 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2054 for (act = 0; act < NUM_ACTIONS; act++)
2055 element_info[i].sound[act] = -1;
2057 /* initialize element/sound mapping from static configuration */
2058 for (i = 0; element_to_sound[i].element > -1; i++)
2060 int element = element_to_sound[i].element;
2061 int action = element_to_sound[i].action;
2062 int sound = element_to_sound[i].sound;
2063 boolean is_class = element_to_sound[i].is_class;
2066 action = ACTION_DEFAULT;
2069 element_info[element].sound[action] = sound;
2071 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2072 if (strEqual(element_info[j].class_name,
2073 element_info[element].class_name))
2074 element_info[j].sound[action] = sound;
2077 /* initialize element class/sound mapping from dynamic configuration */
2078 for (i = 0; i < num_property_mappings; i++)
2080 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
2081 int action = property_mapping[i].ext1_index;
2082 int sound = property_mapping[i].artwork_index;
2084 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
2088 action = ACTION_DEFAULT;
2090 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2091 if (strEqual(element_info[j].class_name,
2092 element_info[element_class].class_name))
2093 element_info[j].sound[action] = sound;
2096 /* initialize element/sound mapping from dynamic configuration */
2097 for (i = 0; i < num_property_mappings; i++)
2099 int element = property_mapping[i].base_index;
2100 int action = property_mapping[i].ext1_index;
2101 int sound = property_mapping[i].artwork_index;
2103 if (element >= MAX_NUM_ELEMENTS)
2107 action = ACTION_DEFAULT;
2109 element_info[element].sound[action] = sound;
2112 /* now set all '-1' values to element specific default values */
2113 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2115 for (act = 0; act < NUM_ACTIONS; act++)
2117 /* generic default action sound (defined by "[default]" directive) */
2118 int default_action_sound = element_info[EL_DEFAULT].sound[act];
2120 /* look for special default action sound (classic game specific) */
2121 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
2122 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
2123 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
2124 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
2125 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
2126 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
2128 /* !!! there's no such thing as a "default action sound" !!! */
2130 /* look for element specific default sound (independent from action) */
2131 if (element_info[i].sound[ACTION_DEFAULT] != -1)
2132 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
2136 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
2137 /* !!! make this better !!! */
2138 if (i == EL_EMPTY_SPACE)
2139 default_action_sound = element_info[EL_DEFAULT].sound[act];
2142 /* no sound for this specific action -- use default action sound */
2143 if (element_info[i].sound[act] == -1)
2144 element_info[i].sound[act] = default_action_sound;
2148 /* copy sound settings to some elements that are only stored in level file
2149 in native R'n'D levels, but are used by game engine in native EM levels */
2150 for (i = 0; copy_properties[i][0] != -1; i++)
2151 for (j = 1; j <= 4; j++)
2152 for (act = 0; act < NUM_ACTIONS; act++)
2153 element_info[copy_properties[i][j]].sound[act] =
2154 element_info[copy_properties[i][0]].sound[act];
2157 static void InitGameModeSoundInfo()
2161 /* set values to -1 to identify later as "uninitialized" values */
2162 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2165 /* initialize gamemode/sound mapping from static configuration */
2166 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
2168 int gamemode = gamemode_to_sound[i].gamemode;
2169 int sound = gamemode_to_sound[i].sound;
2172 gamemode = GAME_MODE_DEFAULT;
2174 menu.sound[gamemode] = sound;
2177 /* now set all '-1' values to levelset specific default values */
2178 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2179 if (menu.sound[i] == -1)
2180 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
2183 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2184 if (menu.sound[i] != -1)
2185 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
2189 static void set_sound_parameters(int sound, char **parameter_raw)
2191 int parameter[NUM_SND_ARGS];
2194 /* get integer values from string parameters */
2195 for (i = 0; i < NUM_SND_ARGS; i++)
2197 get_parameter_value(parameter_raw[i],
2198 sound_config_suffix[i].token,
2199 sound_config_suffix[i].type);
2201 /* explicit loop mode setting in configuration overrides default value */
2202 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2203 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
2205 /* sound volume to change the original volume when loading the sound file */
2206 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
2208 /* sound priority to give certain sounds a higher or lower priority */
2209 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
2212 static void InitSoundInfo()
2214 int *sound_effect_properties;
2215 int num_sounds = getSoundListSize();
2218 checked_free(sound_info);
2220 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
2221 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
2223 /* initialize sound effect for all elements to "no sound" */
2224 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2225 for (j = 0; j < NUM_ACTIONS; j++)
2226 element_info[i].sound[j] = SND_UNDEFINED;
2228 for (i = 0; i < num_sounds; i++)
2230 struct FileInfo *sound = getSoundListEntry(i);
2231 int len_effect_text = strlen(sound->token);
2233 sound_effect_properties[i] = ACTION_OTHER;
2234 sound_info[i].loop = FALSE; /* default: play sound only once */
2237 printf("::: sound %d: '%s'\n", i, sound->token);
2240 /* determine all loop sounds and identify certain sound classes */
2242 for (j = 0; element_action_info[j].suffix; j++)
2244 int len_action_text = strlen(element_action_info[j].suffix);
2246 if (len_action_text < len_effect_text &&
2247 strEqual(&sound->token[len_effect_text - len_action_text],
2248 element_action_info[j].suffix))
2250 sound_effect_properties[i] = element_action_info[j].value;
2251 sound_info[i].loop = element_action_info[j].is_loop_sound;
2257 /* associate elements and some selected sound actions */
2259 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2261 if (element_info[j].class_name)
2263 int len_class_text = strlen(element_info[j].class_name);
2265 if (len_class_text + 1 < len_effect_text &&
2266 strncmp(sound->token,
2267 element_info[j].class_name, len_class_text) == 0 &&
2268 sound->token[len_class_text] == '.')
2270 int sound_action_value = sound_effect_properties[i];
2272 element_info[j].sound[sound_action_value] = i;
2277 set_sound_parameters(i, sound->parameter);
2280 free(sound_effect_properties);
2283 static void InitGameModeMusicInfo()
2285 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
2286 int num_property_mappings = getMusicListPropertyMappingSize();
2287 int default_levelset_music = -1;
2290 /* set values to -1 to identify later as "uninitialized" values */
2291 for (i = 0; i < MAX_LEVELS; i++)
2292 levelset.music[i] = -1;
2293 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2296 /* initialize gamemode/music mapping from static configuration */
2297 for (i = 0; gamemode_to_music[i].music > -1; i++)
2299 int gamemode = gamemode_to_music[i].gamemode;
2300 int music = gamemode_to_music[i].music;
2303 printf("::: gamemode == %d, music == %d\n", gamemode, music);
2307 gamemode = GAME_MODE_DEFAULT;
2309 menu.music[gamemode] = music;
2312 /* initialize gamemode/music mapping from dynamic configuration */
2313 for (i = 0; i < num_property_mappings; i++)
2315 int prefix = property_mapping[i].base_index;
2316 int gamemode = property_mapping[i].ext1_index;
2317 int level = property_mapping[i].ext2_index;
2318 int music = property_mapping[i].artwork_index;
2321 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
2322 prefix, gamemode, level, music);
2325 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
2329 gamemode = GAME_MODE_DEFAULT;
2331 /* level specific music only allowed for in-game music */
2332 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
2333 gamemode = GAME_MODE_PLAYING;
2338 default_levelset_music = music;
2341 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
2342 levelset.music[level] = music;
2343 if (gamemode != GAME_MODE_PLAYING)
2344 menu.music[gamemode] = music;
2347 /* now set all '-1' values to menu specific default values */
2348 /* (undefined values of "levelset.music[]" might stay at "-1" to
2349 allow dynamic selection of music files from music directory!) */
2350 for (i = 0; i < MAX_LEVELS; i++)
2351 if (levelset.music[i] == -1)
2352 levelset.music[i] = default_levelset_music;
2353 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2354 if (menu.music[i] == -1)
2355 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
2358 for (i = 0; i < MAX_LEVELS; i++)
2359 if (levelset.music[i] != -1)
2360 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
2361 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2362 if (menu.music[i] != -1)
2363 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
2367 static void set_music_parameters(int music, char **parameter_raw)
2369 int parameter[NUM_MUS_ARGS];
2372 /* get integer values from string parameters */
2373 for (i = 0; i < NUM_MUS_ARGS; i++)
2375 get_parameter_value(parameter_raw[i],
2376 music_config_suffix[i].token,
2377 music_config_suffix[i].type);
2379 /* explicit loop mode setting in configuration overrides default value */
2380 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2381 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
2384 static void InitMusicInfo()
2386 int num_music = getMusicListSize();
2389 checked_free(music_info);
2391 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
2393 for (i = 0; i < num_music; i++)
2395 struct FileInfo *music = getMusicListEntry(i);
2396 int len_music_text = strlen(music->token);
2398 music_info[i].loop = TRUE; /* default: play music in loop mode */
2400 /* determine all loop music */
2402 for (j = 0; music_prefix_info[j].prefix; j++)
2404 int len_prefix_text = strlen(music_prefix_info[j].prefix);
2406 if (len_prefix_text < len_music_text &&
2407 strncmp(music->token,
2408 music_prefix_info[j].prefix, len_prefix_text) == 0)
2410 music_info[i].loop = music_prefix_info[j].is_loop_music;
2416 set_music_parameters(i, music->parameter);
2420 static void ReinitializeGraphics()
2422 print_timestamp_init("ReinitializeGraphics");
2424 InitGraphicInfo(); /* graphic properties mapping */
2425 print_timestamp_time("InitGraphicInfo");
2426 InitElementGraphicInfo(); /* element game graphic mapping */
2427 print_timestamp_time("InitElementGraphicInfo");
2428 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
2429 print_timestamp_time("InitElementSpecialGraphicInfo");
2431 InitElementSmallImages(); /* scale elements to all needed sizes */
2432 print_timestamp_time("InitElementSmallImages");
2433 InitScaledImages(); /* scale all other images, if needed */
2434 print_timestamp_time("InitScaledImages");
2435 InitFontGraphicInfo(); /* initialize text drawing functions */
2436 print_timestamp_time("InitFontGraphicInfo");
2438 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
2439 print_timestamp_time("InitGraphicInfo_EM");
2441 SetMainBackgroundImage(IMG_BACKGROUND);
2442 print_timestamp_time("SetMainBackgroundImage");
2443 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2444 print_timestamp_time("SetDoorBackgroundImage");
2447 print_timestamp_time("InitGadgets");
2449 print_timestamp_time("InitToons");
2451 print_timestamp_done("ReinitializeGraphics");
2454 static void ReinitializeSounds()
2456 InitSoundInfo(); /* sound properties mapping */
2457 InitElementSoundInfo(); /* element game sound mapping */
2458 InitGameModeSoundInfo(); /* game mode sound mapping */
2460 InitPlayLevelSound(); /* internal game sound settings */
2463 static void ReinitializeMusic()
2465 InitMusicInfo(); /* music properties mapping */
2466 InitGameModeMusicInfo(); /* game mode music mapping */
2469 static int get_special_property_bit(int element, int property_bit_nr)
2471 struct PropertyBitInfo
2477 static struct PropertyBitInfo pb_can_move_into_acid[] =
2479 /* the player may be able fall into acid when gravity is activated */
2484 { EL_SP_MURPHY, 0 },
2485 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2487 /* all elements that can move may be able to also move into acid */
2490 { EL_BUG_RIGHT, 1 },
2493 { EL_SPACESHIP, 2 },
2494 { EL_SPACESHIP_LEFT, 2 },
2495 { EL_SPACESHIP_RIGHT, 2 },
2496 { EL_SPACESHIP_UP, 2 },
2497 { EL_SPACESHIP_DOWN, 2 },
2498 { EL_BD_BUTTERFLY, 3 },
2499 { EL_BD_BUTTERFLY_LEFT, 3 },
2500 { EL_BD_BUTTERFLY_RIGHT, 3 },
2501 { EL_BD_BUTTERFLY_UP, 3 },
2502 { EL_BD_BUTTERFLY_DOWN, 3 },
2503 { EL_BD_FIREFLY, 4 },
2504 { EL_BD_FIREFLY_LEFT, 4 },
2505 { EL_BD_FIREFLY_RIGHT, 4 },
2506 { EL_BD_FIREFLY_UP, 4 },
2507 { EL_BD_FIREFLY_DOWN, 4 },
2509 { EL_YAMYAM_LEFT, 5 },
2510 { EL_YAMYAM_RIGHT, 5 },
2511 { EL_YAMYAM_UP, 5 },
2512 { EL_YAMYAM_DOWN, 5 },
2513 { EL_DARK_YAMYAM, 6 },
2516 { EL_PACMAN_LEFT, 8 },
2517 { EL_PACMAN_RIGHT, 8 },
2518 { EL_PACMAN_UP, 8 },
2519 { EL_PACMAN_DOWN, 8 },
2521 { EL_MOLE_LEFT, 9 },
2522 { EL_MOLE_RIGHT, 9 },
2524 { EL_MOLE_DOWN, 9 },
2528 { EL_SATELLITE, 13 },
2529 { EL_SP_SNIKSNAK, 14 },
2530 { EL_SP_ELECTRON, 15 },
2533 { EL_EMC_ANDROID, 18 },
2538 static struct PropertyBitInfo pb_dont_collide_with[] =
2540 { EL_SP_SNIKSNAK, 0 },
2541 { EL_SP_ELECTRON, 1 },
2549 struct PropertyBitInfo *pb_info;
2552 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2553 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2558 struct PropertyBitInfo *pb_info = NULL;
2561 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2562 if (pb_definition[i].bit_nr == property_bit_nr)
2563 pb_info = pb_definition[i].pb_info;
2565 if (pb_info == NULL)
2568 for (i = 0; pb_info[i].element != -1; i++)
2569 if (pb_info[i].element == element)
2570 return pb_info[i].bit_nr;
2575 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2576 boolean property_value)
2578 int bit_nr = get_special_property_bit(element, property_bit_nr);
2583 *bitfield |= (1 << bit_nr);
2585 *bitfield &= ~(1 << bit_nr);
2589 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2591 int bit_nr = get_special_property_bit(element, property_bit_nr);
2594 return ((*bitfield & (1 << bit_nr)) != 0);
2599 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2601 static int group_nr;
2602 static struct ElementGroupInfo *group;
2603 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2606 if (actual_group == NULL) /* not yet initialized */
2609 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
2611 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2612 group_element - EL_GROUP_START + 1);
2614 /* replace element which caused too deep recursion by question mark */
2615 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2620 if (recursion_depth == 0) /* initialization */
2622 group = actual_group;
2623 group_nr = GROUP_NR(group_element);
2625 group->num_elements_resolved = 0;
2626 group->choice_pos = 0;
2628 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2629 element_info[i].in_group[group_nr] = FALSE;
2632 for (i = 0; i < actual_group->num_elements; i++)
2634 int element = actual_group->element[i];
2636 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2639 if (IS_GROUP_ELEMENT(element))
2640 ResolveGroupElementExt(element, recursion_depth + 1);
2643 group->element_resolved[group->num_elements_resolved++] = element;
2644 element_info[element].in_group[group_nr] = TRUE;
2649 void ResolveGroupElement(int group_element)
2651 ResolveGroupElementExt(group_element, 0);
2654 void InitElementPropertiesStatic()
2656 static boolean clipboard_elements_initialized = FALSE;
2658 static int ep_diggable[] =
2663 EL_SP_BUGGY_BASE_ACTIVATING,
2666 EL_INVISIBLE_SAND_ACTIVE,
2669 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2670 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2675 EL_SP_BUGGY_BASE_ACTIVE,
2682 static int ep_collectible_only[] =
2704 EL_DYNABOMB_INCREASE_NUMBER,
2705 EL_DYNABOMB_INCREASE_SIZE,
2706 EL_DYNABOMB_INCREASE_POWER,
2724 /* !!! handle separately !!! */
2725 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2731 static int ep_dont_run_into[] =
2733 /* same elements as in 'ep_dont_touch' */
2739 /* same elements as in 'ep_dont_collide_with' */
2751 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2756 EL_SP_BUGGY_BASE_ACTIVE,
2763 static int ep_dont_collide_with[] =
2765 /* same elements as in 'ep_dont_touch' */
2782 static int ep_dont_touch[] =
2792 static int ep_indestructible[] =
2796 EL_ACID_POOL_TOPLEFT,
2797 EL_ACID_POOL_TOPRIGHT,
2798 EL_ACID_POOL_BOTTOMLEFT,
2799 EL_ACID_POOL_BOTTOM,
2800 EL_ACID_POOL_BOTTOMRIGHT,
2801 EL_SP_HARDWARE_GRAY,
2802 EL_SP_HARDWARE_GREEN,
2803 EL_SP_HARDWARE_BLUE,
2805 EL_SP_HARDWARE_YELLOW,
2806 EL_SP_HARDWARE_BASE_1,
2807 EL_SP_HARDWARE_BASE_2,
2808 EL_SP_HARDWARE_BASE_3,
2809 EL_SP_HARDWARE_BASE_4,
2810 EL_SP_HARDWARE_BASE_5,
2811 EL_SP_HARDWARE_BASE_6,
2812 EL_INVISIBLE_STEELWALL,
2813 EL_INVISIBLE_STEELWALL_ACTIVE,
2814 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2815 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2816 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2817 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2818 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2819 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2820 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2821 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2822 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2823 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2824 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2825 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2827 EL_LIGHT_SWITCH_ACTIVE,
2828 EL_SIGN_EXCLAMATION,
2829 EL_SIGN_RADIOACTIVITY,
2836 EL_SIGN_ENTRY_FORBIDDEN,
2837 EL_SIGN_EMERGENCY_EXIT,
2845 EL_STEEL_EXIT_CLOSED,
2847 EL_STEEL_EXIT_OPENING,
2848 EL_STEEL_EXIT_CLOSING,
2849 EL_EM_STEEL_EXIT_CLOSED,
2850 EL_EM_STEEL_EXIT_OPEN,
2851 EL_EM_STEEL_EXIT_OPENING,
2852 EL_EM_STEEL_EXIT_CLOSING,
2853 EL_DC_STEELWALL_1_LEFT,
2854 EL_DC_STEELWALL_1_RIGHT,
2855 EL_DC_STEELWALL_1_TOP,
2856 EL_DC_STEELWALL_1_BOTTOM,
2857 EL_DC_STEELWALL_1_HORIZONTAL,
2858 EL_DC_STEELWALL_1_VERTICAL,
2859 EL_DC_STEELWALL_1_TOPLEFT,
2860 EL_DC_STEELWALL_1_TOPRIGHT,
2861 EL_DC_STEELWALL_1_BOTTOMLEFT,
2862 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2863 EL_DC_STEELWALL_1_TOPLEFT_2,
2864 EL_DC_STEELWALL_1_TOPRIGHT_2,
2865 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2866 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2867 EL_DC_STEELWALL_2_LEFT,
2868 EL_DC_STEELWALL_2_RIGHT,
2869 EL_DC_STEELWALL_2_TOP,
2870 EL_DC_STEELWALL_2_BOTTOM,
2871 EL_DC_STEELWALL_2_HORIZONTAL,
2872 EL_DC_STEELWALL_2_VERTICAL,
2873 EL_DC_STEELWALL_2_MIDDLE,
2874 EL_DC_STEELWALL_2_SINGLE,
2875 EL_STEELWALL_SLIPPERY,
2889 EL_GATE_1_GRAY_ACTIVE,
2890 EL_GATE_2_GRAY_ACTIVE,
2891 EL_GATE_3_GRAY_ACTIVE,
2892 EL_GATE_4_GRAY_ACTIVE,
2901 EL_EM_GATE_1_GRAY_ACTIVE,
2902 EL_EM_GATE_2_GRAY_ACTIVE,
2903 EL_EM_GATE_3_GRAY_ACTIVE,
2904 EL_EM_GATE_4_GRAY_ACTIVE,
2913 EL_EMC_GATE_5_GRAY_ACTIVE,
2914 EL_EMC_GATE_6_GRAY_ACTIVE,
2915 EL_EMC_GATE_7_GRAY_ACTIVE,
2916 EL_EMC_GATE_8_GRAY_ACTIVE,
2918 EL_DC_GATE_WHITE_GRAY,
2919 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2920 EL_DC_GATE_FAKE_GRAY,
2922 EL_SWITCHGATE_OPENING,
2923 EL_SWITCHGATE_CLOSED,
2924 EL_SWITCHGATE_CLOSING,
2926 EL_DC_SWITCHGATE_SWITCH_UP,
2927 EL_DC_SWITCHGATE_SWITCH_DOWN,
2930 EL_TIMEGATE_OPENING,
2932 EL_TIMEGATE_CLOSING,
2934 EL_DC_TIMEGATE_SWITCH,
2935 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2940 EL_TUBE_VERTICAL_LEFT,
2941 EL_TUBE_VERTICAL_RIGHT,
2942 EL_TUBE_HORIZONTAL_UP,
2943 EL_TUBE_HORIZONTAL_DOWN,
2948 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2949 EL_EXPANDABLE_STEELWALL_VERTICAL,
2950 EL_EXPANDABLE_STEELWALL_ANY,
2955 static int ep_slippery[] =
2969 EL_ROBOT_WHEEL_ACTIVE,
2975 EL_ACID_POOL_TOPLEFT,
2976 EL_ACID_POOL_TOPRIGHT,
2986 EL_STEELWALL_SLIPPERY,
2989 EL_EMC_WALL_SLIPPERY_1,
2990 EL_EMC_WALL_SLIPPERY_2,
2991 EL_EMC_WALL_SLIPPERY_3,
2992 EL_EMC_WALL_SLIPPERY_4,
2994 EL_EMC_MAGIC_BALL_ACTIVE,
2999 static int ep_can_change[] =
3004 static int ep_can_move[] =
3006 /* same elements as in 'pb_can_move_into_acid' */
3029 static int ep_can_fall[] =
3043 EL_QUICKSAND_FAST_FULL,
3045 EL_BD_MAGIC_WALL_FULL,
3046 EL_DC_MAGIC_WALL_FULL,
3060 static int ep_can_smash_player[] =
3086 static int ep_can_smash_enemies[] =
3095 static int ep_can_smash_everything[] =
3104 static int ep_explodes_by_fire[] =
3106 /* same elements as in 'ep_explodes_impact' */
3111 /* same elements as in 'ep_explodes_smashed' */
3121 EL_EM_DYNAMITE_ACTIVE,
3122 EL_DYNABOMB_PLAYER_1_ACTIVE,
3123 EL_DYNABOMB_PLAYER_2_ACTIVE,
3124 EL_DYNABOMB_PLAYER_3_ACTIVE,
3125 EL_DYNABOMB_PLAYER_4_ACTIVE,
3126 EL_DYNABOMB_INCREASE_NUMBER,
3127 EL_DYNABOMB_INCREASE_SIZE,
3128 EL_DYNABOMB_INCREASE_POWER,
3129 EL_SP_DISK_RED_ACTIVE,
3143 static int ep_explodes_smashed[] =
3145 /* same elements as in 'ep_explodes_impact' */
3159 static int ep_explodes_impact[] =
3168 static int ep_walkable_over[] =
3172 EL_SOKOBAN_FIELD_EMPTY,
3181 EL_EM_STEEL_EXIT_OPEN,
3183 EL_EM_STEEL_EXIT_OPENING,
3193 EL_GATE_1_GRAY_ACTIVE,
3194 EL_GATE_2_GRAY_ACTIVE,
3195 EL_GATE_3_GRAY_ACTIVE,
3196 EL_GATE_4_GRAY_ACTIVE,
3204 static int ep_walkable_inside[] =
3209 EL_TUBE_VERTICAL_LEFT,
3210 EL_TUBE_VERTICAL_RIGHT,
3211 EL_TUBE_HORIZONTAL_UP,
3212 EL_TUBE_HORIZONTAL_DOWN,
3221 static int ep_walkable_under[] =
3226 static int ep_passable_over[] =
3236 EL_EM_GATE_1_GRAY_ACTIVE,
3237 EL_EM_GATE_2_GRAY_ACTIVE,
3238 EL_EM_GATE_3_GRAY_ACTIVE,
3239 EL_EM_GATE_4_GRAY_ACTIVE,
3248 EL_EMC_GATE_5_GRAY_ACTIVE,
3249 EL_EMC_GATE_6_GRAY_ACTIVE,
3250 EL_EMC_GATE_7_GRAY_ACTIVE,
3251 EL_EMC_GATE_8_GRAY_ACTIVE,
3253 EL_DC_GATE_WHITE_GRAY,
3254 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3261 static int ep_passable_inside[] =
3267 EL_SP_PORT_HORIZONTAL,
3268 EL_SP_PORT_VERTICAL,
3270 EL_SP_GRAVITY_PORT_LEFT,
3271 EL_SP_GRAVITY_PORT_RIGHT,
3272 EL_SP_GRAVITY_PORT_UP,
3273 EL_SP_GRAVITY_PORT_DOWN,
3274 EL_SP_GRAVITY_ON_PORT_LEFT,
3275 EL_SP_GRAVITY_ON_PORT_RIGHT,
3276 EL_SP_GRAVITY_ON_PORT_UP,
3277 EL_SP_GRAVITY_ON_PORT_DOWN,
3278 EL_SP_GRAVITY_OFF_PORT_LEFT,
3279 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3280 EL_SP_GRAVITY_OFF_PORT_UP,
3281 EL_SP_GRAVITY_OFF_PORT_DOWN,
3286 static int ep_passable_under[] =
3291 static int ep_droppable[] =
3296 static int ep_explodes_1x1_old[] =
3301 static int ep_pushable[] =
3313 EL_SOKOBAN_FIELD_FULL,
3322 static int ep_explodes_cross_old[] =
3327 static int ep_protected[] =
3329 /* same elements as in 'ep_walkable_inside' */
3333 EL_TUBE_VERTICAL_LEFT,
3334 EL_TUBE_VERTICAL_RIGHT,
3335 EL_TUBE_HORIZONTAL_UP,
3336 EL_TUBE_HORIZONTAL_DOWN,
3342 /* same elements as in 'ep_passable_over' */
3351 EL_EM_GATE_1_GRAY_ACTIVE,
3352 EL_EM_GATE_2_GRAY_ACTIVE,
3353 EL_EM_GATE_3_GRAY_ACTIVE,
3354 EL_EM_GATE_4_GRAY_ACTIVE,
3363 EL_EMC_GATE_5_GRAY_ACTIVE,
3364 EL_EMC_GATE_6_GRAY_ACTIVE,
3365 EL_EMC_GATE_7_GRAY_ACTIVE,
3366 EL_EMC_GATE_8_GRAY_ACTIVE,
3368 EL_DC_GATE_WHITE_GRAY,
3369 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3373 /* same elements as in 'ep_passable_inside' */
3378 EL_SP_PORT_HORIZONTAL,
3379 EL_SP_PORT_VERTICAL,
3381 EL_SP_GRAVITY_PORT_LEFT,
3382 EL_SP_GRAVITY_PORT_RIGHT,
3383 EL_SP_GRAVITY_PORT_UP,
3384 EL_SP_GRAVITY_PORT_DOWN,
3385 EL_SP_GRAVITY_ON_PORT_LEFT,
3386 EL_SP_GRAVITY_ON_PORT_RIGHT,
3387 EL_SP_GRAVITY_ON_PORT_UP,
3388 EL_SP_GRAVITY_ON_PORT_DOWN,
3389 EL_SP_GRAVITY_OFF_PORT_LEFT,
3390 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3391 EL_SP_GRAVITY_OFF_PORT_UP,
3392 EL_SP_GRAVITY_OFF_PORT_DOWN,
3397 static int ep_throwable[] =
3402 static int ep_can_explode[] =
3404 /* same elements as in 'ep_explodes_impact' */
3409 /* same elements as in 'ep_explodes_smashed' */
3415 /* elements that can explode by explosion or by dragonfire */
3419 EL_EM_DYNAMITE_ACTIVE,
3420 EL_DYNABOMB_PLAYER_1_ACTIVE,
3421 EL_DYNABOMB_PLAYER_2_ACTIVE,
3422 EL_DYNABOMB_PLAYER_3_ACTIVE,
3423 EL_DYNABOMB_PLAYER_4_ACTIVE,
3424 EL_DYNABOMB_INCREASE_NUMBER,
3425 EL_DYNABOMB_INCREASE_SIZE,
3426 EL_DYNABOMB_INCREASE_POWER,
3427 EL_SP_DISK_RED_ACTIVE,
3435 /* elements that can explode only by explosion */
3441 static int ep_gravity_reachable[] =
3447 EL_INVISIBLE_SAND_ACTIVE,
3452 EL_SP_PORT_HORIZONTAL,
3453 EL_SP_PORT_VERTICAL,
3455 EL_SP_GRAVITY_PORT_LEFT,
3456 EL_SP_GRAVITY_PORT_RIGHT,
3457 EL_SP_GRAVITY_PORT_UP,
3458 EL_SP_GRAVITY_PORT_DOWN,
3459 EL_SP_GRAVITY_ON_PORT_LEFT,
3460 EL_SP_GRAVITY_ON_PORT_RIGHT,
3461 EL_SP_GRAVITY_ON_PORT_UP,
3462 EL_SP_GRAVITY_ON_PORT_DOWN,
3463 EL_SP_GRAVITY_OFF_PORT_LEFT,
3464 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3465 EL_SP_GRAVITY_OFF_PORT_UP,
3466 EL_SP_GRAVITY_OFF_PORT_DOWN,
3472 static int ep_player[] =
3479 EL_SOKOBAN_FIELD_PLAYER,
3485 static int ep_can_pass_magic_wall[] =
3499 static int ep_can_pass_dc_magic_wall[] =
3515 static int ep_switchable[] =
3519 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3520 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3521 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3522 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3523 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3524 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3525 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3526 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3527 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3528 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3529 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3530 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3531 EL_SWITCHGATE_SWITCH_UP,
3532 EL_SWITCHGATE_SWITCH_DOWN,
3533 EL_DC_SWITCHGATE_SWITCH_UP,
3534 EL_DC_SWITCHGATE_SWITCH_DOWN,
3536 EL_LIGHT_SWITCH_ACTIVE,
3538 EL_DC_TIMEGATE_SWITCH,
3539 EL_BALLOON_SWITCH_LEFT,
3540 EL_BALLOON_SWITCH_RIGHT,
3541 EL_BALLOON_SWITCH_UP,
3542 EL_BALLOON_SWITCH_DOWN,
3543 EL_BALLOON_SWITCH_ANY,
3544 EL_BALLOON_SWITCH_NONE,
3547 EL_EMC_MAGIC_BALL_SWITCH,
3548 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3553 static int ep_bd_element[] =
3587 static int ep_sp_element[] =
3589 /* should always be valid */
3592 /* standard classic Supaplex elements */
3599 EL_SP_HARDWARE_GRAY,
3607 EL_SP_GRAVITY_PORT_RIGHT,
3608 EL_SP_GRAVITY_PORT_DOWN,
3609 EL_SP_GRAVITY_PORT_LEFT,
3610 EL_SP_GRAVITY_PORT_UP,
3615 EL_SP_PORT_VERTICAL,
3616 EL_SP_PORT_HORIZONTAL,
3622 EL_SP_HARDWARE_BASE_1,
3623 EL_SP_HARDWARE_GREEN,
3624 EL_SP_HARDWARE_BLUE,
3626 EL_SP_HARDWARE_YELLOW,
3627 EL_SP_HARDWARE_BASE_2,
3628 EL_SP_HARDWARE_BASE_3,
3629 EL_SP_HARDWARE_BASE_4,
3630 EL_SP_HARDWARE_BASE_5,
3631 EL_SP_HARDWARE_BASE_6,
3635 /* additional elements that appeared in newer Supaplex levels */
3638 /* additional gravity port elements (not switching, but setting gravity) */
3639 EL_SP_GRAVITY_ON_PORT_LEFT,
3640 EL_SP_GRAVITY_ON_PORT_RIGHT,
3641 EL_SP_GRAVITY_ON_PORT_UP,
3642 EL_SP_GRAVITY_ON_PORT_DOWN,
3643 EL_SP_GRAVITY_OFF_PORT_LEFT,
3644 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3645 EL_SP_GRAVITY_OFF_PORT_UP,
3646 EL_SP_GRAVITY_OFF_PORT_DOWN,
3648 /* more than one Murphy in a level results in an inactive clone */
3651 /* runtime Supaplex elements */
3652 EL_SP_DISK_RED_ACTIVE,
3653 EL_SP_TERMINAL_ACTIVE,
3654 EL_SP_BUGGY_BASE_ACTIVATING,
3655 EL_SP_BUGGY_BASE_ACTIVE,
3662 static int ep_sb_element[] =
3667 EL_SOKOBAN_FIELD_EMPTY,
3668 EL_SOKOBAN_FIELD_FULL,
3669 EL_SOKOBAN_FIELD_PLAYER,
3674 EL_INVISIBLE_STEELWALL,
3679 static int ep_gem[] =
3691 static int ep_food_dark_yamyam[] =
3719 static int ep_food_penguin[] =
3733 static int ep_food_pig[] =
3745 static int ep_historic_wall[] =
3756 EL_GATE_1_GRAY_ACTIVE,
3757 EL_GATE_2_GRAY_ACTIVE,
3758 EL_GATE_3_GRAY_ACTIVE,
3759 EL_GATE_4_GRAY_ACTIVE,
3768 EL_EM_GATE_1_GRAY_ACTIVE,
3769 EL_EM_GATE_2_GRAY_ACTIVE,
3770 EL_EM_GATE_3_GRAY_ACTIVE,
3771 EL_EM_GATE_4_GRAY_ACTIVE,
3778 EL_EXPANDABLE_WALL_HORIZONTAL,
3779 EL_EXPANDABLE_WALL_VERTICAL,
3780 EL_EXPANDABLE_WALL_ANY,
3781 EL_EXPANDABLE_WALL_GROWING,
3782 EL_BD_EXPANDABLE_WALL,
3789 EL_SP_HARDWARE_GRAY,
3790 EL_SP_HARDWARE_GREEN,
3791 EL_SP_HARDWARE_BLUE,
3793 EL_SP_HARDWARE_YELLOW,
3794 EL_SP_HARDWARE_BASE_1,
3795 EL_SP_HARDWARE_BASE_2,
3796 EL_SP_HARDWARE_BASE_3,
3797 EL_SP_HARDWARE_BASE_4,
3798 EL_SP_HARDWARE_BASE_5,
3799 EL_SP_HARDWARE_BASE_6,
3801 EL_SP_TERMINAL_ACTIVE,
3804 EL_INVISIBLE_STEELWALL,
3805 EL_INVISIBLE_STEELWALL_ACTIVE,
3807 EL_INVISIBLE_WALL_ACTIVE,
3808 EL_STEELWALL_SLIPPERY,
3825 static int ep_historic_solid[] =
3829 EL_EXPANDABLE_WALL_HORIZONTAL,
3830 EL_EXPANDABLE_WALL_VERTICAL,
3831 EL_EXPANDABLE_WALL_ANY,
3832 EL_BD_EXPANDABLE_WALL,
3845 EL_QUICKSAND_FILLING,
3846 EL_QUICKSAND_EMPTYING,
3848 EL_MAGIC_WALL_ACTIVE,
3849 EL_MAGIC_WALL_EMPTYING,
3850 EL_MAGIC_WALL_FILLING,
3854 EL_BD_MAGIC_WALL_ACTIVE,
3855 EL_BD_MAGIC_WALL_EMPTYING,
3856 EL_BD_MAGIC_WALL_FULL,
3857 EL_BD_MAGIC_WALL_FILLING,
3858 EL_BD_MAGIC_WALL_DEAD,
3867 EL_SP_TERMINAL_ACTIVE,
3871 EL_INVISIBLE_WALL_ACTIVE,
3872 EL_SWITCHGATE_SWITCH_UP,
3873 EL_SWITCHGATE_SWITCH_DOWN,
3874 EL_DC_SWITCHGATE_SWITCH_UP,
3875 EL_DC_SWITCHGATE_SWITCH_DOWN,
3877 EL_TIMEGATE_SWITCH_ACTIVE,
3878 EL_DC_TIMEGATE_SWITCH,
3879 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3891 /* the following elements are a direct copy of "indestructible" elements,
3892 except "EL_ACID", which is "indestructible", but not "solid"! */
3897 EL_ACID_POOL_TOPLEFT,
3898 EL_ACID_POOL_TOPRIGHT,
3899 EL_ACID_POOL_BOTTOMLEFT,
3900 EL_ACID_POOL_BOTTOM,
3901 EL_ACID_POOL_BOTTOMRIGHT,
3902 EL_SP_HARDWARE_GRAY,
3903 EL_SP_HARDWARE_GREEN,
3904 EL_SP_HARDWARE_BLUE,
3906 EL_SP_HARDWARE_YELLOW,
3907 EL_SP_HARDWARE_BASE_1,
3908 EL_SP_HARDWARE_BASE_2,
3909 EL_SP_HARDWARE_BASE_3,
3910 EL_SP_HARDWARE_BASE_4,
3911 EL_SP_HARDWARE_BASE_5,
3912 EL_SP_HARDWARE_BASE_6,
3913 EL_INVISIBLE_STEELWALL,
3914 EL_INVISIBLE_STEELWALL_ACTIVE,
3915 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3916 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3917 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3918 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3919 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3920 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3921 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3922 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3923 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3924 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3925 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3926 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3928 EL_LIGHT_SWITCH_ACTIVE,
3929 EL_SIGN_EXCLAMATION,
3930 EL_SIGN_RADIOACTIVITY,
3937 EL_SIGN_ENTRY_FORBIDDEN,
3938 EL_SIGN_EMERGENCY_EXIT,
3946 EL_STEEL_EXIT_CLOSED,
3948 EL_DC_STEELWALL_1_LEFT,
3949 EL_DC_STEELWALL_1_RIGHT,
3950 EL_DC_STEELWALL_1_TOP,
3951 EL_DC_STEELWALL_1_BOTTOM,
3952 EL_DC_STEELWALL_1_HORIZONTAL,
3953 EL_DC_STEELWALL_1_VERTICAL,
3954 EL_DC_STEELWALL_1_TOPLEFT,
3955 EL_DC_STEELWALL_1_TOPRIGHT,
3956 EL_DC_STEELWALL_1_BOTTOMLEFT,
3957 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3958 EL_DC_STEELWALL_1_TOPLEFT_2,
3959 EL_DC_STEELWALL_1_TOPRIGHT_2,
3960 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3961 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3962 EL_DC_STEELWALL_2_LEFT,
3963 EL_DC_STEELWALL_2_RIGHT,
3964 EL_DC_STEELWALL_2_TOP,
3965 EL_DC_STEELWALL_2_BOTTOM,
3966 EL_DC_STEELWALL_2_HORIZONTAL,
3967 EL_DC_STEELWALL_2_VERTICAL,
3968 EL_DC_STEELWALL_2_MIDDLE,
3969 EL_DC_STEELWALL_2_SINGLE,
3970 EL_STEELWALL_SLIPPERY,
3984 EL_GATE_1_GRAY_ACTIVE,
3985 EL_GATE_2_GRAY_ACTIVE,
3986 EL_GATE_3_GRAY_ACTIVE,
3987 EL_GATE_4_GRAY_ACTIVE,
3996 EL_EM_GATE_1_GRAY_ACTIVE,
3997 EL_EM_GATE_2_GRAY_ACTIVE,
3998 EL_EM_GATE_3_GRAY_ACTIVE,
3999 EL_EM_GATE_4_GRAY_ACTIVE,
4001 EL_SWITCHGATE_OPENING,
4002 EL_SWITCHGATE_CLOSED,
4003 EL_SWITCHGATE_CLOSING,
4005 EL_TIMEGATE_OPENING,
4007 EL_TIMEGATE_CLOSING,
4011 EL_TUBE_VERTICAL_LEFT,
4012 EL_TUBE_VERTICAL_RIGHT,
4013 EL_TUBE_HORIZONTAL_UP,
4014 EL_TUBE_HORIZONTAL_DOWN,
4023 static int ep_classic_enemy[] =
4040 static int ep_belt[] =
4042 EL_CONVEYOR_BELT_1_LEFT,
4043 EL_CONVEYOR_BELT_1_MIDDLE,
4044 EL_CONVEYOR_BELT_1_RIGHT,
4045 EL_CONVEYOR_BELT_2_LEFT,
4046 EL_CONVEYOR_BELT_2_MIDDLE,
4047 EL_CONVEYOR_BELT_2_RIGHT,
4048 EL_CONVEYOR_BELT_3_LEFT,
4049 EL_CONVEYOR_BELT_3_MIDDLE,
4050 EL_CONVEYOR_BELT_3_RIGHT,
4051 EL_CONVEYOR_BELT_4_LEFT,
4052 EL_CONVEYOR_BELT_4_MIDDLE,
4053 EL_CONVEYOR_BELT_4_RIGHT,
4058 static int ep_belt_active[] =
4060 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
4061 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
4062 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
4063 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
4064 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
4065 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
4066 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
4067 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
4068 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
4069 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
4070 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
4071 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
4076 static int ep_belt_switch[] =
4078 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4079 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4080 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4081 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4082 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4083 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4084 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4085 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4086 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4087 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4088 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4089 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4094 static int ep_tube[] =
4101 EL_TUBE_HORIZONTAL_UP,
4102 EL_TUBE_HORIZONTAL_DOWN,
4104 EL_TUBE_VERTICAL_LEFT,
4105 EL_TUBE_VERTICAL_RIGHT,
4111 static int ep_acid_pool[] =
4113 EL_ACID_POOL_TOPLEFT,
4114 EL_ACID_POOL_TOPRIGHT,
4115 EL_ACID_POOL_BOTTOMLEFT,
4116 EL_ACID_POOL_BOTTOM,
4117 EL_ACID_POOL_BOTTOMRIGHT,
4122 static int ep_keygate[] =
4132 EL_GATE_1_GRAY_ACTIVE,
4133 EL_GATE_2_GRAY_ACTIVE,
4134 EL_GATE_3_GRAY_ACTIVE,
4135 EL_GATE_4_GRAY_ACTIVE,
4144 EL_EM_GATE_1_GRAY_ACTIVE,
4145 EL_EM_GATE_2_GRAY_ACTIVE,
4146 EL_EM_GATE_3_GRAY_ACTIVE,
4147 EL_EM_GATE_4_GRAY_ACTIVE,
4156 EL_EMC_GATE_5_GRAY_ACTIVE,
4157 EL_EMC_GATE_6_GRAY_ACTIVE,
4158 EL_EMC_GATE_7_GRAY_ACTIVE,
4159 EL_EMC_GATE_8_GRAY_ACTIVE,
4161 EL_DC_GATE_WHITE_GRAY,
4162 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4167 static int ep_amoeboid[] =
4179 static int ep_amoebalive[] =
4190 static int ep_has_editor_content[] =
4196 EL_SOKOBAN_FIELD_PLAYER,
4213 static int ep_can_turn_each_move[] =
4215 /* !!! do something with this one !!! */
4219 static int ep_can_grow[] =
4233 static int ep_active_bomb[] =
4236 EL_EM_DYNAMITE_ACTIVE,
4237 EL_DYNABOMB_PLAYER_1_ACTIVE,
4238 EL_DYNABOMB_PLAYER_2_ACTIVE,
4239 EL_DYNABOMB_PLAYER_3_ACTIVE,
4240 EL_DYNABOMB_PLAYER_4_ACTIVE,
4241 EL_SP_DISK_RED_ACTIVE,
4246 static int ep_inactive[] =
4256 EL_QUICKSAND_FAST_EMPTY,
4279 EL_GATE_1_GRAY_ACTIVE,
4280 EL_GATE_2_GRAY_ACTIVE,
4281 EL_GATE_3_GRAY_ACTIVE,
4282 EL_GATE_4_GRAY_ACTIVE,
4291 EL_EM_GATE_1_GRAY_ACTIVE,
4292 EL_EM_GATE_2_GRAY_ACTIVE,
4293 EL_EM_GATE_3_GRAY_ACTIVE,
4294 EL_EM_GATE_4_GRAY_ACTIVE,
4303 EL_EMC_GATE_5_GRAY_ACTIVE,
4304 EL_EMC_GATE_6_GRAY_ACTIVE,
4305 EL_EMC_GATE_7_GRAY_ACTIVE,
4306 EL_EMC_GATE_8_GRAY_ACTIVE,
4308 EL_DC_GATE_WHITE_GRAY,
4309 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4310 EL_DC_GATE_FAKE_GRAY,
4313 EL_INVISIBLE_STEELWALL,
4321 EL_WALL_EMERALD_YELLOW,
4322 EL_DYNABOMB_INCREASE_NUMBER,
4323 EL_DYNABOMB_INCREASE_SIZE,
4324 EL_DYNABOMB_INCREASE_POWER,
4328 EL_SOKOBAN_FIELD_EMPTY,
4329 EL_SOKOBAN_FIELD_FULL,
4330 EL_WALL_EMERALD_RED,
4331 EL_WALL_EMERALD_PURPLE,
4332 EL_ACID_POOL_TOPLEFT,
4333 EL_ACID_POOL_TOPRIGHT,
4334 EL_ACID_POOL_BOTTOMLEFT,
4335 EL_ACID_POOL_BOTTOM,
4336 EL_ACID_POOL_BOTTOMRIGHT,
4340 EL_BD_MAGIC_WALL_DEAD,
4342 EL_DC_MAGIC_WALL_DEAD,
4343 EL_AMOEBA_TO_DIAMOND,
4351 EL_SP_GRAVITY_PORT_RIGHT,
4352 EL_SP_GRAVITY_PORT_DOWN,
4353 EL_SP_GRAVITY_PORT_LEFT,
4354 EL_SP_GRAVITY_PORT_UP,
4355 EL_SP_PORT_HORIZONTAL,
4356 EL_SP_PORT_VERTICAL,
4367 EL_SP_HARDWARE_GRAY,
4368 EL_SP_HARDWARE_GREEN,
4369 EL_SP_HARDWARE_BLUE,
4371 EL_SP_HARDWARE_YELLOW,
4372 EL_SP_HARDWARE_BASE_1,
4373 EL_SP_HARDWARE_BASE_2,
4374 EL_SP_HARDWARE_BASE_3,
4375 EL_SP_HARDWARE_BASE_4,
4376 EL_SP_HARDWARE_BASE_5,
4377 EL_SP_HARDWARE_BASE_6,
4378 EL_SP_GRAVITY_ON_PORT_LEFT,
4379 EL_SP_GRAVITY_ON_PORT_RIGHT,
4380 EL_SP_GRAVITY_ON_PORT_UP,
4381 EL_SP_GRAVITY_ON_PORT_DOWN,
4382 EL_SP_GRAVITY_OFF_PORT_LEFT,
4383 EL_SP_GRAVITY_OFF_PORT_RIGHT,
4384 EL_SP_GRAVITY_OFF_PORT_UP,
4385 EL_SP_GRAVITY_OFF_PORT_DOWN,
4386 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4387 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4388 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4389 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4390 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4391 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4392 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4393 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4394 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4395 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4396 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4397 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4398 EL_SIGN_EXCLAMATION,
4399 EL_SIGN_RADIOACTIVITY,
4406 EL_SIGN_ENTRY_FORBIDDEN,
4407 EL_SIGN_EMERGENCY_EXIT,
4415 EL_DC_STEELWALL_1_LEFT,
4416 EL_DC_STEELWALL_1_RIGHT,
4417 EL_DC_STEELWALL_1_TOP,
4418 EL_DC_STEELWALL_1_BOTTOM,
4419 EL_DC_STEELWALL_1_HORIZONTAL,
4420 EL_DC_STEELWALL_1_VERTICAL,
4421 EL_DC_STEELWALL_1_TOPLEFT,
4422 EL_DC_STEELWALL_1_TOPRIGHT,
4423 EL_DC_STEELWALL_1_BOTTOMLEFT,
4424 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4425 EL_DC_STEELWALL_1_TOPLEFT_2,
4426 EL_DC_STEELWALL_1_TOPRIGHT_2,
4427 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4428 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4429 EL_DC_STEELWALL_2_LEFT,
4430 EL_DC_STEELWALL_2_RIGHT,
4431 EL_DC_STEELWALL_2_TOP,
4432 EL_DC_STEELWALL_2_BOTTOM,
4433 EL_DC_STEELWALL_2_HORIZONTAL,
4434 EL_DC_STEELWALL_2_VERTICAL,
4435 EL_DC_STEELWALL_2_MIDDLE,
4436 EL_DC_STEELWALL_2_SINGLE,
4437 EL_STEELWALL_SLIPPERY,
4442 EL_EMC_WALL_SLIPPERY_1,
4443 EL_EMC_WALL_SLIPPERY_2,
4444 EL_EMC_WALL_SLIPPERY_3,
4445 EL_EMC_WALL_SLIPPERY_4,
4466 static int ep_em_slippery_wall[] =
4471 static int ep_gfx_crumbled[] =
4482 static int ep_editor_cascade_active[] =
4484 EL_INTERNAL_CASCADE_BD_ACTIVE,
4485 EL_INTERNAL_CASCADE_EM_ACTIVE,
4486 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4487 EL_INTERNAL_CASCADE_RND_ACTIVE,
4488 EL_INTERNAL_CASCADE_SB_ACTIVE,
4489 EL_INTERNAL_CASCADE_SP_ACTIVE,
4490 EL_INTERNAL_CASCADE_DC_ACTIVE,
4491 EL_INTERNAL_CASCADE_DX_ACTIVE,
4492 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4493 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4494 EL_INTERNAL_CASCADE_CE_ACTIVE,
4495 EL_INTERNAL_CASCADE_GE_ACTIVE,
4496 EL_INTERNAL_CASCADE_REF_ACTIVE,
4497 EL_INTERNAL_CASCADE_USER_ACTIVE,
4498 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4503 static int ep_editor_cascade_inactive[] =
4505 EL_INTERNAL_CASCADE_BD,
4506 EL_INTERNAL_CASCADE_EM,
4507 EL_INTERNAL_CASCADE_EMC,
4508 EL_INTERNAL_CASCADE_RND,
4509 EL_INTERNAL_CASCADE_SB,
4510 EL_INTERNAL_CASCADE_SP,
4511 EL_INTERNAL_CASCADE_DC,
4512 EL_INTERNAL_CASCADE_DX,
4513 EL_INTERNAL_CASCADE_CHARS,
4514 EL_INTERNAL_CASCADE_STEEL_CHARS,
4515 EL_INTERNAL_CASCADE_CE,
4516 EL_INTERNAL_CASCADE_GE,
4517 EL_INTERNAL_CASCADE_REF,
4518 EL_INTERNAL_CASCADE_USER,
4519 EL_INTERNAL_CASCADE_DYNAMIC,
4524 static int ep_obsolete[] =
4528 EL_EM_KEY_1_FILE_OBSOLETE,
4529 EL_EM_KEY_2_FILE_OBSOLETE,
4530 EL_EM_KEY_3_FILE_OBSOLETE,
4531 EL_EM_KEY_4_FILE_OBSOLETE,
4532 EL_ENVELOPE_OBSOLETE,
4541 } element_properties[] =
4543 { ep_diggable, EP_DIGGABLE },
4544 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4545 { ep_dont_run_into, EP_DONT_RUN_INTO },
4546 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4547 { ep_dont_touch, EP_DONT_TOUCH },
4548 { ep_indestructible, EP_INDESTRUCTIBLE },
4549 { ep_slippery, EP_SLIPPERY },
4550 { ep_can_change, EP_CAN_CHANGE },
4551 { ep_can_move, EP_CAN_MOVE },
4552 { ep_can_fall, EP_CAN_FALL },
4553 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4554 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4555 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4556 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4557 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4558 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4559 { ep_walkable_over, EP_WALKABLE_OVER },
4560 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4561 { ep_walkable_under, EP_WALKABLE_UNDER },
4562 { ep_passable_over, EP_PASSABLE_OVER },
4563 { ep_passable_inside, EP_PASSABLE_INSIDE },
4564 { ep_passable_under, EP_PASSABLE_UNDER },
4565 { ep_droppable, EP_DROPPABLE },
4566 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4567 { ep_pushable, EP_PUSHABLE },
4568 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4569 { ep_protected, EP_PROTECTED },
4570 { ep_throwable, EP_THROWABLE },
4571 { ep_can_explode, EP_CAN_EXPLODE },
4572 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4574 { ep_player, EP_PLAYER },
4575 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4576 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4577 { ep_switchable, EP_SWITCHABLE },
4578 { ep_bd_element, EP_BD_ELEMENT },
4579 { ep_sp_element, EP_SP_ELEMENT },
4580 { ep_sb_element, EP_SB_ELEMENT },
4582 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4583 { ep_food_penguin, EP_FOOD_PENGUIN },
4584 { ep_food_pig, EP_FOOD_PIG },
4585 { ep_historic_wall, EP_HISTORIC_WALL },
4586 { ep_historic_solid, EP_HISTORIC_SOLID },
4587 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4588 { ep_belt, EP_BELT },
4589 { ep_belt_active, EP_BELT_ACTIVE },
4590 { ep_belt_switch, EP_BELT_SWITCH },
4591 { ep_tube, EP_TUBE },
4592 { ep_acid_pool, EP_ACID_POOL },
4593 { ep_keygate, EP_KEYGATE },
4594 { ep_amoeboid, EP_AMOEBOID },
4595 { ep_amoebalive, EP_AMOEBALIVE },
4596 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4597 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4598 { ep_can_grow, EP_CAN_GROW },
4599 { ep_active_bomb, EP_ACTIVE_BOMB },
4600 { ep_inactive, EP_INACTIVE },
4602 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4604 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4606 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4607 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4609 { ep_obsolete, EP_OBSOLETE },
4616 /* always start with reliable default values (element has no properties) */
4617 /* (but never initialize clipboard elements after the very first time) */
4618 /* (to be able to use clipboard elements between several levels) */
4619 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4620 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4621 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4622 SET_PROPERTY(i, j, FALSE);
4624 /* set all base element properties from above array definitions */
4625 for (i = 0; element_properties[i].elements != NULL; i++)
4626 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4627 SET_PROPERTY((element_properties[i].elements)[j],
4628 element_properties[i].property, TRUE);
4630 /* copy properties to some elements that are only stored in level file */
4631 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4632 for (j = 0; copy_properties[j][0] != -1; j++)
4633 if (HAS_PROPERTY(copy_properties[j][0], i))
4634 for (k = 1; k <= 4; k++)
4635 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4637 /* set static element properties that are not listed in array definitions */
4638 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4639 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4641 clipboard_elements_initialized = TRUE;
4644 void InitElementPropertiesEngine(int engine_version)
4646 static int no_wall_properties[] =
4649 EP_COLLECTIBLE_ONLY,
4651 EP_DONT_COLLIDE_WITH,
4654 EP_CAN_SMASH_PLAYER,
4655 EP_CAN_SMASH_ENEMIES,
4656 EP_CAN_SMASH_EVERYTHING,
4661 EP_FOOD_DARK_YAMYAM,
4677 /* important: after initialization in InitElementPropertiesStatic(), the
4678 elements are not again initialized to a default value; therefore all
4679 changes have to make sure that they leave the element with a defined
4680 property (which means that conditional property changes must be set to
4681 a reliable default value before) */
4683 /* resolve group elements */
4684 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4685 ResolveGroupElement(EL_GROUP_START + i);
4687 /* set all special, combined or engine dependent element properties */
4688 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4690 /* do not change (already initialized) clipboard elements here */
4691 if (IS_CLIPBOARD_ELEMENT(i))
4694 /* ---------- INACTIVE ------------------------------------------------- */
4695 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4696 i <= EL_CHAR_END) ||
4697 (i >= EL_STEEL_CHAR_START &&
4698 i <= EL_STEEL_CHAR_END)));
4700 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4701 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4702 IS_WALKABLE_INSIDE(i) ||
4703 IS_WALKABLE_UNDER(i)));
4705 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4706 IS_PASSABLE_INSIDE(i) ||
4707 IS_PASSABLE_UNDER(i)));
4709 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4710 IS_PASSABLE_OVER(i)));
4712 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4713 IS_PASSABLE_INSIDE(i)));
4715 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4716 IS_PASSABLE_UNDER(i)));
4718 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4721 /* ---------- COLLECTIBLE ---------------------------------------------- */
4722 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4726 /* ---------- SNAPPABLE ------------------------------------------------ */
4727 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4728 IS_COLLECTIBLE(i) ||
4732 /* ---------- WALL ----------------------------------------------------- */
4733 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4735 for (j = 0; no_wall_properties[j] != -1; j++)
4736 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4737 i >= EL_FIRST_RUNTIME_UNREAL)
4738 SET_PROPERTY(i, EP_WALL, FALSE);
4740 if (IS_HISTORIC_WALL(i))
4741 SET_PROPERTY(i, EP_WALL, TRUE);
4743 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4744 if (engine_version < VERSION_IDENT(2,2,0,0))
4745 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4747 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4749 !IS_COLLECTIBLE(i)));
4751 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4752 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4753 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4755 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4756 IS_INDESTRUCTIBLE(i)));
4758 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4760 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4761 else if (engine_version < VERSION_IDENT(2,2,0,0))
4762 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4764 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4768 if (IS_CUSTOM_ELEMENT(i))
4770 /* these are additional properties which are initially false when set */
4772 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4774 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4775 if (DONT_COLLIDE_WITH(i))
4776 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4778 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4779 if (CAN_SMASH_EVERYTHING(i))
4780 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4781 if (CAN_SMASH_ENEMIES(i))
4782 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4785 /* ---------- CAN_SMASH ------------------------------------------------ */
4786 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4787 CAN_SMASH_ENEMIES(i) ||
4788 CAN_SMASH_EVERYTHING(i)));
4790 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4791 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4792 EXPLODES_BY_FIRE(i)));
4794 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4795 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4796 EXPLODES_SMASHED(i)));
4798 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4799 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4800 EXPLODES_IMPACT(i)));
4802 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4803 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4805 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4806 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4807 i == EL_BLACK_ORB));
4809 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4810 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4812 IS_CUSTOM_ELEMENT(i)));
4814 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4815 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4816 i == EL_SP_ELECTRON));
4818 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4819 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4820 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4821 getMoveIntoAcidProperty(&level, i));
4823 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4824 if (MAYBE_DONT_COLLIDE_WITH(i))
4825 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4826 getDontCollideWithProperty(&level, i));
4828 /* ---------- SP_PORT -------------------------------------------------- */
4829 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4830 IS_PASSABLE_INSIDE(i)));
4832 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4833 for (j = 0; j < level.num_android_clone_elements; j++)
4834 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4836 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4838 /* ---------- CAN_CHANGE ----------------------------------------------- */
4839 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4840 for (j = 0; j < element_info[i].num_change_pages; j++)
4841 if (element_info[i].change_page[j].can_change)
4842 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4844 /* ---------- HAS_ACTION ----------------------------------------------- */
4845 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4846 for (j = 0; j < element_info[i].num_change_pages; j++)
4847 if (element_info[i].change_page[j].has_action)
4848 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4850 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4851 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4854 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4856 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4857 element_info[i].crumbled[ACTION_DEFAULT] !=
4858 element_info[i].graphic[ACTION_DEFAULT]);
4860 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
4861 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4862 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
4865 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4866 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4867 IS_EDITOR_CASCADE_INACTIVE(i)));
4870 /* dynamically adjust element properties according to game engine version */
4872 static int ep_em_slippery_wall[] =
4877 EL_EXPANDABLE_WALL_HORIZONTAL,
4878 EL_EXPANDABLE_WALL_VERTICAL,
4879 EL_EXPANDABLE_WALL_ANY,
4880 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4881 EL_EXPANDABLE_STEELWALL_VERTICAL,
4882 EL_EXPANDABLE_STEELWALL_ANY,
4883 EL_EXPANDABLE_STEELWALL_GROWING,
4887 static int ep_em_explodes_by_fire[] =
4890 EL_EM_DYNAMITE_ACTIVE,
4895 /* special EM style gems behaviour */
4896 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4897 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4898 level.em_slippery_gems);
4900 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4901 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4902 (level.em_slippery_gems &&
4903 engine_version > VERSION_IDENT(2,0,1,0)));
4905 /* special EM style explosion behaviour regarding chain reactions */
4906 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4907 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4908 level.em_explodes_by_fire);
4911 /* this is needed because some graphics depend on element properties */
4912 if (game_status == GAME_MODE_PLAYING)
4913 InitElementGraphicInfo();
4916 void InitElementPropertiesAfterLoading(int engine_version)
4920 /* set some other uninitialized values of custom elements in older levels */
4921 if (engine_version < VERSION_IDENT(3,1,0,0))
4923 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4925 int element = EL_CUSTOM_START + i;
4927 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4929 element_info[element].explosion_delay = 17;
4930 element_info[element].ignition_delay = 8;
4935 void InitElementPropertiesGfxElement()
4939 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4941 struct ElementInfo *ei = &element_info[i];
4943 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4947 static void InitGlobal()
4952 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4954 /* check if element_name_info entry defined for each element in "main.h" */
4955 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4956 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4958 element_info[i].token_name = element_name_info[i].token_name;
4959 element_info[i].class_name = element_name_info[i].class_name;
4960 element_info[i].editor_description= element_name_info[i].editor_description;
4963 printf("%04d: %s\n", i, element_name_info[i].token_name);
4967 /* create hash from image config list */
4968 image_config_hash = newSetupFileHash();
4969 for (i = 0; image_config[i].token != NULL; i++)
4970 setHashEntry(image_config_hash,
4971 image_config[i].token,
4972 image_config[i].value);
4974 /* create hash from element token list */
4975 element_token_hash = newSetupFileHash();
4976 for (i = 0; element_name_info[i].token_name != NULL; i++)
4977 setHashEntry(element_token_hash,
4978 element_name_info[i].token_name,
4981 /* create hash from graphic token list */
4982 graphic_token_hash = newSetupFileHash();
4983 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4984 if (strSuffix(image_config[i].value, ".pcx") ||
4985 strSuffix(image_config[i].value, ".wav") ||
4986 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4987 setHashEntry(graphic_token_hash,
4988 image_config[i].token,
4989 int2str(graphic++, 0));
4991 /* create hash from font token list */
4992 font_token_hash = newSetupFileHash();
4993 for (i = 0; font_info[i].token_name != NULL; i++)
4994 setHashEntry(font_token_hash,
4995 font_info[i].token_name,
4998 /* always start with reliable default values (all elements) */
4999 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5000 ActiveElement[i] = i;
5002 /* now add all entries that have an active state (active elements) */
5003 for (i = 0; element_with_active_state[i].element != -1; i++)
5005 int element = element_with_active_state[i].element;
5006 int element_active = element_with_active_state[i].element_active;
5008 ActiveElement[element] = element_active;
5011 /* always start with reliable default values (all buttons) */
5012 for (i = 0; i < NUM_IMAGE_FILES; i++)
5013 ActiveButton[i] = i;
5015 /* now add all entries that have an active state (active buttons) */
5016 for (i = 0; button_with_active_state[i].button != -1; i++)
5018 int button = button_with_active_state[i].button;
5019 int button_active = button_with_active_state[i].button_active;
5021 ActiveButton[button] = button_active;
5024 /* always start with reliable default values (all fonts) */
5025 for (i = 0; i < NUM_FONTS; i++)
5028 /* now add all entries that have an active state (active fonts) */
5029 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
5031 int font = font_with_active_state[i].font_nr;
5032 int font_active = font_with_active_state[i].font_nr_active;
5034 ActiveFont[font] = font_active;
5037 global.autoplay_leveldir = NULL;
5038 global.convert_leveldir = NULL;
5039 global.create_images_dir = NULL;
5041 global.frames_per_second = 0;
5042 global.fps_slowdown = FALSE;
5043 global.fps_slowdown_factor = 1;
5045 global.border_status = GAME_MODE_MAIN;
5047 global.fading_status = GAME_MODE_MAIN;
5048 global.fading_type = TYPE_ENTER_MENU;
5052 void Execute_Command(char *command)
5056 if (strEqual(command, "print graphicsinfo.conf"))
5058 printf("# You can configure additional/alternative image files here.\n");
5059 printf("# (The entries below are default and therefore commented out.)\n");
5061 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
5063 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5066 for (i = 0; image_config[i].token != NULL; i++)
5067 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
5068 image_config[i].value));
5072 else if (strEqual(command, "print soundsinfo.conf"))
5074 printf("# You can configure additional/alternative sound files here.\n");
5075 printf("# (The entries below are default and therefore commented out.)\n");
5077 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
5079 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5082 for (i = 0; sound_config[i].token != NULL; i++)
5083 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
5084 sound_config[i].value));
5088 else if (strEqual(command, "print musicinfo.conf"))
5090 printf("# You can configure additional/alternative music files here.\n");
5091 printf("# (The entries below are default and therefore commented out.)\n");
5093 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
5095 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5098 for (i = 0; music_config[i].token != NULL; i++)
5099 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
5100 music_config[i].value));
5104 else if (strEqual(command, "print editorsetup.conf"))
5106 printf("# You can configure your personal editor element list here.\n");
5107 printf("# (The entries below are default and therefore commented out.)\n");
5110 /* this is needed to be able to check element list for cascade elements */
5111 InitElementPropertiesStatic();
5112 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5114 PrintEditorElementList();
5118 else if (strEqual(command, "print helpanim.conf"))
5120 printf("# You can configure different element help animations here.\n");
5121 printf("# (The entries below are default and therefore commented out.)\n");
5124 for (i = 0; helpanim_config[i].token != NULL; i++)
5126 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
5127 helpanim_config[i].value));
5129 if (strEqual(helpanim_config[i].token, "end"))
5135 else if (strEqual(command, "print helptext.conf"))
5137 printf("# You can configure different element help text here.\n");
5138 printf("# (The entries below are default and therefore commented out.)\n");
5141 for (i = 0; helptext_config[i].token != NULL; i++)
5142 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
5143 helptext_config[i].value));
5147 else if (strPrefix(command, "dump level "))
5149 char *filename = &command[11];
5151 if (!fileExists(filename))
5152 Error(ERR_EXIT, "cannot open file '%s'", filename);
5154 LoadLevelFromFilename(&level, filename);
5159 else if (strPrefix(command, "dump tape "))
5161 char *filename = &command[10];
5163 if (!fileExists(filename))
5164 Error(ERR_EXIT, "cannot open file '%s'", filename);
5166 LoadTapeFromFilename(filename);
5171 else if (strPrefix(command, "autoplay "))
5173 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
5175 while (*str_ptr != '\0') /* continue parsing string */
5177 /* cut leading whitespace from string, replace it by string terminator */
5178 while (*str_ptr == ' ' || *str_ptr == '\t')
5181 if (*str_ptr == '\0') /* end of string reached */
5184 if (global.autoplay_leveldir == NULL) /* read level set string */
5186 global.autoplay_leveldir = str_ptr;
5187 global.autoplay_all = TRUE; /* default: play all tapes */
5189 for (i = 0; i < MAX_TAPES_PER_SET; i++)
5190 global.autoplay_level[i] = FALSE;
5192 else /* read level number string */
5194 int level_nr = atoi(str_ptr); /* get level_nr value */
5196 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5197 global.autoplay_level[level_nr] = TRUE;
5199 global.autoplay_all = FALSE;
5202 /* advance string pointer to the next whitespace (or end of string) */
5203 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5207 else if (strPrefix(command, "convert "))
5209 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
5210 char *str_ptr = strchr(str_copy, ' ');
5212 global.convert_leveldir = str_copy;
5213 global.convert_level_nr = -1;
5215 if (str_ptr != NULL) /* level number follows */
5217 *str_ptr++ = '\0'; /* terminate leveldir string */
5218 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
5221 else if (strPrefix(command, "create images "))
5223 #if defined(TARGET_SDL)
5224 global.create_images_dir = getStringCopy(&command[14]);
5226 if (access(global.create_images_dir, W_OK) != 0)
5227 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
5228 global.create_images_dir);
5230 Error(ERR_EXIT, "command only available for SDL target");
5235 #if defined(TARGET_SDL)
5236 else if (strEqual(command, "SDL_ListModes"))
5241 SDL_Init(SDL_INIT_VIDEO);
5243 /* get available fullscreen/hardware modes */
5244 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
5246 /* check if there are any modes available */
5249 printf("No modes available!\n");
5254 /* check if our resolution is restricted */
5255 if (modes == (SDL_Rect **)-1)
5257 printf("All resolutions available.\n");
5261 printf("Available Modes:\n");
5263 for(i = 0; modes[i]; i++)
5264 printf(" %d x %d\n", modes[i]->w, modes[i]->h);
5274 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
5278 static void InitSetup()
5280 LoadSetup(); /* global setup info */
5282 /* set some options from setup file */
5284 if (setup.options.verbose)
5285 options.verbose = TRUE;
5288 static void InitGameInfo()
5290 game.restart_level = FALSE;
5293 static void InitPlayerInfo()
5297 /* choose default local player */
5298 local_player = &stored_player[0];
5300 for (i = 0; i < MAX_PLAYERS; i++)
5301 stored_player[i].connected = FALSE;
5303 local_player->connected = TRUE;
5306 static void InitArtworkInfo()
5311 static char *get_string_in_brackets(char *string)
5313 char *string_in_brackets = checked_malloc(strlen(string) + 3);
5315 sprintf(string_in_brackets, "[%s]", string);
5317 return string_in_brackets;
5320 static char *get_level_id_suffix(int id_nr)
5322 char *id_suffix = checked_malloc(1 + 3 + 1);
5324 if (id_nr < 0 || id_nr > 999)
5327 sprintf(id_suffix, ".%03d", id_nr);
5333 static char *get_element_class_token(int element)
5335 char *element_class_name = element_info[element].class_name;
5336 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
5338 sprintf(element_class_token, "[%s]", element_class_name);
5340 return element_class_token;
5343 static char *get_action_class_token(int action)
5345 char *action_class_name = &element_action_info[action].suffix[1];
5346 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
5348 sprintf(action_class_token, "[%s]", action_class_name);
5350 return action_class_token;
5354 static void InitArtworkConfig()
5356 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
5357 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
5358 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
5359 static char *action_id_suffix[NUM_ACTIONS + 1];
5360 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5361 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5362 static char *level_id_suffix[MAX_LEVELS + 1];
5363 static char *dummy[1] = { NULL };
5364 static char *ignore_generic_tokens[] =
5370 static char **ignore_image_tokens;
5371 static char **ignore_sound_tokens;
5372 static char **ignore_music_tokens;
5373 int num_ignore_generic_tokens;
5374 int num_ignore_image_tokens;
5375 int num_ignore_sound_tokens;
5376 int num_ignore_music_tokens;
5379 /* dynamically determine list of generic tokens to be ignored */
5380 num_ignore_generic_tokens = 0;
5381 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5382 num_ignore_generic_tokens++;
5384 /* dynamically determine list of image tokens to be ignored */
5385 num_ignore_image_tokens = num_ignore_generic_tokens;
5386 for (i = 0; image_config_vars[i].token != NULL; i++)
5387 num_ignore_image_tokens++;
5388 ignore_image_tokens =
5389 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5390 for (i = 0; i < num_ignore_generic_tokens; i++)
5391 ignore_image_tokens[i] = ignore_generic_tokens[i];
5392 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5393 ignore_image_tokens[num_ignore_generic_tokens + i] =
5394 image_config_vars[i].token;
5395 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5397 /* dynamically determine list of sound tokens to be ignored */
5398 num_ignore_sound_tokens = num_ignore_generic_tokens;
5399 ignore_sound_tokens =
5400 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5401 for (i = 0; i < num_ignore_generic_tokens; i++)
5402 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5403 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5405 /* dynamically determine list of music tokens to be ignored */
5406 num_ignore_music_tokens = num_ignore_generic_tokens;
5407 ignore_music_tokens =
5408 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5409 for (i = 0; i < num_ignore_generic_tokens; i++)
5410 ignore_music_tokens[i] = ignore_generic_tokens[i];
5411 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5413 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5414 image_id_prefix[i] = element_info[i].token_name;
5415 for (i = 0; i < NUM_FONTS; i++)
5416 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5417 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
5419 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5420 sound_id_prefix[i] = element_info[i].token_name;
5421 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5422 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5423 get_string_in_brackets(element_info[i].class_name);
5424 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
5426 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5427 music_id_prefix[i] = music_prefix_info[i].prefix;
5428 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
5430 for (i = 0; i < NUM_ACTIONS; i++)
5431 action_id_suffix[i] = element_action_info[i].suffix;
5432 action_id_suffix[NUM_ACTIONS] = NULL;
5434 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5435 direction_id_suffix[i] = element_direction_info[i].suffix;
5436 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5438 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5439 special_id_suffix[i] = special_suffix_info[i].suffix;
5440 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5442 for (i = 0; i < MAX_LEVELS; i++)
5443 level_id_suffix[i] = get_level_id_suffix(i);
5444 level_id_suffix[MAX_LEVELS] = NULL;
5446 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5447 image_id_prefix, action_id_suffix, direction_id_suffix,
5448 special_id_suffix, ignore_image_tokens);
5449 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5450 sound_id_prefix, action_id_suffix, dummy,
5451 special_id_suffix, ignore_sound_tokens);
5452 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5453 music_id_prefix, special_id_suffix, level_id_suffix,
5454 dummy, ignore_music_tokens);
5457 static void InitMixer()
5466 struct GraphicInfo *graphic_info_last = graphic_info;
5467 char *filename_font_initial = NULL;
5468 char *filename_anim_initial = NULL;
5469 Bitmap *bitmap_font_initial = NULL;
5473 /* determine settings for initial font (for displaying startup messages) */
5474 for (i = 0; image_config[i].token != NULL; i++)
5476 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5478 char font_token[128];
5481 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5482 len_font_token = strlen(font_token);
5484 if (strEqual(image_config[i].token, font_token))
5485 filename_font_initial = image_config[i].value;
5486 else if (strlen(image_config[i].token) > len_font_token &&
5487 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5489 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5490 font_initial[j].src_x = atoi(image_config[i].value);
5491 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5492 font_initial[j].src_y = atoi(image_config[i].value);
5493 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5494 font_initial[j].width = atoi(image_config[i].value);
5495 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5496 font_initial[j].height = atoi(image_config[i].value);
5501 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5503 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5504 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5507 if (filename_font_initial == NULL) /* should not happen */
5508 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5510 /* create additional image buffers for double-buffering and cross-fading */
5511 bitmap_db_cross = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5512 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
5513 bitmap_db_panel = CreateBitmap(DXSIZE, DYSIZE, DEFAULT_DEPTH);
5514 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
5515 bitmap_db_toons = CreateBitmap(FULL_SXSIZE, FULL_SYSIZE, DEFAULT_DEPTH);
5517 /* initialize screen properties */
5518 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5519 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5521 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5522 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5523 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5524 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5525 InitGfxCustomArtworkInfo();
5527 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5529 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5530 font_initial[j].bitmap = bitmap_font_initial;
5532 InitFontGraphicInfo();
5534 font_height = getFontHeight(FC_RED);
5537 DrawInitText(getWindowTitleString(), 20, FC_YELLOW);
5539 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
5541 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
5542 DrawInitText(PROGRAM_WEBSITE_STRING, WIN_YSIZE - 20 - font_height, FC_RED);
5544 DrawInitText("Loading graphics", 120, FC_GREEN);
5548 /* initialize busy animation with default values */
5549 int parameter[NUM_GFX_ARGS];
5550 for (i = 0; i < NUM_GFX_ARGS; i++)
5551 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5552 image_config_suffix[i].token,
5553 image_config_suffix[i].type);
5555 for (i = 0; i < NUM_GFX_ARGS; i++)
5556 printf("::: '%s' => %d\n", image_config_suffix[i].token, parameter[i]);
5560 /* determine settings for busy animation (when displaying startup messages) */
5561 for (i = 0; image_config[i].token != NULL; i++)
5563 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5564 int len_anim_token = strlen(anim_token);
5566 if (strEqual(image_config[i].token, anim_token))
5567 filename_anim_initial = image_config[i].value;
5568 else if (strlen(image_config[i].token) > len_anim_token &&
5569 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5572 for (j = 0; image_config_suffix[j].token != NULL; j++)
5574 if (strEqual(&image_config[i].token[len_anim_token],
5575 image_config_suffix[j].token))
5577 get_graphic_parameter_value(image_config[i].value,
5578 image_config_suffix[j].token,
5579 image_config_suffix[j].type);
5582 if (strEqual(&image_config[i].token[len_anim_token], ".x"))
5583 anim_initial.src_x = atoi(image_config[i].value);
5584 else if (strEqual(&image_config[i].token[len_anim_token], ".y"))
5585 anim_initial.src_y = atoi(image_config[i].value);
5586 else if (strEqual(&image_config[i].token[len_anim_token], ".width"))
5587 anim_initial.width = atoi(image_config[i].value);
5588 else if (strEqual(&image_config[i].token[len_anim_token], ".height"))
5589 anim_initial.height = atoi(image_config[i].value);
5590 else if (strEqual(&image_config[i].token[len_anim_token], ".frames"))
5591 anim_initial.anim_frames = atoi(image_config[i].value);
5592 else if (strEqual(&image_config[i].token[len_anim_token],
5593 ".frames_per_line"))
5594 anim_initial.anim_frames_per_line = atoi(image_config[i].value);
5595 else if (strEqual(&image_config[i].token[len_anim_token], ".delay"))
5596 anim_initial.anim_delay = atoi(image_config[i].value);
5601 #if defined(CREATE_SPECIAL_EDITION_RND_JUE)
5602 filename_anim_initial = "loading.pcx";
5604 parameter[GFX_ARG_X] = 0;
5605 parameter[GFX_ARG_Y] = 0;
5606 parameter[GFX_ARG_WIDTH] = 128;
5607 parameter[GFX_ARG_HEIGHT] = 40;
5608 parameter[GFX_ARG_FRAMES] = 32;
5609 parameter[GFX_ARG_DELAY] = 4;
5610 parameter[GFX_ARG_FRAMES_PER_LINE] = ARG_UNDEFINED_VALUE;
5613 if (filename_anim_initial == NULL) /* should not happen */
5614 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5616 anim_initial.bitmap = LoadCustomImage(filename_anim_initial);
5618 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
5620 set_graphic_parameters_ext(0, parameter, anim_initial.bitmap);
5623 printf("::: INIT_GFX: anim_frames_per_line == %d [%d / %d] [%d, %d]\n",
5624 graphic_info[0].anim_frames_per_line,
5625 get_scaled_graphic_width(0),
5626 graphic_info[0].width,
5627 getOriginalImageWidthFromImageID(0),
5628 graphic_info[0].scale_up_factor);
5631 graphic_info = graphic_info_last;
5633 init.busy.width = anim_initial.width;
5634 init.busy.height = anim_initial.height;
5636 InitMenuDesignSettings_Static();
5637 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5641 void RedrawBackground()
5643 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
5644 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
5646 redraw_mask = REDRAW_ALL;
5649 void InitGfxBackground()
5653 fieldbuffer = bitmap_db_field;
5654 SetDrawtoField(DRAW_BACKBUFFER);
5657 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5661 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
5662 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
5665 for (x = 0; x < MAX_BUF_XSIZE; x++)
5666 for (y = 0; y < MAX_BUF_YSIZE; y++)
5669 redraw_mask = REDRAW_ALL;
5672 static void InitLevelInfo()
5674 LoadLevelInfo(); /* global level info */
5675 LoadLevelSetup_LastSeries(); /* last played series info */
5676 LoadLevelSetup_SeriesInfo(); /* last played level info */
5679 static void InitLevelArtworkInfo()
5681 LoadLevelArtworkInfo();
5684 static void InitImages()
5686 print_timestamp_init("InitImages");
5689 printf("::: leveldir_current->identifier == '%s'\n",
5690 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5691 printf("::: leveldir_current->graphics_path == '%s'\n",
5692 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5693 printf("::: leveldir_current->graphics_set == '%s'\n",
5694 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5695 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5696 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5699 setLevelArtworkDir(artwork.gfx_first);
5702 printf("::: leveldir_current->identifier == '%s'\n",
5703 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5704 printf("::: leveldir_current->graphics_path == '%s'\n",
5705 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5706 printf("::: leveldir_current->graphics_set == '%s'\n",
5707 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5708 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5709 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5713 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5714 leveldir_current->identifier,
5715 artwork.gfx_current_identifier,
5716 artwork.gfx_current->identifier,
5717 leveldir_current->graphics_set,
5718 leveldir_current->graphics_path);
5721 UPDATE_BUSY_STATE();
5723 ReloadCustomImages();
5724 print_timestamp_time("ReloadCustomImages");
5726 UPDATE_BUSY_STATE();
5728 LoadCustomElementDescriptions();
5729 print_timestamp_time("LoadCustomElementDescriptions");
5731 UPDATE_BUSY_STATE();
5733 LoadMenuDesignSettings();
5734 print_timestamp_time("LoadMenuDesignSettings");
5736 UPDATE_BUSY_STATE();
5738 ReinitializeGraphics();
5739 print_timestamp_time("ReinitializeGraphics");
5741 UPDATE_BUSY_STATE();
5743 print_timestamp_done("InitImages");
5746 static void InitSound(char *identifier)
5748 print_timestamp_init("InitSound");
5750 if (identifier == NULL)
5751 identifier = artwork.snd_current->identifier;
5753 /* set artwork path to send it to the sound server process */
5754 setLevelArtworkDir(artwork.snd_first);
5756 InitReloadCustomSounds(identifier);
5757 print_timestamp_time("InitReloadCustomSounds");
5759 ReinitializeSounds();
5760 print_timestamp_time("ReinitializeSounds");
5762 print_timestamp_done("InitSound");
5765 static void InitMusic(char *identifier)
5767 print_timestamp_init("InitMusic");
5769 if (identifier == NULL)
5770 identifier = artwork.mus_current->identifier;
5772 /* set artwork path to send it to the sound server process */
5773 setLevelArtworkDir(artwork.mus_first);
5775 InitReloadCustomMusic(identifier);
5776 print_timestamp_time("InitReloadCustomMusic");
5778 ReinitializeMusic();
5779 print_timestamp_time("ReinitializeMusic");
5781 print_timestamp_done("InitMusic");
5784 void InitNetworkServer()
5786 #if defined(NETWORK_AVALIABLE)
5790 if (!options.network)
5793 #if defined(NETWORK_AVALIABLE)
5794 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5796 if (!ConnectToServer(options.server_host, options.server_port))
5797 Error(ERR_EXIT, "cannot connect to network game server");
5799 SendToServer_PlayerName(setup.player_name);
5800 SendToServer_ProtocolVersion();
5803 SendToServer_NrWanted(nr_wanted);
5807 static boolean CheckArtworkConfigForCustomElements(char *filename)
5809 SetupFileHash *setup_file_hash;
5810 boolean redefined_ce_found = FALSE;
5812 /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */
5814 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5816 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5818 char *token = HASH_ITERATION_TOKEN(itr);
5820 if (strPrefix(token, "custom_"))
5822 redefined_ce_found = TRUE;
5827 END_HASH_ITERATION(setup_file_hash, itr)
5829 freeSetupFileHash(setup_file_hash);
5832 return redefined_ce_found;
5835 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5837 char *filename_base, *filename_local;
5838 boolean redefined_ce_found = FALSE;
5840 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5843 printf("::: leveldir_current->identifier == '%s'\n",
5844 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5845 printf("::: leveldir_current->graphics_path == '%s'\n",
5846 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5847 printf("::: leveldir_current->graphics_set == '%s'\n",
5848 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5849 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5850 leveldir_current == NULL ? "[NULL]" :
5851 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5854 /* first look for special artwork configured in level series config */
5855 filename_base = getCustomArtworkLevelConfigFilename(type);
5858 printf("::: filename_base == '%s'\n", filename_base);
5861 if (fileExists(filename_base))
5862 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5864 filename_local = getCustomArtworkConfigFilename(type);
5867 printf("::: filename_local == '%s'\n", filename_local);
5870 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5871 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5874 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5877 return redefined_ce_found;
5880 static void InitOverrideArtwork()
5882 boolean redefined_ce_found = FALSE;
5884 /* to check if this level set redefines any CEs, do not use overriding */
5885 gfx.override_level_graphics = FALSE;
5886 gfx.override_level_sounds = FALSE;
5887 gfx.override_level_music = FALSE;
5889 /* now check if this level set has definitions for custom elements */
5890 if (setup.override_level_graphics == AUTO ||
5891 setup.override_level_sounds == AUTO ||
5892 setup.override_level_music == AUTO)
5893 redefined_ce_found =
5894 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5895 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5896 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5899 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5902 if (redefined_ce_found)
5904 /* this level set has CE definitions: change "AUTO" to "FALSE" */
5905 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5906 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
5907 gfx.override_level_music = (setup.override_level_music == TRUE);
5911 /* this level set has no CE definitions: change "AUTO" to "TRUE" */
5912 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5913 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
5914 gfx.override_level_music = (setup.override_level_music != FALSE);
5918 printf("::: => %d, %d, %d\n",
5919 gfx.override_level_graphics,
5920 gfx.override_level_sounds,
5921 gfx.override_level_music);
5925 static char *getNewArtworkIdentifier(int type)
5927 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5928 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5929 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5930 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5931 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5933 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5935 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
5937 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5938 char *leveldir_identifier = leveldir_current->identifier;
5940 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
5941 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5943 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
5945 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5946 char *artwork_current_identifier;
5947 char *artwork_new_identifier = NULL; /* default: nothing has changed */
5949 /* leveldir_current may be invalid (level group, parent link) */
5950 if (!validLevelSeries(leveldir_current))
5953 /* 1st step: determine artwork set to be activated in descending order:
5954 --------------------------------------------------------------------
5955 1. setup artwork (when configured to override everything else)
5956 2. artwork set configured in "levelinfo.conf" of current level set
5957 (artwork in level directory will have priority when loading later)
5958 3. artwork in level directory (stored in artwork sub-directory)
5959 4. setup artwork (currently configured in setup menu) */
5961 if (setup_override_artwork)
5962 artwork_current_identifier = setup_artwork_set;
5963 else if (leveldir_artwork_set != NULL)
5964 artwork_current_identifier = leveldir_artwork_set;
5965 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5966 artwork_current_identifier = leveldir_identifier;
5968 artwork_current_identifier = setup_artwork_set;
5971 /* 2nd step: check if it is really needed to reload artwork set
5972 ------------------------------------------------------------ */
5975 if (type == ARTWORK_TYPE_GRAPHICS)
5976 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
5977 artwork_new_identifier,
5978 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5979 artwork_current_identifier,
5980 leveldir_current->graphics_set,
5981 leveldir_current->identifier);
5984 /* ---------- reload if level set and also artwork set has changed ------- */
5985 if (leveldir_current_identifier[type] != leveldir_identifier &&
5986 (last_has_level_artwork_set[type] || has_level_artwork_set))
5987 artwork_new_identifier = artwork_current_identifier;
5989 leveldir_current_identifier[type] = leveldir_identifier;
5990 last_has_level_artwork_set[type] = has_level_artwork_set;
5993 if (type == ARTWORK_TYPE_GRAPHICS)
5994 printf("::: 1: '%s'\n", artwork_new_identifier);
5997 /* ---------- reload if "override artwork" setting has changed ----------- */
5998 if (last_override_level_artwork[type] != setup_override_artwork)
5999 artwork_new_identifier = artwork_current_identifier;
6001 last_override_level_artwork[type] = setup_override_artwork;
6004 if (type == ARTWORK_TYPE_GRAPHICS)
6005 printf("::: 2: '%s'\n", artwork_new_identifier);
6008 /* ---------- reload if current artwork identifier has changed ----------- */
6009 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
6010 artwork_current_identifier))
6011 artwork_new_identifier = artwork_current_identifier;
6013 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
6016 if (type == ARTWORK_TYPE_GRAPHICS)
6017 printf("::: 3: '%s'\n", artwork_new_identifier);
6020 /* ---------- do not reload directly after starting ---------------------- */
6021 if (!initialized[type])
6022 artwork_new_identifier = NULL;
6024 initialized[type] = TRUE;
6027 if (type == ARTWORK_TYPE_GRAPHICS)
6028 printf("::: 4: '%s'\n", artwork_new_identifier);
6032 if (type == ARTWORK_TYPE_GRAPHICS)
6033 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
6034 artwork.gfx_current_identifier, artwork_current_identifier,
6035 artwork.gfx_current->identifier, leveldir_current->graphics_set,
6036 artwork_new_identifier);
6039 return artwork_new_identifier;
6042 void ReloadCustomArtwork(int force_reload)
6044 int last_game_status = game_status; /* save current game status */
6045 char *gfx_new_identifier;
6046 char *snd_new_identifier;
6047 char *mus_new_identifier;
6048 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
6049 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
6050 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
6051 boolean reload_needed;
6053 InitOverrideArtwork();
6055 force_reload_gfx |= AdjustGraphicsForEMC();
6057 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
6058 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
6059 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
6061 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
6062 snd_new_identifier != NULL || force_reload_snd ||
6063 mus_new_identifier != NULL || force_reload_mus);
6068 print_timestamp_init("ReloadCustomArtwork");
6070 game_status = GAME_MODE_LOADING;
6072 FadeOut(REDRAW_ALL);
6075 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6077 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
6079 print_timestamp_time("ClearRectangle");
6082 printf("::: fading in ... %d\n", fading.fade_mode);
6086 printf("::: done\n");
6089 if (gfx_new_identifier != NULL || force_reload_gfx)
6092 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
6093 artwork.gfx_current_identifier,
6095 artwork.gfx_current->identifier,
6096 leveldir_current->graphics_set);
6100 print_timestamp_time("InitImages");
6103 if (snd_new_identifier != NULL || force_reload_snd)
6105 InitSound(snd_new_identifier);
6106 print_timestamp_time("InitSound");
6109 if (mus_new_identifier != NULL || force_reload_mus)
6111 InitMusic(mus_new_identifier);
6112 print_timestamp_time("InitMusic");
6115 game_status = last_game_status; /* restore current game status */
6118 printf("::: ----------------DELAY 1 ...\n");
6123 printf("::: FadeOut @ ReloadCustomArtwork ...\n");
6125 FadeOut(REDRAW_ALL);
6127 printf("::: FadeOut @ ReloadCustomArtwork done\n");
6132 /* force redraw of (open or closed) door graphics */
6133 SetDoorState(DOOR_OPEN_ALL);
6134 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
6139 FadeSetEnterScreen();
6140 FadeSkipNextFadeOut();
6141 // FadeSetDisabled();
6146 fading = fading_none;
6151 redraw_mask = REDRAW_ALL;
6154 print_timestamp_done("ReloadCustomArtwork");
6157 void KeyboardAutoRepeatOffUnlessAutoplay()
6159 if (global.autoplay_leveldir == NULL)
6160 KeyboardAutoRepeatOff();
6164 /* ========================================================================= */
6166 /* ========================================================================= */
6170 print_timestamp_init("OpenAll");
6172 game_status = GAME_MODE_LOADING;
6178 InitGlobal(); /* initialize some global variables */
6180 print_timestamp_time("[init global stuff]");
6182 if (options.execute_command)
6183 Execute_Command(options.execute_command);
6185 if (options.serveronly)
6187 #if defined(PLATFORM_UNIX)
6188 NetworkServer(options.server_port, options.serveronly);
6190 Error(ERR_WARN, "networking only supported in Unix version");
6193 exit(0); /* never reached, server loops forever */
6200 InitArtworkInfo(); /* needed before loading gfx, sound & music */
6201 InitArtworkConfig(); /* needed before forking sound child process */
6208 InitRND(NEW_RANDOMIZE);
6209 InitSimpleRandom(NEW_RANDOMIZE);
6213 print_timestamp_time("[init setup/config stuff]");
6216 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
6218 InitEventFilter(FilterMouseMotionEvents);
6220 print_timestamp_time("[init video stuff]");
6222 InitElementPropertiesStatic();
6223 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
6224 InitElementPropertiesGfxElement();
6226 print_timestamp_time("[init element properties stuff]");
6230 print_timestamp_time("InitGfx");
6233 print_timestamp_time("InitLevelInfo");
6235 InitLevelArtworkInfo();
6236 print_timestamp_time("InitLevelArtworkInfo");
6238 InitOverrideArtwork(); /* needs to know current level directory */
6239 print_timestamp_time("InitOverrideArtwork");
6241 InitImages(); /* needs to know current level directory */
6242 print_timestamp_time("InitImages");
6244 InitSound(NULL); /* needs to know current level directory */
6245 print_timestamp_time("InitSound");
6247 InitMusic(NULL); /* needs to know current level directory */
6248 print_timestamp_time("InitMusic");
6250 InitGfxBackground();
6260 if (global.autoplay_leveldir)
6265 else if (global.convert_leveldir)
6270 else if (global.create_images_dir)
6272 CreateLevelSketchImages();
6276 game_status = GAME_MODE_MAIN;
6279 FadeSetEnterScreen();
6280 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
6281 FadeSkipNextFadeOut();
6282 // FadeSetDisabled();
6284 fading = fading_none;
6287 print_timestamp_time("[post-artwork]");
6289 print_timestamp_done("OpenAll");
6293 InitNetworkServer();
6296 void CloseAllAndExit(int exit_value)
6301 CloseAudio(); /* called after freeing sounds (needed for SDL) */
6313 #if defined(TARGET_SDL)
6314 if (network_server) /* terminate network server */
6315 SDL_KillThread(server_thread);
6318 CloseVideoDisplay();
6319 ClosePlatformDependentStuff();
6321 if (exit_value != 0)
6322 NotifyUserAboutErrorFile();