1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2006 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
14 #include "libgame/libgame.h"
29 #include "conf_e2g.c" /* include auto-generated data structure definitions */
30 #include "conf_esg.c" /* include auto-generated data structure definitions */
31 #include "conf_e2s.c" /* include auto-generated data structure definitions */
32 #include "conf_fnt.c" /* include auto-generated data structure definitions */
33 #include "conf_g2s.c" /* include auto-generated data structure definitions */
34 #include "conf_g2m.c" /* include auto-generated data structure definitions */
35 #include "conf_act.c" /* include auto-generated data structure definitions */
38 #define CONFIG_TOKEN_FONT_INITIAL "font.initial"
39 #define CONFIG_TOKEN_GLOBAL_BUSY "global.busy"
41 #define DEBUG_PRINT_INIT_TIMESTAMPS TRUE
42 #define DEBUG_PRINT_INIT_TIMESTAMPS_DEPTH 1
45 static struct FontBitmapInfo font_initial[NUM_INITIAL_FONTS];
46 static struct GraphicInfo anim_initial;
48 static int copy_properties[][5] =
52 EL_BUG_LEFT, EL_BUG_RIGHT,
53 EL_BUG_UP, EL_BUG_DOWN
57 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
58 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
62 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
63 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
67 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
68 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
72 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
73 EL_PACMAN_UP, EL_PACMAN_DOWN
77 EL_YAMYAM_LEFT, EL_YAMYAM_RIGHT,
78 EL_YAMYAM_UP, EL_YAMYAM_DOWN
82 EL_MOLE_LEFT, EL_MOLE_RIGHT,
83 EL_MOLE_UP, EL_MOLE_DOWN
92 static void print_timestamp_ext(char *message, char *mode)
95 #if DEBUG_PRINT_INIT_TIMESTAMPS
96 static char *debug_message = NULL;
97 static char *last_message = NULL;
98 static int counter_nr = 0;
99 int max_depth = DEBUG_PRINT_INIT_TIMESTAMPS_DEPTH;
101 checked_free(debug_message);
102 debug_message = getStringCat3(mode, " ", message);
104 if (strEqual(mode, "INIT"))
106 debug_print_timestamp(counter_nr, NULL);
108 if (counter_nr + 1 < max_depth)
109 debug_print_timestamp(counter_nr, debug_message);
113 debug_print_timestamp(counter_nr, NULL);
115 else if (strEqual(mode, "DONE"))
119 if (counter_nr + 1 < max_depth ||
120 (counter_nr == 0 && max_depth == 1))
122 last_message = message;
124 if (counter_nr == 0 && max_depth == 1)
126 checked_free(debug_message);
127 debug_message = getStringCat3("TIME", " ", message);
130 debug_print_timestamp(counter_nr, debug_message);
133 else if (!strEqual(mode, "TIME") ||
134 !strEqual(message, last_message))
136 if (counter_nr < max_depth)
137 debug_print_timestamp(counter_nr, debug_message);
143 static void print_timestamp_init(char *message)
145 print_timestamp_ext(message, "INIT");
148 static void print_timestamp_time(char *message)
150 print_timestamp_ext(message, "TIME");
153 static void print_timestamp_done(char *message)
155 print_timestamp_ext(message, "DONE");
160 struct GraphicInfo *graphic_info_last = graphic_info;
162 static unsigned long action_delay = 0;
163 unsigned long action_delay_value = GameFrameDelay;
164 int sync_frame = FrameCounter;
167 if (game_status != GAME_MODE_LOADING)
170 if (anim_initial.bitmap == NULL || window == NULL)
173 if (!DelayReached(&action_delay, action_delay_value))
178 static unsigned long last_counter = -1;
179 unsigned long current_counter = Counter();
180 unsigned long delay = current_counter - last_counter;
182 if (last_counter != -1 && delay > action_delay_value + 5)
183 printf("::: DrawInitAnim: DELAY TOO LONG: %ld\n", delay);
185 last_counter = current_counter;
190 anim_initial.anim_mode = ANIM_LOOP;
191 anim_initial.anim_start_frame = 0;
192 anim_initial.offset_x = anim_initial.width;
193 anim_initial.offset_y = 0;
197 x = ALIGNED_TEXT_XPOS(&init.busy);
198 y = ALIGNED_TEXT_YPOS(&init.busy);
200 x = WIN_XSIZE / 2 - TILESIZE / 2;
201 y = WIN_YSIZE / 2 - TILESIZE / 2;
204 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
208 static boolean done = FALSE;
211 printf("::: %d, %d, %d, %d => %d, %d [%d, %d] [%d, %d]\n",
212 init.busy.x, init.busy.y,
213 init.busy.align, init.busy.valign,
215 graphic_info[graphic].width,
216 graphic_info[graphic].height,
217 sync_frame, anim_initial.anim_delay);
223 if (sync_frame % anim_initial.anim_delay == 0)
228 int width = graphic_info[graphic].width;
229 int height = graphic_info[graphic].height;
230 int frame = getGraphicAnimationFrame(graphic, sync_frame);
232 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
233 BlitBitmap(src_bitmap, window, src_x, src_y, width, height, x, y);
235 /* !!! this can only draw TILEX/TILEY size animations !!! */
236 DrawGraphicAnimationExt(window, x, y, graphic, sync_frame, NO_MASKING);
240 graphic_info = graphic_info_last;
247 FreeLevelEditorGadgets();
256 static boolean gadgets_initialized = FALSE;
258 if (gadgets_initialized)
261 CreateLevelEditorGadgets();
265 CreateScreenGadgets();
267 InitGadgetsSoundCallback(PlaySoundActivating, PlaySoundSelecting);
269 gadgets_initialized = TRUE;
272 inline void InitElementSmallImagesScaledUp(int graphic)
275 struct FileInfo *fi = getImageListEntryFromImageID(graphic);
277 printf("::: '%s' -> '%s'\n", fi->token, fi->filename);
280 CreateImageWithSmallImages(graphic, graphic_info[graphic].scale_up_factor);
283 void InitElementSmallImages()
285 static int special_graphics[] =
287 IMG_EDITOR_ELEMENT_BORDER,
288 IMG_EDITOR_ELEMENT_BORDER_INPUT,
289 IMG_EDITOR_CASCADE_LIST,
290 IMG_EDITOR_CASCADE_LIST_ACTIVE,
293 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
294 int num_property_mappings = getImageListPropertyMappingSize();
297 /* initialize normal images from static configuration */
298 for (i = 0; element_to_graphic[i].element > -1; i++)
299 InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
301 /* initialize special images from static configuration */
302 for (i = 0; element_to_special_graphic[i].element > -1; i++)
303 InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
305 /* initialize images from dynamic configuration (may be elements or other) */
306 for (i = 0; i < num_property_mappings; i++)
307 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
309 /* initialize special images from above list (non-element images) */
310 for (i = 0; special_graphics[i] > -1; i++)
311 InitElementSmallImagesScaledUp(special_graphics[i]);
314 void InitScaledImages()
318 /* scale normal images from static configuration, if not already scaled */
319 for (i = 0; i < NUM_IMAGE_FILES; i++)
320 ScaleImage(i, graphic_info[i].scale_up_factor);
324 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
325 void SetBitmaps_EM(Bitmap **em_bitmap)
327 em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
328 em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].bitmap;
332 static int getFontBitmapID(int font_nr)
336 /* (special case: do not use special font for GAME_MODE_LOADING) */
337 if (game_status >= GAME_MODE_TITLE_INITIAL &&
338 game_status <= GAME_MODE_PSEUDO_PREVIEW)
339 special = game_status;
340 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
341 special = GFX_SPECIAL_ARG_MAIN;
343 else if (game_status == GAME_MODE_PLAYING)
344 special = GFX_SPECIAL_ARG_DOOR;
351 font_info[font_nr].token_name,
352 special_suffix_info[special].suffix);
357 return font_info[font_nr].special_bitmap_id[special];
362 static int getFontFromToken(char *token)
365 char *value = getHashEntry(font_token_hash, token);
372 /* !!! OPTIMIZE THIS BY USING HASH !!! */
373 for (i = 0; i < NUM_FONTS; i++)
374 if (strEqual(token, font_info[i].token_name))
378 /* if font not found, use reliable default value */
379 return FONT_INITIAL_1;
382 void InitFontGraphicInfo()
384 static struct FontBitmapInfo *font_bitmap_info = NULL;
385 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
386 int num_property_mappings = getImageListPropertyMappingSize();
387 int num_font_bitmaps = NUM_FONTS;
390 if (graphic_info == NULL) /* still at startup phase */
392 InitFontInfo(font_initial, NUM_INITIAL_FONTS,
393 getFontBitmapID, getFontFromToken);
398 /* ---------- initialize font graphic definitions ---------- */
400 /* always start with reliable default values (normal font graphics) */
401 for (i = 0; i < NUM_FONTS; i++)
402 font_info[i].graphic = IMG_FONT_INITIAL_1;
404 /* initialize normal font/graphic mapping from static configuration */
405 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
407 int font_nr = font_to_graphic[i].font_nr;
408 int special = font_to_graphic[i].special;
409 int graphic = font_to_graphic[i].graphic;
414 font_info[font_nr].graphic = graphic;
417 /* always start with reliable default values (special font graphics) */
418 for (i = 0; i < NUM_FONTS; i++)
420 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
422 font_info[i].special_graphic[j] = font_info[i].graphic;
423 font_info[i].special_bitmap_id[j] = i;
427 /* initialize special font/graphic mapping from static configuration */
428 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
430 int font_nr = font_to_graphic[i].font_nr;
431 int special = font_to_graphic[i].special;
432 int graphic = font_to_graphic[i].graphic;
433 int base_graphic = font2baseimg(font_nr);
435 if (IS_SPECIAL_GFX_ARG(special))
437 boolean base_redefined =
438 getImageListEntryFromImageID(base_graphic)->redefined;
439 boolean special_redefined =
440 getImageListEntryFromImageID(graphic)->redefined;
441 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
443 /* if the base font ("font.title_1", for example) has been redefined,
444 but not the special font ("font.title_1.LEVELS", for example), do not
445 use an existing (in this case considered obsolete) special font
446 anymore, but use the automatically determined default font */
447 /* special case: cloned special fonts must be explicitly redefined,
448 but are not automatically redefined by redefining base font */
449 if (base_redefined && !special_redefined && !special_cloned)
452 font_info[font_nr].special_graphic[special] = graphic;
453 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
458 /* initialize special font/graphic mapping from dynamic configuration */
459 for (i = 0; i < num_property_mappings; i++)
461 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
462 int special = property_mapping[i].ext3_index;
463 int graphic = property_mapping[i].artwork_index;
468 if (IS_SPECIAL_GFX_ARG(special))
470 font_info[font_nr].special_graphic[special] = graphic;
471 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
476 /* correct special font/graphic mapping for cloned fonts for downwards
477 compatibility of PREVIEW fonts -- this is only needed for implicit
478 redefinition of special font by redefined base font, and only if other
479 fonts are cloned from this special font (like in the "Zelda" level set) */
480 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
482 int font_nr = font_to_graphic[i].font_nr;
483 int special = font_to_graphic[i].special;
484 int graphic = font_to_graphic[i].graphic;
486 if (IS_SPECIAL_GFX_ARG(special))
488 boolean special_redefined =
489 getImageListEntryFromImageID(graphic)->redefined;
490 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
492 if (special_cloned && !special_redefined)
496 for (j = 0; font_to_graphic[j].font_nr > -1; j++)
498 int font_nr2 = font_to_graphic[j].font_nr;
499 int special2 = font_to_graphic[j].special;
500 int graphic2 = font_to_graphic[j].graphic;
502 if (IS_SPECIAL_GFX_ARG(special2) &&
503 graphic2 == graphic_info[graphic].clone_from)
505 font_info[font_nr].special_graphic[special] =
506 font_info[font_nr2].special_graphic[special2];
507 font_info[font_nr].special_bitmap_id[special] =
508 font_info[font_nr2].special_bitmap_id[special2];
515 /* reset non-redefined ".active" font graphics if normal font is redefined */
516 /* (this different treatment is needed because normal and active fonts are
517 independently defined ("active" is not a property of font definitions!) */
518 for (i = 0; i < NUM_FONTS; i++)
520 int font_nr_base = i;
521 int font_nr_active = FONT_ACTIVE(font_nr_base);
523 /* check only those fonts with exist as normal and ".active" variant */
524 if (font_nr_base != font_nr_active)
526 int base_graphic = font_info[font_nr_base].graphic;
527 int active_graphic = font_info[font_nr_active].graphic;
528 boolean base_redefined =
529 getImageListEntryFromImageID(base_graphic)->redefined;
530 boolean active_redefined =
531 getImageListEntryFromImageID(active_graphic)->redefined;
533 /* if the base font ("font.menu_1", for example) has been redefined,
534 but not the active font ("font.menu_1.active", for example), do not
535 use an existing (in this case considered obsolete) active font
536 anymore, but use the automatically determined default font */
537 if (base_redefined && !active_redefined)
538 font_info[font_nr_active].graphic = base_graphic;
540 /* now also check each "special" font (which may be the same as above) */
541 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
543 int base_graphic = font_info[font_nr_base].special_graphic[j];
544 int active_graphic = font_info[font_nr_active].special_graphic[j];
545 boolean base_redefined =
546 getImageListEntryFromImageID(base_graphic)->redefined;
547 boolean active_redefined =
548 getImageListEntryFromImageID(active_graphic)->redefined;
550 /* same as above, but check special graphic definitions, for example:
551 redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN" */
552 if (base_redefined && !active_redefined)
554 font_info[font_nr_active].special_graphic[j] =
555 font_info[font_nr_base].special_graphic[j];
556 font_info[font_nr_active].special_bitmap_id[j] =
557 font_info[font_nr_base].special_bitmap_id[j];
563 /* ---------- initialize font bitmap array ---------- */
565 if (font_bitmap_info != NULL)
566 FreeFontInfo(font_bitmap_info);
569 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
571 /* ---------- initialize font bitmap definitions ---------- */
573 for (i = 0; i < NUM_FONTS; i++)
575 if (i < NUM_INITIAL_FONTS)
577 font_bitmap_info[i] = font_initial[i];
581 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
583 int font_bitmap_id = font_info[i].special_bitmap_id[j];
584 int graphic = font_info[i].special_graphic[j];
586 /* set 'graphic_info' for font entries, if uninitialized (guessed) */
587 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
589 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
590 graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
593 /* copy font relevant information from graphics information */
594 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
595 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
596 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
597 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
598 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
600 font_bitmap_info[font_bitmap_id].draw_xoffset =
601 graphic_info[graphic].draw_xoffset;
602 font_bitmap_info[font_bitmap_id].draw_yoffset =
603 graphic_info[graphic].draw_yoffset;
605 font_bitmap_info[font_bitmap_id].num_chars =
606 graphic_info[graphic].anim_frames;
607 font_bitmap_info[font_bitmap_id].num_chars_per_line =
608 graphic_info[graphic].anim_frames_per_line;
612 InitFontInfo(font_bitmap_info, num_font_bitmaps,
613 getFontBitmapID, getFontFromToken);
616 void InitElementGraphicInfo()
618 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
619 int num_property_mappings = getImageListPropertyMappingSize();
622 if (graphic_info == NULL) /* still at startup phase */
625 /* set values to -1 to identify later as "uninitialized" values */
626 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
628 for (act = 0; act < NUM_ACTIONS; act++)
630 element_info[i].graphic[act] = -1;
631 element_info[i].crumbled[act] = -1;
633 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
635 element_info[i].direction_graphic[act][dir] = -1;
636 element_info[i].direction_crumbled[act][dir] = -1;
643 /* initialize normal element/graphic mapping from static configuration */
644 for (i = 0; element_to_graphic[i].element > -1; i++)
646 int element = element_to_graphic[i].element;
647 int action = element_to_graphic[i].action;
648 int direction = element_to_graphic[i].direction;
649 boolean crumbled = element_to_graphic[i].crumbled;
650 int graphic = element_to_graphic[i].graphic;
651 int base_graphic = el2baseimg(element);
653 if (graphic_info[graphic].bitmap == NULL)
656 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
659 boolean base_redefined =
660 getImageListEntryFromImageID(base_graphic)->redefined;
661 boolean act_dir_redefined =
662 getImageListEntryFromImageID(graphic)->redefined;
664 /* if the base graphic ("emerald", for example) has been redefined,
665 but not the action graphic ("emerald.falling", for example), do not
666 use an existing (in this case considered obsolete) action graphic
667 anymore, but use the automatically determined default graphic */
668 if (base_redefined && !act_dir_redefined)
673 action = ACTION_DEFAULT;
678 element_info[element].direction_crumbled[action][direction] = graphic;
680 element_info[element].crumbled[action] = graphic;
685 element_info[element].direction_graphic[action][direction] = graphic;
687 element_info[element].graphic[action] = graphic;
691 /* initialize normal element/graphic mapping from dynamic configuration */
692 for (i = 0; i < num_property_mappings; i++)
694 int element = property_mapping[i].base_index;
695 int action = property_mapping[i].ext1_index;
696 int direction = property_mapping[i].ext2_index;
697 int special = property_mapping[i].ext3_index;
698 int graphic = property_mapping[i].artwork_index;
699 boolean crumbled = FALSE;
702 if ((element == EL_EM_DYNAMITE ||
703 element == EL_EM_DYNAMITE_ACTIVE) &&
704 action == ACTION_ACTIVE &&
705 (special == GFX_SPECIAL_ARG_EDITOR ||
706 special == GFX_SPECIAL_ARG_PANEL))
707 printf("::: DYNAMIC: %d, %d, %d -> %d\n",
708 element, action, special, graphic);
711 if (special == GFX_SPECIAL_ARG_CRUMBLED)
717 if (graphic_info[graphic].bitmap == NULL)
720 if (element >= MAX_NUM_ELEMENTS || special != -1)
724 action = ACTION_DEFAULT;
729 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
730 element_info[element].direction_crumbled[action][dir] = -1;
733 element_info[element].direction_crumbled[action][direction] = graphic;
735 element_info[element].crumbled[action] = graphic;
740 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
741 element_info[element].direction_graphic[action][dir] = -1;
744 element_info[element].direction_graphic[action][direction] = graphic;
746 element_info[element].graphic[action] = graphic;
750 /* now copy all graphics that are defined to be cloned from other graphics */
751 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
753 int graphic = element_info[i].graphic[ACTION_DEFAULT];
754 int crumbled_like, diggable_like;
759 crumbled_like = graphic_info[graphic].crumbled_like;
760 diggable_like = graphic_info[graphic].diggable_like;
762 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
764 for (act = 0; act < NUM_ACTIONS; act++)
765 element_info[i].crumbled[act] =
766 element_info[crumbled_like].crumbled[act];
767 for (act = 0; act < NUM_ACTIONS; act++)
768 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
769 element_info[i].direction_crumbled[act][dir] =
770 element_info[crumbled_like].direction_crumbled[act][dir];
773 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
775 element_info[i].graphic[ACTION_DIGGING] =
776 element_info[diggable_like].graphic[ACTION_DIGGING];
777 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
778 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
779 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
784 /* set hardcoded definitions for some runtime elements without graphic */
785 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
789 /* set hardcoded definitions for some internal elements without graphic */
790 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
792 if (IS_EDITOR_CASCADE_INACTIVE(i))
793 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
794 else if (IS_EDITOR_CASCADE_ACTIVE(i))
795 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
799 /* now set all undefined/invalid graphics to -1 to set to default after it */
800 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
802 for (act = 0; act < NUM_ACTIONS; act++)
806 graphic = element_info[i].graphic[act];
807 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
808 element_info[i].graphic[act] = -1;
810 graphic = element_info[i].crumbled[act];
811 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
812 element_info[i].crumbled[act] = -1;
814 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
816 graphic = element_info[i].direction_graphic[act][dir];
817 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
818 element_info[i].direction_graphic[act][dir] = -1;
820 graphic = element_info[i].direction_crumbled[act][dir];
821 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
822 element_info[i].direction_crumbled[act][dir] = -1;
829 /* adjust graphics with 2nd tile for movement according to direction
830 (do this before correcting '-1' values to minimize calculations) */
831 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
833 for (act = 0; act < NUM_ACTIONS; act++)
835 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
837 int graphic = element_info[i].direction_graphic[act][dir];
838 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
840 if (act == ACTION_FALLING) /* special case */
841 graphic = element_info[i].graphic[act];
844 graphic_info[graphic].double_movement &&
845 graphic_info[graphic].swap_double_tiles != 0)
847 struct GraphicInfo *g = &graphic_info[graphic];
848 int src_x_front = g->src_x;
849 int src_y_front = g->src_y;
850 int src_x_back = g->src_x + g->offset2_x;
851 int src_y_back = g->src_y + g->offset2_y;
852 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
854 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
855 src_y_front < src_y_back);
856 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
857 boolean swap_movement_tiles_autodetected =
858 (!frames_are_ordered_diagonally &&
859 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
860 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
861 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
862 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
865 /* swap frontside and backside graphic tile coordinates, if needed */
866 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
868 /* get current (wrong) backside tile coordinates */
869 getGraphicSourceExt(graphic, 0, &dummy, &src_x_back, &src_y_back,
872 /* set frontside tile coordinates to backside tile coordinates */
873 g->src_x = src_x_back;
874 g->src_y = src_y_back;
876 /* invert tile offset to point to new backside tile coordinates */
880 /* do not swap front and backside tiles again after correction */
881 g->swap_double_tiles = 0;
890 /* now set all '-1' values to element specific default values */
891 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
893 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
894 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
895 int default_direction_graphic[NUM_DIRECTIONS_FULL];
896 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
898 if (default_graphic == -1)
899 default_graphic = IMG_UNKNOWN;
901 if (default_crumbled == -1)
902 default_crumbled = default_graphic;
904 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
905 if (default_crumbled == -1)
906 default_crumbled = IMG_EMPTY;
909 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
911 default_direction_graphic[dir] =
912 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
913 default_direction_crumbled[dir] =
914 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
916 if (default_direction_graphic[dir] == -1)
917 default_direction_graphic[dir] = default_graphic;
919 if (default_direction_crumbled[dir] == -1)
920 default_direction_crumbled[dir] = default_direction_graphic[dir];
922 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
923 if (default_direction_crumbled[dir] == -1)
924 default_direction_crumbled[dir] = default_crumbled;
928 for (act = 0; act < NUM_ACTIONS; act++)
930 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
931 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
932 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
933 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
934 act == ACTION_TURNING_FROM_RIGHT ||
935 act == ACTION_TURNING_FROM_UP ||
936 act == ACTION_TURNING_FROM_DOWN);
938 /* generic default action graphic (defined by "[default]" directive) */
939 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
940 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
941 int default_remove_graphic = IMG_EMPTY;
943 if (act_remove && default_action_graphic != -1)
944 default_remove_graphic = default_action_graphic;
946 /* look for special default action graphic (classic game specific) */
947 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
948 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
949 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
950 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
951 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
952 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
954 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
955 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
956 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
957 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
958 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
959 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
962 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
963 /* !!! make this better !!! */
964 if (i == EL_EMPTY_SPACE)
966 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
967 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
971 if (default_action_graphic == -1)
972 default_action_graphic = default_graphic;
974 if (default_action_crumbled == -1)
975 default_action_crumbled = default_action_graphic;
977 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
978 if (default_action_crumbled == -1)
979 default_action_crumbled = default_crumbled;
982 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
984 /* use action graphic as the default direction graphic, if undefined */
985 int default_action_direction_graphic = element_info[i].graphic[act];
986 int default_action_direction_crumbled = element_info[i].crumbled[act];
988 /* no graphic for current action -- use default direction graphic */
989 if (default_action_direction_graphic == -1)
990 default_action_direction_graphic =
991 (act_remove ? default_remove_graphic :
993 element_info[i].direction_graphic[ACTION_TURNING][dir] :
994 default_action_graphic != default_graphic ?
995 default_action_graphic :
996 default_direction_graphic[dir]);
998 if (element_info[i].direction_graphic[act][dir] == -1)
999 element_info[i].direction_graphic[act][dir] =
1000 default_action_direction_graphic;
1003 if (default_action_direction_crumbled == -1)
1004 default_action_direction_crumbled =
1005 element_info[i].direction_graphic[act][dir];
1007 if (default_action_direction_crumbled == -1)
1008 default_action_direction_crumbled =
1009 (act_remove ? default_remove_graphic :
1011 element_info[i].direction_crumbled[ACTION_TURNING][dir] :
1012 default_action_crumbled != default_crumbled ?
1013 default_action_crumbled :
1014 default_direction_crumbled[dir]);
1017 if (element_info[i].direction_crumbled[act][dir] == -1)
1018 element_info[i].direction_crumbled[act][dir] =
1019 default_action_direction_crumbled;
1022 /* no graphic for this specific action -- use default action graphic */
1023 if (element_info[i].graphic[act] == -1)
1024 element_info[i].graphic[act] =
1025 (act_remove ? default_remove_graphic :
1026 act_turning ? element_info[i].graphic[ACTION_TURNING] :
1027 default_action_graphic);
1029 if (element_info[i].crumbled[act] == -1)
1030 element_info[i].crumbled[act] = element_info[i].graphic[act];
1032 if (element_info[i].crumbled[act] == -1)
1033 element_info[i].crumbled[act] =
1034 (act_remove ? default_remove_graphic :
1035 act_turning ? element_info[i].crumbled[ACTION_TURNING] :
1036 default_action_crumbled);
1041 UPDATE_BUSY_STATE();
1044 /* !!! THIS ALSO CLEARS SPECIAL FLAGS (AND IS NOT NEEDED ANYWAY) !!! */
1045 /* set animation mode to "none" for each graphic with only 1 frame */
1046 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1048 for (act = 0; act < NUM_ACTIONS; act++)
1050 int graphic = element_info[i].graphic[act];
1051 int crumbled = element_info[i].crumbled[act];
1053 if (graphic_info[graphic].anim_frames == 1)
1054 graphic_info[graphic].anim_mode = ANIM_NONE;
1055 if (graphic_info[crumbled].anim_frames == 1)
1056 graphic_info[crumbled].anim_mode = ANIM_NONE;
1058 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1060 graphic = element_info[i].direction_graphic[act][dir];
1061 crumbled = element_info[i].direction_crumbled[act][dir];
1063 if (graphic_info[graphic].anim_frames == 1)
1064 graphic_info[graphic].anim_mode = ANIM_NONE;
1065 if (graphic_info[crumbled].anim_frames == 1)
1066 graphic_info[crumbled].anim_mode = ANIM_NONE;
1074 if (options.verbose)
1076 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1077 if (element_info[i].graphic[ACTION_DEFAULT] == IMG_UNKNOWN &&
1079 Error(ERR_INFO, "warning: no graphic for element '%s' (%d)",
1080 element_info[i].token_name, i);
1086 void InitElementSpecialGraphicInfo()
1088 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
1089 int num_property_mappings = getImageListPropertyMappingSize();
1092 /* always start with reliable default values */
1093 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1094 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1095 element_info[i].special_graphic[j] =
1096 element_info[i].graphic[ACTION_DEFAULT];
1098 /* initialize special element/graphic mapping from static configuration */
1099 for (i = 0; element_to_special_graphic[i].element > -1; i++)
1101 int element = element_to_special_graphic[i].element;
1102 int special = element_to_special_graphic[i].special;
1103 int graphic = element_to_special_graphic[i].graphic;
1104 int base_graphic = el2baseimg(element);
1105 boolean base_redefined =
1106 getImageListEntryFromImageID(base_graphic)->redefined;
1107 boolean special_redefined =
1108 getImageListEntryFromImageID(graphic)->redefined;
1111 if ((element == EL_EM_DYNAMITE ||
1112 element == EL_EM_DYNAMITE_ACTIVE) &&
1113 (special == GFX_SPECIAL_ARG_EDITOR ||
1114 special == GFX_SPECIAL_ARG_PANEL))
1115 printf("::: SPECIAL STATIC: %d, %d -> %d\n",
1116 element, special, graphic);
1119 /* if the base graphic ("emerald", for example) has been redefined,
1120 but not the special graphic ("emerald.EDITOR", for example), do not
1121 use an existing (in this case considered obsolete) special graphic
1122 anymore, but use the automatically created (down-scaled) graphic */
1123 if (base_redefined && !special_redefined)
1126 element_info[element].special_graphic[special] = graphic;
1129 /* initialize special element/graphic mapping from dynamic configuration */
1130 for (i = 0; i < num_property_mappings; i++)
1132 int element = property_mapping[i].base_index;
1133 int action = property_mapping[i].ext1_index;
1134 int direction = property_mapping[i].ext2_index;
1135 int special = property_mapping[i].ext3_index;
1136 int graphic = property_mapping[i].artwork_index;
1139 if ((element == EL_EM_DYNAMITE ||
1140 element == EL_EM_DYNAMITE_ACTIVE ||
1141 element == EL_CONVEYOR_BELT_1_MIDDLE ||
1142 element == EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE) &&
1143 (special == GFX_SPECIAL_ARG_EDITOR ||
1144 special == GFX_SPECIAL_ARG_PANEL))
1145 printf("::: SPECIAL DYNAMIC: %d, %d -> %d [%d]\n",
1146 element, special, graphic, property_mapping[i].ext1_index);
1150 if (element == EL_CONVEYOR_BELT_1_MIDDLE &&
1151 action == ACTION_ACTIVE)
1153 element = EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE;
1159 if (element == EL_MAGIC_WALL &&
1160 action == ACTION_ACTIVE)
1162 element = EL_MAGIC_WALL_ACTIVE;
1168 /* for action ".active", replace element with active element, if exists */
1169 if (action == ACTION_ACTIVE && element != ELEMENT_ACTIVE(element))
1171 element = ELEMENT_ACTIVE(element);
1176 if (element >= MAX_NUM_ELEMENTS)
1179 /* do not change special graphic if action or direction was specified */
1180 if (action != -1 || direction != -1)
1183 if (IS_SPECIAL_GFX_ARG(special))
1184 element_info[element].special_graphic[special] = graphic;
1187 /* now set all undefined/invalid graphics to default */
1188 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1189 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1190 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
1191 element_info[i].special_graphic[j] =
1192 element_info[i].graphic[ACTION_DEFAULT];
1195 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
1197 if (type != TYPE_ELEMENT && type != TYPE_GRAPHIC)
1198 return get_parameter_value(value_raw, suffix, type);
1200 if (strEqual(value_raw, ARG_UNDEFINED))
1201 return ARG_UNDEFINED_VALUE;
1204 if (type == TYPE_ELEMENT)
1206 char *value = getHashEntry(element_token_hash, value_raw);
1208 return (value != NULL ? atoi(value) : EL_UNDEFINED);
1210 else if (type == TYPE_GRAPHIC)
1212 char *value = getHashEntry(graphic_token_hash, value_raw);
1214 return (value != NULL ? atoi(value) : IMG_UNDEFINED);
1222 /* !!! THIS IS BUGGY !!! NOT SURE IF YOU GET ELEMENT ID OR GRAPHIC ID !!! */
1223 /* !!! (possible reason why ".clone_from" with elements doesn't work) !!! */
1225 /* !!! OPTIMIZE THIS BY USING HASH !!! */
1226 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1227 if (strEqual(element_info[i].token_name, value_raw))
1230 /* !!! OPTIMIZE THIS BY USING HASH !!! */
1231 for (i = 0; image_config[i].token != NULL; i++)
1233 int len_config_value = strlen(image_config[i].value);
1235 if (!strEqual(&image_config[i].value[len_config_value - 4], ".pcx") &&
1236 !strEqual(&image_config[i].value[len_config_value - 4], ".wav") &&
1237 !strEqual(image_config[i].value, UNDEFINED_FILENAME))
1240 if (strEqual(image_config[i].token, value_raw))
1250 static int get_scaled_graphic_width(int graphic)
1252 int original_width = getOriginalImageWidthFromImageID(graphic);
1253 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1255 return original_width * scale_up_factor;
1258 static int get_scaled_graphic_height(int graphic)
1260 int original_height = getOriginalImageHeightFromImageID(graphic);
1261 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1263 return original_height * scale_up_factor;
1266 static void set_graphic_parameters_ext(int graphic, int *parameter,
1269 struct GraphicInfo *g = &graphic_info[graphic];
1270 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1271 int anim_frames_per_line = 1;
1273 /* always start with reliable default values */
1274 g->src_image_width = 0;
1275 g->src_image_height = 0;
1278 g->width = TILEX; /* default for element graphics */
1279 g->height = TILEY; /* default for element graphics */
1280 g->offset_x = 0; /* one or both of these values ... */
1281 g->offset_y = 0; /* ... will be corrected later */
1282 g->offset2_x = 0; /* one or both of these values ... */
1283 g->offset2_y = 0; /* ... will be corrected later */
1284 g->swap_double_tiles = -1; /* auto-detect tile swapping */
1285 g->crumbled_like = -1; /* do not use clone element */
1286 g->diggable_like = -1; /* do not use clone element */
1287 g->border_size = TILEX / 8; /* "CRUMBLED" border size */
1288 g->scale_up_factor = 1; /* default: no scaling up */
1289 g->clone_from = -1; /* do not use clone graphic */
1290 g->anim_delay_fixed = 0;
1291 g->anim_delay_random = 0;
1292 g->post_delay_fixed = 0;
1293 g->post_delay_random = 0;
1294 g->fade_mode = FADE_MODE_DEFAULT;
1298 g->align = ALIGN_CENTER; /* default for title screens */
1299 g->valign = VALIGN_MIDDLE; /* default for title screens */
1300 g->sort_priority = 0; /* default for title screens */
1302 g->bitmap = src_bitmap;
1305 /* optional zoom factor for scaling up the image to a larger size */
1306 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1307 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1308 if (g->scale_up_factor < 1)
1309 g->scale_up_factor = 1; /* no scaling */
1313 if (g->use_image_size)
1315 /* set new default bitmap size (with scaling, but without small images) */
1316 g->width = get_scaled_graphic_width(graphic);
1317 g->height = get_scaled_graphic_height(graphic);
1321 /* optional x and y tile position of animation frame sequence */
1322 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1323 g->src_x = parameter[GFX_ARG_XPOS] * TILEX;
1324 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1325 g->src_y = parameter[GFX_ARG_YPOS] * TILEY;
1327 /* optional x and y pixel position of animation frame sequence */
1328 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1329 g->src_x = parameter[GFX_ARG_X];
1330 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1331 g->src_y = parameter[GFX_ARG_Y];
1333 /* optional width and height of each animation frame */
1334 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1335 g->width = parameter[GFX_ARG_WIDTH];
1336 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1337 g->height = parameter[GFX_ARG_HEIGHT];
1340 /* optional zoom factor for scaling up the image to a larger size */
1341 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1342 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1343 if (g->scale_up_factor < 1)
1344 g->scale_up_factor = 1; /* no scaling */
1349 /* get final bitmap size (with scaling, but without small images) */
1350 int src_image_width = get_scaled_graphic_width(graphic);
1351 int src_image_height = get_scaled_graphic_height(graphic);
1353 if (src_image_width == 0 || src_image_height == 0)
1355 /* only happens when loaded outside artwork system (like "global.busy") */
1356 src_image_width = src_bitmap->width;
1357 src_image_height = src_bitmap->height;
1360 anim_frames_per_row = src_image_width / g->width;
1361 anim_frames_per_col = src_image_height / g->height;
1363 g->src_image_width = src_image_width;
1364 g->src_image_height = src_image_height;
1367 /* correct x or y offset dependent of vertical or horizontal frame order */
1368 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1370 g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1371 parameter[GFX_ARG_OFFSET] : g->height);
1372 anim_frames_per_line = anim_frames_per_col;
1374 else /* frames are ordered horizontally */
1376 g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1377 parameter[GFX_ARG_OFFSET] : g->width);
1378 anim_frames_per_line = anim_frames_per_row;
1381 /* optionally, the x and y offset of frames can be specified directly */
1382 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1383 g->offset_x = parameter[GFX_ARG_XOFFSET];
1384 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1385 g->offset_y = parameter[GFX_ARG_YOFFSET];
1387 /* optionally, moving animations may have separate start and end graphics */
1388 g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1390 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1391 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1393 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1394 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1395 g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1396 parameter[GFX_ARG_2ND_OFFSET] : g->height);
1397 else /* frames are ordered horizontally */
1398 g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1399 parameter[GFX_ARG_2ND_OFFSET] : g->width);
1401 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1402 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1403 g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1404 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1405 g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1407 /* optionally, the second movement tile can be specified as start tile */
1408 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1409 g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1411 /* automatically determine correct number of frames, if not defined */
1412 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1413 g->anim_frames = parameter[GFX_ARG_FRAMES];
1414 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1415 g->anim_frames = anim_frames_per_row;
1416 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1417 g->anim_frames = anim_frames_per_col;
1421 if (g->anim_frames == 0) /* frames must be at least 1 */
1424 g->anim_frames_per_line =
1425 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1426 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1428 g->anim_delay = parameter[GFX_ARG_DELAY];
1429 if (g->anim_delay == 0) /* delay must be at least 1 */
1432 g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1434 if (g->anim_frames == 1)
1435 g->anim_mode = ANIM_NONE;
1438 /* automatically determine correct start frame, if not defined */
1439 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1440 g->anim_start_frame = 0;
1441 else if (g->anim_mode & ANIM_REVERSE)
1442 g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1444 g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1446 /* animation synchronized with global frame counter, not move position */
1447 g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1449 /* optional element for cloning crumble graphics */
1450 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1451 g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1453 /* optional element for cloning digging graphics */
1454 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1455 g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1457 /* optional border size for "crumbling" diggable graphics */
1458 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1459 g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1461 /* this is only used for player "boring" and "sleeping" actions */
1462 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1463 g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1464 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1465 g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1466 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1467 g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1468 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1469 g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1471 /* this is only used for toon animations */
1472 g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1473 g->step_delay = parameter[GFX_ARG_STEP_DELAY];
1475 /* this is only used for drawing font characters */
1476 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1477 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1479 /* this is only used for drawing envelope graphics */
1480 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1482 /* optional graphic for cloning all graphics settings */
1483 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1484 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1486 /* optional settings for drawing title screens and title messages */
1487 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1488 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1489 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1490 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1491 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1492 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1493 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1494 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1495 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1496 g->align = parameter[GFX_ARG_ALIGN];
1497 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1498 g->valign = parameter[GFX_ARG_VALIGN];
1499 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1500 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1503 static void set_graphic_parameters(int graphic)
1506 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1507 char **parameter_raw = image->parameter;
1508 Bitmap *src_bitmap = getBitmapFromImageID(graphic);
1509 int parameter[NUM_GFX_ARGS];
1512 /* if fallback to default artwork is done, also use the default parameters */
1513 if (image->fallback_to_default)
1514 parameter_raw = image->default_parameter;
1516 /* get integer values from string parameters */
1517 for (i = 0; i < NUM_GFX_ARGS; i++)
1518 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1519 image_config_suffix[i].token,
1520 image_config_suffix[i].type);
1522 set_graphic_parameters_ext(graphic, parameter, src_bitmap);
1526 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1527 char **parameter_raw = image->parameter;
1528 Bitmap *src_bitmap = getBitmapFromImageID(graphic);
1529 int parameter[NUM_GFX_ARGS];
1530 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1531 int anim_frames_per_line = 1;
1534 /* if fallback to default artwork is done, also use the default parameters */
1535 if (image->fallback_to_default)
1536 parameter_raw = image->default_parameter;
1538 /* get integer values from string parameters */
1539 for (i = 0; i < NUM_GFX_ARGS; i++)
1540 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1541 image_config_suffix[i].token,
1542 image_config_suffix[i].type);
1544 graphic_info[graphic].bitmap = src_bitmap;
1546 /* always start with reliable default values */
1547 graphic_info[graphic].src_image_width = 0;
1548 graphic_info[graphic].src_image_height = 0;
1549 graphic_info[graphic].src_x = 0;
1550 graphic_info[graphic].src_y = 0;
1551 graphic_info[graphic].width = TILEX; /* default for element graphics */
1552 graphic_info[graphic].height = TILEY; /* default for element graphics */
1553 graphic_info[graphic].offset_x = 0; /* one or both of these values ... */
1554 graphic_info[graphic].offset_y = 0; /* ... will be corrected later */
1555 graphic_info[graphic].offset2_x = 0; /* one or both of these values ... */
1556 graphic_info[graphic].offset2_y = 0; /* ... will be corrected later */
1557 graphic_info[graphic].swap_double_tiles = -1; /* auto-detect tile swapping */
1558 graphic_info[graphic].crumbled_like = -1; /* do not use clone element */
1559 graphic_info[graphic].diggable_like = -1; /* do not use clone element */
1560 graphic_info[graphic].border_size = TILEX / 8; /* "CRUMBLED" border size */
1561 graphic_info[graphic].scale_up_factor = 1; /* default: no scaling up */
1562 graphic_info[graphic].clone_from = -1; /* do not use clone graphic */
1563 graphic_info[graphic].anim_delay_fixed = 0;
1564 graphic_info[graphic].anim_delay_random = 0;
1565 graphic_info[graphic].post_delay_fixed = 0;
1566 graphic_info[graphic].post_delay_random = 0;
1567 graphic_info[graphic].fade_mode = FADE_MODE_DEFAULT;
1568 graphic_info[graphic].fade_delay = -1;
1569 graphic_info[graphic].post_delay = -1;
1570 graphic_info[graphic].auto_delay = -1;
1571 graphic_info[graphic].align = ALIGN_CENTER; /* default for title screens */
1572 graphic_info[graphic].valign = VALIGN_MIDDLE; /* default for title screens */
1573 graphic_info[graphic].sort_priority = 0; /* default for title screens */
1576 /* optional zoom factor for scaling up the image to a larger size */
1577 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1578 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1579 if (graphic_info[graphic].scale_up_factor < 1)
1580 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
1584 if (graphic_info[graphic].use_image_size)
1586 /* set new default bitmap size (with scaling, but without small images) */
1587 graphic_info[graphic].width = get_scaled_graphic_width(graphic);
1588 graphic_info[graphic].height = get_scaled_graphic_height(graphic);
1592 /* optional x and y tile position of animation frame sequence */
1593 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1594 graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
1595 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1596 graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
1598 /* optional x and y pixel position of animation frame sequence */
1599 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1600 graphic_info[graphic].src_x = parameter[GFX_ARG_X];
1601 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1602 graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
1604 /* optional width and height of each animation frame */
1605 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1606 graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
1607 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1608 graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
1611 /* optional zoom factor for scaling up the image to a larger size */
1612 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1613 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1614 if (graphic_info[graphic].scale_up_factor < 1)
1615 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
1620 /* get final bitmap size (with scaling, but without small images) */
1621 int src_image_width = get_scaled_graphic_width(graphic);
1622 int src_image_height = get_scaled_graphic_height(graphic);
1624 anim_frames_per_row = src_image_width / graphic_info[graphic].width;
1625 anim_frames_per_col = src_image_height / graphic_info[graphic].height;
1627 graphic_info[graphic].src_image_width = src_image_width;
1628 graphic_info[graphic].src_image_height = src_image_height;
1631 /* correct x or y offset dependent of vertical or horizontal frame order */
1632 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1634 graphic_info[graphic].offset_y =
1635 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1636 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
1637 anim_frames_per_line = anim_frames_per_col;
1639 else /* frames are ordered horizontally */
1641 graphic_info[graphic].offset_x =
1642 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1643 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
1644 anim_frames_per_line = anim_frames_per_row;
1647 /* optionally, the x and y offset of frames can be specified directly */
1648 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1649 graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
1650 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1651 graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
1653 /* optionally, moving animations may have separate start and end graphics */
1654 graphic_info[graphic].double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1656 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1657 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1659 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1660 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1661 graphic_info[graphic].offset2_y =
1662 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1663 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].height);
1664 else /* frames are ordered horizontally */
1665 graphic_info[graphic].offset2_x =
1666 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1667 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].width);
1669 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1670 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1671 graphic_info[graphic].offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1672 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1673 graphic_info[graphic].offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1675 /* optionally, the second movement tile can be specified as start tile */
1676 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1677 graphic_info[graphic].swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1679 /* automatically determine correct number of frames, if not defined */
1680 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1681 graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
1682 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1683 graphic_info[graphic].anim_frames = anim_frames_per_row;
1684 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1685 graphic_info[graphic].anim_frames = anim_frames_per_col;
1687 graphic_info[graphic].anim_frames = 1;
1689 if (graphic_info[graphic].anim_frames == 0) /* frames must be at least 1 */
1690 graphic_info[graphic].anim_frames = 1;
1692 graphic_info[graphic].anim_frames_per_line =
1693 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1694 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1696 graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
1697 if (graphic_info[graphic].anim_delay == 0) /* delay must be at least 1 */
1698 graphic_info[graphic].anim_delay = 1;
1700 graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
1702 if (graphic_info[graphic].anim_frames == 1)
1703 graphic_info[graphic].anim_mode = ANIM_NONE;
1706 /* automatically determine correct start frame, if not defined */
1707 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1708 graphic_info[graphic].anim_start_frame = 0;
1709 else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
1710 graphic_info[graphic].anim_start_frame =
1711 graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1713 graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
1715 /* animation synchronized with global frame counter, not move position */
1716 graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1718 /* optional element for cloning crumble graphics */
1719 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1720 graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1722 /* optional element for cloning digging graphics */
1723 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1724 graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1726 /* optional border size for "crumbling" diggable graphics */
1727 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1728 graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
1730 /* this is only used for player "boring" and "sleeping" actions */
1731 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1732 graphic_info[graphic].anim_delay_fixed =
1733 parameter[GFX_ARG_ANIM_DELAY_FIXED];
1734 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1735 graphic_info[graphic].anim_delay_random =
1736 parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1737 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1738 graphic_info[graphic].post_delay_fixed =
1739 parameter[GFX_ARG_POST_DELAY_FIXED];
1740 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1741 graphic_info[graphic].post_delay_random =
1742 parameter[GFX_ARG_POST_DELAY_RANDOM];
1744 /* this is only used for toon animations */
1745 graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
1746 graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY];
1748 /* this is only used for drawing font characters */
1749 graphic_info[graphic].draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1750 graphic_info[graphic].draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1752 /* this is only used for drawing envelope graphics */
1753 graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1755 /* optional graphic for cloning all graphics settings */
1756 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1757 graphic_info[graphic].clone_from = parameter[GFX_ARG_CLONE_FROM];
1759 /* optional settings for drawing title screens and title messages */
1760 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1761 graphic_info[graphic].fade_mode = parameter[GFX_ARG_FADE_MODE];
1762 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1763 graphic_info[graphic].fade_delay = parameter[GFX_ARG_FADE_DELAY];
1764 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1765 graphic_info[graphic].post_delay = parameter[GFX_ARG_POST_DELAY];
1766 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1767 graphic_info[graphic].auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1768 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1769 graphic_info[graphic].align = parameter[GFX_ARG_ALIGN];
1770 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1771 graphic_info[graphic].valign = parameter[GFX_ARG_VALIGN];
1772 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1773 graphic_info[graphic].sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1776 UPDATE_BUSY_STATE();
1779 static void set_cloned_graphic_parameters(int graphic)
1781 int fallback_graphic = IMG_CHAR_EXCLAM;
1782 int max_num_images = getImageListSize();
1783 int clone_graphic = graphic_info[graphic].clone_from;
1784 int num_references_followed = 1;
1786 while (graphic_info[clone_graphic].clone_from != -1 &&
1787 num_references_followed < max_num_images)
1789 clone_graphic = graphic_info[clone_graphic].clone_from;
1791 num_references_followed++;
1794 if (num_references_followed >= max_num_images)
1796 Error(ERR_INFO_LINE, "-");
1797 Error(ERR_INFO, "warning: error found in config file:");
1798 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1799 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1800 Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1801 Error(ERR_INFO, "custom graphic rejected for this element/action");
1803 if (graphic == fallback_graphic)
1804 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1806 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1807 Error(ERR_INFO_LINE, "-");
1809 graphic_info[graphic] = graphic_info[fallback_graphic];
1813 graphic_info[graphic] = graphic_info[clone_graphic];
1814 graphic_info[graphic].clone_from = clone_graphic;
1818 static void InitGraphicInfo()
1820 int fallback_graphic = IMG_CHAR_EXCLAM;
1821 int num_images = getImageListSize();
1824 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1825 static boolean clipmasks_initialized = FALSE;
1827 XGCValues clip_gc_values;
1828 unsigned long clip_gc_valuemask;
1829 GC copy_clipmask_gc = None;
1832 /* use image size as default values for width and height for these images */
1833 static int full_size_graphics[] =
1838 IMG_BACKGROUND_ENVELOPE_1,
1839 IMG_BACKGROUND_ENVELOPE_2,
1840 IMG_BACKGROUND_ENVELOPE_3,
1841 IMG_BACKGROUND_ENVELOPE_4,
1844 IMG_BACKGROUND_TITLE_INITIAL,
1845 IMG_BACKGROUND_TITLE,
1846 IMG_BACKGROUND_MAIN,
1847 IMG_BACKGROUND_LEVELS,
1848 IMG_BACKGROUND_SCORES,
1849 IMG_BACKGROUND_EDITOR,
1850 IMG_BACKGROUND_INFO,
1851 IMG_BACKGROUND_INFO_ELEMENTS,
1852 IMG_BACKGROUND_INFO_MUSIC,
1853 IMG_BACKGROUND_INFO_CREDITS,
1854 IMG_BACKGROUND_INFO_PROGRAM,
1855 IMG_BACKGROUND_INFO_LEVELSET,
1856 IMG_BACKGROUND_SETUP,
1857 IMG_BACKGROUND_DOOR,
1859 IMG_TITLESCREEN_INITIAL_1,
1860 IMG_TITLESCREEN_INITIAL_2,
1861 IMG_TITLESCREEN_INITIAL_3,
1862 IMG_TITLESCREEN_INITIAL_4,
1863 IMG_TITLESCREEN_INITIAL_5,
1873 checked_free(graphic_info);
1875 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1878 /* initialize "use_image_size" flag with default value */
1879 for (i = 0; i < num_images; i++)
1880 graphic_info[i].use_image_size = FALSE;
1882 /* initialize "use_image_size" flag from static configuration above */
1883 for (i = 0; full_size_graphics[i] != -1; i++)
1884 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1887 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1888 if (clipmasks_initialized)
1890 for (i = 0; i < num_images; i++)
1892 if (graphic_info[i].clip_mask)
1893 XFreePixmap(display, graphic_info[i].clip_mask);
1894 if (graphic_info[i].clip_gc)
1895 XFreeGC(display, graphic_info[i].clip_gc);
1897 graphic_info[i].clip_mask = None;
1898 graphic_info[i].clip_gc = None;
1903 /* first set all graphic paramaters ... */
1904 for (i = 0; i < num_images; i++)
1905 set_graphic_parameters(i);
1907 /* ... then copy these parameters for cloned graphics */
1908 for (i = 0; i < num_images; i++)
1909 if (graphic_info[i].clone_from != -1)
1910 set_cloned_graphic_parameters(i);
1912 for (i = 0; i < num_images; i++)
1917 int first_frame, last_frame;
1918 int src_bitmap_width, src_bitmap_height;
1920 /* now check if no animation frames are outside of the loaded image */
1922 if (graphic_info[i].bitmap == NULL)
1923 continue; /* skip check for optional images that are undefined */
1925 /* get image size (this can differ from the standard element tile size!) */
1926 width = graphic_info[i].width;
1927 height = graphic_info[i].height;
1929 /* get final bitmap size (with scaling, but without small images) */
1930 src_bitmap_width = graphic_info[i].src_image_width;
1931 src_bitmap_height = graphic_info[i].src_image_height;
1933 /* check if first animation frame is inside specified bitmap */
1936 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1939 /* this avoids calculating wrong start position for out-of-bounds frame */
1940 src_x = graphic_info[i].src_x;
1941 src_y = graphic_info[i].src_y;
1944 if (src_x < 0 || src_y < 0 ||
1945 src_x + width > src_bitmap_width ||
1946 src_y + height > src_bitmap_height)
1948 Error(ERR_INFO_LINE, "-");
1949 Error(ERR_INFO, "warning: error found in config file:");
1950 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1951 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1952 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1954 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1955 src_x, src_y, src_bitmap_width, src_bitmap_height);
1956 Error(ERR_INFO, "custom graphic rejected for this element/action");
1958 if (i == fallback_graphic)
1959 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1961 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1962 Error(ERR_INFO_LINE, "-");
1964 graphic_info[i] = graphic_info[fallback_graphic];
1967 /* check if last animation frame is inside specified bitmap */
1969 last_frame = graphic_info[i].anim_frames - 1;
1970 getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1972 if (src_x < 0 || src_y < 0 ||
1973 src_x + width > src_bitmap_width ||
1974 src_y + height > src_bitmap_height)
1976 Error(ERR_INFO_LINE, "-");
1977 Error(ERR_INFO, "warning: error found in config file:");
1978 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1979 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1980 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1982 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1983 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1984 Error(ERR_INFO, "custom graphic rejected for this element/action");
1986 if (i == fallback_graphic)
1987 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1989 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1990 Error(ERR_INFO_LINE, "-");
1992 graphic_info[i] = graphic_info[fallback_graphic];
1995 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1996 /* currently we only need a tile clip mask from the first frame */
1997 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1999 if (copy_clipmask_gc == None)
2001 clip_gc_values.graphics_exposures = False;
2002 clip_gc_valuemask = GCGraphicsExposures;
2003 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
2004 clip_gc_valuemask, &clip_gc_values);
2007 graphic_info[i].clip_mask =
2008 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
2010 src_pixmap = src_bitmap->clip_mask;
2011 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
2012 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
2014 clip_gc_values.graphics_exposures = False;
2015 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
2016 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
2018 graphic_info[i].clip_gc =
2019 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
2023 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
2024 if (copy_clipmask_gc)
2025 XFreeGC(display, copy_clipmask_gc);
2027 clipmasks_initialized = TRUE;
2031 static void InitElementSoundInfo()
2033 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
2034 int num_property_mappings = getSoundListPropertyMappingSize();
2037 /* set values to -1 to identify later as "uninitialized" values */
2038 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2039 for (act = 0; act < NUM_ACTIONS; act++)
2040 element_info[i].sound[act] = -1;
2042 /* initialize element/sound mapping from static configuration */
2043 for (i = 0; element_to_sound[i].element > -1; i++)
2045 int element = element_to_sound[i].element;
2046 int action = element_to_sound[i].action;
2047 int sound = element_to_sound[i].sound;
2048 boolean is_class = element_to_sound[i].is_class;
2051 action = ACTION_DEFAULT;
2054 element_info[element].sound[action] = sound;
2056 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2057 if (strEqual(element_info[j].class_name,
2058 element_info[element].class_name))
2059 element_info[j].sound[action] = sound;
2062 /* initialize element class/sound mapping from dynamic configuration */
2063 for (i = 0; i < num_property_mappings; i++)
2065 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
2066 int action = property_mapping[i].ext1_index;
2067 int sound = property_mapping[i].artwork_index;
2069 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
2073 action = ACTION_DEFAULT;
2075 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2076 if (strEqual(element_info[j].class_name,
2077 element_info[element_class].class_name))
2078 element_info[j].sound[action] = sound;
2081 /* initialize element/sound mapping from dynamic configuration */
2082 for (i = 0; i < num_property_mappings; i++)
2084 int element = property_mapping[i].base_index;
2085 int action = property_mapping[i].ext1_index;
2086 int sound = property_mapping[i].artwork_index;
2088 if (element >= MAX_NUM_ELEMENTS)
2092 action = ACTION_DEFAULT;
2094 element_info[element].sound[action] = sound;
2097 /* now set all '-1' values to element specific default values */
2098 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2100 for (act = 0; act < NUM_ACTIONS; act++)
2102 /* generic default action sound (defined by "[default]" directive) */
2103 int default_action_sound = element_info[EL_DEFAULT].sound[act];
2105 /* look for special default action sound (classic game specific) */
2106 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
2107 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
2108 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
2109 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
2110 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
2111 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
2113 /* !!! there's no such thing as a "default action sound" !!! */
2115 /* look for element specific default sound (independent from action) */
2116 if (element_info[i].sound[ACTION_DEFAULT] != -1)
2117 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
2121 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
2122 /* !!! make this better !!! */
2123 if (i == EL_EMPTY_SPACE)
2124 default_action_sound = element_info[EL_DEFAULT].sound[act];
2127 /* no sound for this specific action -- use default action sound */
2128 if (element_info[i].sound[act] == -1)
2129 element_info[i].sound[act] = default_action_sound;
2133 /* copy sound settings to some elements that are only stored in level file
2134 in native R'n'D levels, but are used by game engine in native EM levels */
2135 for (i = 0; copy_properties[i][0] != -1; i++)
2136 for (j = 1; j <= 4; j++)
2137 for (act = 0; act < NUM_ACTIONS; act++)
2138 element_info[copy_properties[i][j]].sound[act] =
2139 element_info[copy_properties[i][0]].sound[act];
2142 static void InitGameModeSoundInfo()
2146 /* set values to -1 to identify later as "uninitialized" values */
2147 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2150 /* initialize gamemode/sound mapping from static configuration */
2151 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
2153 int gamemode = gamemode_to_sound[i].gamemode;
2154 int sound = gamemode_to_sound[i].sound;
2157 gamemode = GAME_MODE_DEFAULT;
2159 menu.sound[gamemode] = sound;
2162 /* now set all '-1' values to levelset specific default values */
2163 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2164 if (menu.sound[i] == -1)
2165 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
2168 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2169 if (menu.sound[i] != -1)
2170 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
2174 static void set_sound_parameters(int sound, char **parameter_raw)
2176 int parameter[NUM_SND_ARGS];
2179 /* get integer values from string parameters */
2180 for (i = 0; i < NUM_SND_ARGS; i++)
2182 get_parameter_value(parameter_raw[i],
2183 sound_config_suffix[i].token,
2184 sound_config_suffix[i].type);
2186 /* explicit loop mode setting in configuration overrides default value */
2187 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2188 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
2190 /* sound volume to change the original volume when loading the sound file */
2191 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
2193 /* sound priority to give certain sounds a higher or lower priority */
2194 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
2197 static void InitSoundInfo()
2199 int *sound_effect_properties;
2200 int num_sounds = getSoundListSize();
2203 checked_free(sound_info);
2205 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
2206 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
2208 /* initialize sound effect for all elements to "no sound" */
2209 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2210 for (j = 0; j < NUM_ACTIONS; j++)
2211 element_info[i].sound[j] = SND_UNDEFINED;
2213 for (i = 0; i < num_sounds; i++)
2215 struct FileInfo *sound = getSoundListEntry(i);
2216 int len_effect_text = strlen(sound->token);
2218 sound_effect_properties[i] = ACTION_OTHER;
2219 sound_info[i].loop = FALSE; /* default: play sound only once */
2222 printf("::: sound %d: '%s'\n", i, sound->token);
2225 /* determine all loop sounds and identify certain sound classes */
2227 for (j = 0; element_action_info[j].suffix; j++)
2229 int len_action_text = strlen(element_action_info[j].suffix);
2231 if (len_action_text < len_effect_text &&
2232 strEqual(&sound->token[len_effect_text - len_action_text],
2233 element_action_info[j].suffix))
2235 sound_effect_properties[i] = element_action_info[j].value;
2236 sound_info[i].loop = element_action_info[j].is_loop_sound;
2242 /* associate elements and some selected sound actions */
2244 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2246 if (element_info[j].class_name)
2248 int len_class_text = strlen(element_info[j].class_name);
2250 if (len_class_text + 1 < len_effect_text &&
2251 strncmp(sound->token,
2252 element_info[j].class_name, len_class_text) == 0 &&
2253 sound->token[len_class_text] == '.')
2255 int sound_action_value = sound_effect_properties[i];
2257 element_info[j].sound[sound_action_value] = i;
2262 set_sound_parameters(i, sound->parameter);
2265 free(sound_effect_properties);
2268 static void InitGameModeMusicInfo()
2270 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
2271 int num_property_mappings = getMusicListPropertyMappingSize();
2272 int default_levelset_music = -1;
2275 /* set values to -1 to identify later as "uninitialized" values */
2276 for (i = 0; i < MAX_LEVELS; i++)
2277 levelset.music[i] = -1;
2278 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2281 /* initialize gamemode/music mapping from static configuration */
2282 for (i = 0; gamemode_to_music[i].music > -1; i++)
2284 int gamemode = gamemode_to_music[i].gamemode;
2285 int music = gamemode_to_music[i].music;
2288 printf("::: gamemode == %d, music == %d\n", gamemode, music);
2292 gamemode = GAME_MODE_DEFAULT;
2294 menu.music[gamemode] = music;
2297 /* initialize gamemode/music mapping from dynamic configuration */
2298 for (i = 0; i < num_property_mappings; i++)
2300 int prefix = property_mapping[i].base_index;
2301 int gamemode = property_mapping[i].ext1_index;
2302 int level = property_mapping[i].ext2_index;
2303 int music = property_mapping[i].artwork_index;
2306 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
2307 prefix, gamemode, level, music);
2310 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
2314 gamemode = GAME_MODE_DEFAULT;
2316 /* level specific music only allowed for in-game music */
2317 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
2318 gamemode = GAME_MODE_PLAYING;
2323 default_levelset_music = music;
2326 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
2327 levelset.music[level] = music;
2328 if (gamemode != GAME_MODE_PLAYING)
2329 menu.music[gamemode] = music;
2332 /* now set all '-1' values to menu specific default values */
2333 /* (undefined values of "levelset.music[]" might stay at "-1" to
2334 allow dynamic selection of music files from music directory!) */
2335 for (i = 0; i < MAX_LEVELS; i++)
2336 if (levelset.music[i] == -1)
2337 levelset.music[i] = default_levelset_music;
2338 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2339 if (menu.music[i] == -1)
2340 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
2343 for (i = 0; i < MAX_LEVELS; i++)
2344 if (levelset.music[i] != -1)
2345 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
2346 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2347 if (menu.music[i] != -1)
2348 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
2352 static void set_music_parameters(int music, char **parameter_raw)
2354 int parameter[NUM_MUS_ARGS];
2357 /* get integer values from string parameters */
2358 for (i = 0; i < NUM_MUS_ARGS; i++)
2360 get_parameter_value(parameter_raw[i],
2361 music_config_suffix[i].token,
2362 music_config_suffix[i].type);
2364 /* explicit loop mode setting in configuration overrides default value */
2365 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2366 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
2369 static void InitMusicInfo()
2371 int num_music = getMusicListSize();
2374 checked_free(music_info);
2376 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
2378 for (i = 0; i < num_music; i++)
2380 struct FileInfo *music = getMusicListEntry(i);
2381 int len_music_text = strlen(music->token);
2383 music_info[i].loop = TRUE; /* default: play music in loop mode */
2385 /* determine all loop music */
2387 for (j = 0; music_prefix_info[j].prefix; j++)
2389 int len_prefix_text = strlen(music_prefix_info[j].prefix);
2391 if (len_prefix_text < len_music_text &&
2392 strncmp(music->token,
2393 music_prefix_info[j].prefix, len_prefix_text) == 0)
2395 music_info[i].loop = music_prefix_info[j].is_loop_music;
2401 set_music_parameters(i, music->parameter);
2405 static void ReinitializeGraphics()
2407 print_timestamp_init("ReinitializeGraphics");
2409 InitGraphicInfo(); /* graphic properties mapping */
2410 print_timestamp_time("InitGraphicInfo");
2411 InitElementGraphicInfo(); /* element game graphic mapping */
2412 print_timestamp_time("InitElementGraphicInfo");
2413 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
2414 print_timestamp_time("InitElementSpecialGraphicInfo");
2416 InitElementSmallImages(); /* scale elements to all needed sizes */
2417 print_timestamp_time("InitElementSmallImages");
2418 InitScaledImages(); /* scale all other images, if needed */
2419 print_timestamp_time("InitScaledImages");
2420 InitFontGraphicInfo(); /* initialize text drawing functions */
2421 print_timestamp_time("InitFontGraphicInfo");
2423 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
2424 print_timestamp_time("InitGraphicInfo_EM");
2426 SetMainBackgroundImage(IMG_BACKGROUND);
2427 print_timestamp_time("SetMainBackgroundImage");
2428 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2429 print_timestamp_time("SetDoorBackgroundImage");
2432 print_timestamp_time("InitGadgets");
2434 print_timestamp_time("InitToons");
2436 print_timestamp_done("ReinitializeGraphics");
2439 static void ReinitializeSounds()
2441 InitSoundInfo(); /* sound properties mapping */
2442 InitElementSoundInfo(); /* element game sound mapping */
2443 InitGameModeSoundInfo(); /* game mode sound mapping */
2445 InitPlayLevelSound(); /* internal game sound settings */
2448 static void ReinitializeMusic()
2450 InitMusicInfo(); /* music properties mapping */
2451 InitGameModeMusicInfo(); /* game mode music mapping */
2454 static int get_special_property_bit(int element, int property_bit_nr)
2456 struct PropertyBitInfo
2462 static struct PropertyBitInfo pb_can_move_into_acid[] =
2464 /* the player may be able fall into acid when gravity is activated */
2469 { EL_SP_MURPHY, 0 },
2470 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2472 /* all elements that can move may be able to also move into acid */
2475 { EL_BUG_RIGHT, 1 },
2478 { EL_SPACESHIP, 2 },
2479 { EL_SPACESHIP_LEFT, 2 },
2480 { EL_SPACESHIP_RIGHT, 2 },
2481 { EL_SPACESHIP_UP, 2 },
2482 { EL_SPACESHIP_DOWN, 2 },
2483 { EL_BD_BUTTERFLY, 3 },
2484 { EL_BD_BUTTERFLY_LEFT, 3 },
2485 { EL_BD_BUTTERFLY_RIGHT, 3 },
2486 { EL_BD_BUTTERFLY_UP, 3 },
2487 { EL_BD_BUTTERFLY_DOWN, 3 },
2488 { EL_BD_FIREFLY, 4 },
2489 { EL_BD_FIREFLY_LEFT, 4 },
2490 { EL_BD_FIREFLY_RIGHT, 4 },
2491 { EL_BD_FIREFLY_UP, 4 },
2492 { EL_BD_FIREFLY_DOWN, 4 },
2494 { EL_YAMYAM_LEFT, 5 },
2495 { EL_YAMYAM_RIGHT, 5 },
2496 { EL_YAMYAM_UP, 5 },
2497 { EL_YAMYAM_DOWN, 5 },
2498 { EL_DARK_YAMYAM, 6 },
2501 { EL_PACMAN_LEFT, 8 },
2502 { EL_PACMAN_RIGHT, 8 },
2503 { EL_PACMAN_UP, 8 },
2504 { EL_PACMAN_DOWN, 8 },
2506 { EL_MOLE_LEFT, 9 },
2507 { EL_MOLE_RIGHT, 9 },
2509 { EL_MOLE_DOWN, 9 },
2513 { EL_SATELLITE, 13 },
2514 { EL_SP_SNIKSNAK, 14 },
2515 { EL_SP_ELECTRON, 15 },
2518 { EL_EMC_ANDROID, 18 },
2523 static struct PropertyBitInfo pb_dont_collide_with[] =
2525 { EL_SP_SNIKSNAK, 0 },
2526 { EL_SP_ELECTRON, 1 },
2534 struct PropertyBitInfo *pb_info;
2537 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2538 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2543 struct PropertyBitInfo *pb_info = NULL;
2546 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2547 if (pb_definition[i].bit_nr == property_bit_nr)
2548 pb_info = pb_definition[i].pb_info;
2550 if (pb_info == NULL)
2553 for (i = 0; pb_info[i].element != -1; i++)
2554 if (pb_info[i].element == element)
2555 return pb_info[i].bit_nr;
2560 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2561 boolean property_value)
2563 int bit_nr = get_special_property_bit(element, property_bit_nr);
2568 *bitfield |= (1 << bit_nr);
2570 *bitfield &= ~(1 << bit_nr);
2574 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2576 int bit_nr = get_special_property_bit(element, property_bit_nr);
2579 return ((*bitfield & (1 << bit_nr)) != 0);
2584 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2586 static int group_nr;
2587 static struct ElementGroupInfo *group;
2588 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2591 if (actual_group == NULL) /* not yet initialized */
2594 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
2596 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2597 group_element - EL_GROUP_START + 1);
2599 /* replace element which caused too deep recursion by question mark */
2600 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2605 if (recursion_depth == 0) /* initialization */
2607 group = actual_group;
2608 group_nr = GROUP_NR(group_element);
2610 group->num_elements_resolved = 0;
2611 group->choice_pos = 0;
2613 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2614 element_info[i].in_group[group_nr] = FALSE;
2617 for (i = 0; i < actual_group->num_elements; i++)
2619 int element = actual_group->element[i];
2621 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2624 if (IS_GROUP_ELEMENT(element))
2625 ResolveGroupElementExt(element, recursion_depth + 1);
2628 group->element_resolved[group->num_elements_resolved++] = element;
2629 element_info[element].in_group[group_nr] = TRUE;
2634 void ResolveGroupElement(int group_element)
2636 ResolveGroupElementExt(group_element, 0);
2639 void InitElementPropertiesStatic()
2641 static boolean clipboard_elements_initialized = FALSE;
2643 static int ep_diggable[] =
2648 EL_SP_BUGGY_BASE_ACTIVATING,
2651 EL_INVISIBLE_SAND_ACTIVE,
2654 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2655 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2660 EL_SP_BUGGY_BASE_ACTIVE,
2667 static int ep_collectible_only[] =
2689 EL_DYNABOMB_INCREASE_NUMBER,
2690 EL_DYNABOMB_INCREASE_SIZE,
2691 EL_DYNABOMB_INCREASE_POWER,
2709 /* !!! handle separately !!! */
2710 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2716 static int ep_dont_run_into[] =
2718 /* same elements as in 'ep_dont_touch' */
2724 /* same elements as in 'ep_dont_collide_with' */
2736 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2741 EL_SP_BUGGY_BASE_ACTIVE,
2748 static int ep_dont_collide_with[] =
2750 /* same elements as in 'ep_dont_touch' */
2767 static int ep_dont_touch[] =
2777 static int ep_indestructible[] =
2781 EL_ACID_POOL_TOPLEFT,
2782 EL_ACID_POOL_TOPRIGHT,
2783 EL_ACID_POOL_BOTTOMLEFT,
2784 EL_ACID_POOL_BOTTOM,
2785 EL_ACID_POOL_BOTTOMRIGHT,
2786 EL_SP_HARDWARE_GRAY,
2787 EL_SP_HARDWARE_GREEN,
2788 EL_SP_HARDWARE_BLUE,
2790 EL_SP_HARDWARE_YELLOW,
2791 EL_SP_HARDWARE_BASE_1,
2792 EL_SP_HARDWARE_BASE_2,
2793 EL_SP_HARDWARE_BASE_3,
2794 EL_SP_HARDWARE_BASE_4,
2795 EL_SP_HARDWARE_BASE_5,
2796 EL_SP_HARDWARE_BASE_6,
2797 EL_INVISIBLE_STEELWALL,
2798 EL_INVISIBLE_STEELWALL_ACTIVE,
2799 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2800 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2801 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2802 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2803 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2804 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2805 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2806 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2807 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2808 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2809 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2810 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2812 EL_LIGHT_SWITCH_ACTIVE,
2813 EL_SIGN_EXCLAMATION,
2814 EL_SIGN_RADIOACTIVITY,
2821 EL_SIGN_ENTRY_FORBIDDEN,
2822 EL_SIGN_EMERGENCY_EXIT,
2830 EL_STEEL_EXIT_CLOSED,
2832 EL_EM_STEEL_EXIT_CLOSED,
2833 EL_EM_STEEL_EXIT_OPEN,
2834 EL_DC_STEELWALL_1_LEFT,
2835 EL_DC_STEELWALL_1_RIGHT,
2836 EL_DC_STEELWALL_1_TOP,
2837 EL_DC_STEELWALL_1_BOTTOM,
2838 EL_DC_STEELWALL_1_HORIZONTAL,
2839 EL_DC_STEELWALL_1_VERTICAL,
2840 EL_DC_STEELWALL_1_TOPLEFT,
2841 EL_DC_STEELWALL_1_TOPRIGHT,
2842 EL_DC_STEELWALL_1_BOTTOMLEFT,
2843 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2844 EL_DC_STEELWALL_1_TOPLEFT_2,
2845 EL_DC_STEELWALL_1_TOPRIGHT_2,
2846 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2847 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2848 EL_DC_STEELWALL_2_LEFT,
2849 EL_DC_STEELWALL_2_RIGHT,
2850 EL_DC_STEELWALL_2_TOP,
2851 EL_DC_STEELWALL_2_BOTTOM,
2852 EL_DC_STEELWALL_2_HORIZONTAL,
2853 EL_DC_STEELWALL_2_VERTICAL,
2854 EL_DC_STEELWALL_2_MIDDLE,
2855 EL_DC_STEELWALL_2_SINGLE,
2856 EL_STEELWALL_SLIPPERY,
2870 EL_GATE_1_GRAY_ACTIVE,
2871 EL_GATE_2_GRAY_ACTIVE,
2872 EL_GATE_3_GRAY_ACTIVE,
2873 EL_GATE_4_GRAY_ACTIVE,
2882 EL_EM_GATE_1_GRAY_ACTIVE,
2883 EL_EM_GATE_2_GRAY_ACTIVE,
2884 EL_EM_GATE_3_GRAY_ACTIVE,
2885 EL_EM_GATE_4_GRAY_ACTIVE,
2894 EL_EMC_GATE_5_GRAY_ACTIVE,
2895 EL_EMC_GATE_6_GRAY_ACTIVE,
2896 EL_EMC_GATE_7_GRAY_ACTIVE,
2897 EL_EMC_GATE_8_GRAY_ACTIVE,
2899 EL_DC_GATE_WHITE_GRAY,
2900 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2901 EL_DC_GATE_FAKE_GRAY,
2903 EL_SWITCHGATE_OPENING,
2904 EL_SWITCHGATE_CLOSED,
2905 EL_SWITCHGATE_CLOSING,
2907 EL_DC_SWITCHGATE_SWITCH_UP,
2908 EL_DC_SWITCHGATE_SWITCH_DOWN,
2911 EL_TIMEGATE_OPENING,
2913 EL_TIMEGATE_CLOSING,
2915 EL_DC_TIMEGATE_SWITCH,
2916 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2921 EL_TUBE_VERTICAL_LEFT,
2922 EL_TUBE_VERTICAL_RIGHT,
2923 EL_TUBE_HORIZONTAL_UP,
2924 EL_TUBE_HORIZONTAL_DOWN,
2929 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2930 EL_EXPANDABLE_STEELWALL_VERTICAL,
2931 EL_EXPANDABLE_STEELWALL_ANY,
2936 static int ep_slippery[] =
2950 EL_ROBOT_WHEEL_ACTIVE,
2956 EL_ACID_POOL_TOPLEFT,
2957 EL_ACID_POOL_TOPRIGHT,
2967 EL_STEELWALL_SLIPPERY,
2970 EL_EMC_WALL_SLIPPERY_1,
2971 EL_EMC_WALL_SLIPPERY_2,
2972 EL_EMC_WALL_SLIPPERY_3,
2973 EL_EMC_WALL_SLIPPERY_4,
2975 EL_EMC_MAGIC_BALL_ACTIVE,
2980 static int ep_can_change[] =
2985 static int ep_can_move[] =
2987 /* same elements as in 'pb_can_move_into_acid' */
3010 static int ep_can_fall[] =
3024 EL_QUICKSAND_FAST_FULL,
3026 EL_BD_MAGIC_WALL_FULL,
3027 EL_DC_MAGIC_WALL_FULL,
3041 static int ep_can_smash_player[] =
3067 static int ep_can_smash_enemies[] =
3076 static int ep_can_smash_everything[] =
3085 static int ep_explodes_by_fire[] =
3087 /* same elements as in 'ep_explodes_impact' */
3092 /* same elements as in 'ep_explodes_smashed' */
3102 EL_EM_DYNAMITE_ACTIVE,
3103 EL_DYNABOMB_PLAYER_1_ACTIVE,
3104 EL_DYNABOMB_PLAYER_2_ACTIVE,
3105 EL_DYNABOMB_PLAYER_3_ACTIVE,
3106 EL_DYNABOMB_PLAYER_4_ACTIVE,
3107 EL_DYNABOMB_INCREASE_NUMBER,
3108 EL_DYNABOMB_INCREASE_SIZE,
3109 EL_DYNABOMB_INCREASE_POWER,
3110 EL_SP_DISK_RED_ACTIVE,
3124 static int ep_explodes_smashed[] =
3126 /* same elements as in 'ep_explodes_impact' */
3140 static int ep_explodes_impact[] =
3149 static int ep_walkable_over[] =
3153 EL_SOKOBAN_FIELD_EMPTY,
3159 EL_EM_STEEL_EXIT_OPEN,
3168 EL_GATE_1_GRAY_ACTIVE,
3169 EL_GATE_2_GRAY_ACTIVE,
3170 EL_GATE_3_GRAY_ACTIVE,
3171 EL_GATE_4_GRAY_ACTIVE,
3179 static int ep_walkable_inside[] =
3184 EL_TUBE_VERTICAL_LEFT,
3185 EL_TUBE_VERTICAL_RIGHT,
3186 EL_TUBE_HORIZONTAL_UP,
3187 EL_TUBE_HORIZONTAL_DOWN,
3196 static int ep_walkable_under[] =
3201 static int ep_passable_over[] =
3211 EL_EM_GATE_1_GRAY_ACTIVE,
3212 EL_EM_GATE_2_GRAY_ACTIVE,
3213 EL_EM_GATE_3_GRAY_ACTIVE,
3214 EL_EM_GATE_4_GRAY_ACTIVE,
3223 EL_EMC_GATE_5_GRAY_ACTIVE,
3224 EL_EMC_GATE_6_GRAY_ACTIVE,
3225 EL_EMC_GATE_7_GRAY_ACTIVE,
3226 EL_EMC_GATE_8_GRAY_ACTIVE,
3228 EL_DC_GATE_WHITE_GRAY,
3229 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3236 static int ep_passable_inside[] =
3242 EL_SP_PORT_HORIZONTAL,
3243 EL_SP_PORT_VERTICAL,
3245 EL_SP_GRAVITY_PORT_LEFT,
3246 EL_SP_GRAVITY_PORT_RIGHT,
3247 EL_SP_GRAVITY_PORT_UP,
3248 EL_SP_GRAVITY_PORT_DOWN,
3249 EL_SP_GRAVITY_ON_PORT_LEFT,
3250 EL_SP_GRAVITY_ON_PORT_RIGHT,
3251 EL_SP_GRAVITY_ON_PORT_UP,
3252 EL_SP_GRAVITY_ON_PORT_DOWN,
3253 EL_SP_GRAVITY_OFF_PORT_LEFT,
3254 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3255 EL_SP_GRAVITY_OFF_PORT_UP,
3256 EL_SP_GRAVITY_OFF_PORT_DOWN,
3261 static int ep_passable_under[] =
3266 static int ep_droppable[] =
3271 static int ep_explodes_1x1_old[] =
3276 static int ep_pushable[] =
3288 EL_SOKOBAN_FIELD_FULL,
3297 static int ep_explodes_cross_old[] =
3302 static int ep_protected[] =
3304 /* same elements as in 'ep_walkable_inside' */
3308 EL_TUBE_VERTICAL_LEFT,
3309 EL_TUBE_VERTICAL_RIGHT,
3310 EL_TUBE_HORIZONTAL_UP,
3311 EL_TUBE_HORIZONTAL_DOWN,
3317 /* same elements as in 'ep_passable_over' */
3326 EL_EM_GATE_1_GRAY_ACTIVE,
3327 EL_EM_GATE_2_GRAY_ACTIVE,
3328 EL_EM_GATE_3_GRAY_ACTIVE,
3329 EL_EM_GATE_4_GRAY_ACTIVE,
3338 EL_EMC_GATE_5_GRAY_ACTIVE,
3339 EL_EMC_GATE_6_GRAY_ACTIVE,
3340 EL_EMC_GATE_7_GRAY_ACTIVE,
3341 EL_EMC_GATE_8_GRAY_ACTIVE,
3343 EL_DC_GATE_WHITE_GRAY,
3344 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3348 /* same elements as in 'ep_passable_inside' */
3353 EL_SP_PORT_HORIZONTAL,
3354 EL_SP_PORT_VERTICAL,
3356 EL_SP_GRAVITY_PORT_LEFT,
3357 EL_SP_GRAVITY_PORT_RIGHT,
3358 EL_SP_GRAVITY_PORT_UP,
3359 EL_SP_GRAVITY_PORT_DOWN,
3360 EL_SP_GRAVITY_ON_PORT_LEFT,
3361 EL_SP_GRAVITY_ON_PORT_RIGHT,
3362 EL_SP_GRAVITY_ON_PORT_UP,
3363 EL_SP_GRAVITY_ON_PORT_DOWN,
3364 EL_SP_GRAVITY_OFF_PORT_LEFT,
3365 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3366 EL_SP_GRAVITY_OFF_PORT_UP,
3367 EL_SP_GRAVITY_OFF_PORT_DOWN,
3372 static int ep_throwable[] =
3377 static int ep_can_explode[] =
3379 /* same elements as in 'ep_explodes_impact' */
3384 /* same elements as in 'ep_explodes_smashed' */
3390 /* elements that can explode by explosion or by dragonfire */
3394 EL_EM_DYNAMITE_ACTIVE,
3395 EL_DYNABOMB_PLAYER_1_ACTIVE,
3396 EL_DYNABOMB_PLAYER_2_ACTIVE,
3397 EL_DYNABOMB_PLAYER_3_ACTIVE,
3398 EL_DYNABOMB_PLAYER_4_ACTIVE,
3399 EL_DYNABOMB_INCREASE_NUMBER,
3400 EL_DYNABOMB_INCREASE_SIZE,
3401 EL_DYNABOMB_INCREASE_POWER,
3402 EL_SP_DISK_RED_ACTIVE,
3410 /* elements that can explode only by explosion */
3416 static int ep_gravity_reachable[] =
3422 EL_INVISIBLE_SAND_ACTIVE,
3427 EL_SP_PORT_HORIZONTAL,
3428 EL_SP_PORT_VERTICAL,
3430 EL_SP_GRAVITY_PORT_LEFT,
3431 EL_SP_GRAVITY_PORT_RIGHT,
3432 EL_SP_GRAVITY_PORT_UP,
3433 EL_SP_GRAVITY_PORT_DOWN,
3434 EL_SP_GRAVITY_ON_PORT_LEFT,
3435 EL_SP_GRAVITY_ON_PORT_RIGHT,
3436 EL_SP_GRAVITY_ON_PORT_UP,
3437 EL_SP_GRAVITY_ON_PORT_DOWN,
3438 EL_SP_GRAVITY_OFF_PORT_LEFT,
3439 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3440 EL_SP_GRAVITY_OFF_PORT_UP,
3441 EL_SP_GRAVITY_OFF_PORT_DOWN,
3447 static int ep_player[] =
3454 EL_SOKOBAN_FIELD_PLAYER,
3460 static int ep_can_pass_magic_wall[] =
3474 static int ep_can_pass_dc_magic_wall[] =
3490 static int ep_switchable[] =
3494 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3495 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3496 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3497 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3498 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3499 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3500 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3501 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3502 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3503 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3504 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3505 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3506 EL_SWITCHGATE_SWITCH_UP,
3507 EL_SWITCHGATE_SWITCH_DOWN,
3508 EL_DC_SWITCHGATE_SWITCH_UP,
3509 EL_DC_SWITCHGATE_SWITCH_DOWN,
3511 EL_LIGHT_SWITCH_ACTIVE,
3513 EL_DC_TIMEGATE_SWITCH,
3514 EL_BALLOON_SWITCH_LEFT,
3515 EL_BALLOON_SWITCH_RIGHT,
3516 EL_BALLOON_SWITCH_UP,
3517 EL_BALLOON_SWITCH_DOWN,
3518 EL_BALLOON_SWITCH_ANY,
3519 EL_BALLOON_SWITCH_NONE,
3522 EL_EMC_MAGIC_BALL_SWITCH,
3523 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3528 static int ep_bd_element[] =
3562 static int ep_sp_element[] =
3564 /* should always be valid */
3567 /* standard classic Supaplex elements */
3574 EL_SP_HARDWARE_GRAY,
3582 EL_SP_GRAVITY_PORT_RIGHT,
3583 EL_SP_GRAVITY_PORT_DOWN,
3584 EL_SP_GRAVITY_PORT_LEFT,
3585 EL_SP_GRAVITY_PORT_UP,
3590 EL_SP_PORT_VERTICAL,
3591 EL_SP_PORT_HORIZONTAL,
3597 EL_SP_HARDWARE_BASE_1,
3598 EL_SP_HARDWARE_GREEN,
3599 EL_SP_HARDWARE_BLUE,
3601 EL_SP_HARDWARE_YELLOW,
3602 EL_SP_HARDWARE_BASE_2,
3603 EL_SP_HARDWARE_BASE_3,
3604 EL_SP_HARDWARE_BASE_4,
3605 EL_SP_HARDWARE_BASE_5,
3606 EL_SP_HARDWARE_BASE_6,
3610 /* additional elements that appeared in newer Supaplex levels */
3613 /* additional gravity port elements (not switching, but setting gravity) */
3614 EL_SP_GRAVITY_ON_PORT_LEFT,
3615 EL_SP_GRAVITY_ON_PORT_RIGHT,
3616 EL_SP_GRAVITY_ON_PORT_UP,
3617 EL_SP_GRAVITY_ON_PORT_DOWN,
3618 EL_SP_GRAVITY_OFF_PORT_LEFT,
3619 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3620 EL_SP_GRAVITY_OFF_PORT_UP,
3621 EL_SP_GRAVITY_OFF_PORT_DOWN,
3623 /* more than one Murphy in a level results in an inactive clone */
3626 /* runtime Supaplex elements */
3627 EL_SP_DISK_RED_ACTIVE,
3628 EL_SP_TERMINAL_ACTIVE,
3629 EL_SP_BUGGY_BASE_ACTIVATING,
3630 EL_SP_BUGGY_BASE_ACTIVE,
3637 static int ep_sb_element[] =
3642 EL_SOKOBAN_FIELD_EMPTY,
3643 EL_SOKOBAN_FIELD_FULL,
3644 EL_SOKOBAN_FIELD_PLAYER,
3649 EL_INVISIBLE_STEELWALL,
3654 static int ep_gem[] =
3666 static int ep_food_dark_yamyam[] =
3694 static int ep_food_penguin[] =
3708 static int ep_food_pig[] =
3720 static int ep_historic_wall[] =
3731 EL_GATE_1_GRAY_ACTIVE,
3732 EL_GATE_2_GRAY_ACTIVE,
3733 EL_GATE_3_GRAY_ACTIVE,
3734 EL_GATE_4_GRAY_ACTIVE,
3743 EL_EM_GATE_1_GRAY_ACTIVE,
3744 EL_EM_GATE_2_GRAY_ACTIVE,
3745 EL_EM_GATE_3_GRAY_ACTIVE,
3746 EL_EM_GATE_4_GRAY_ACTIVE,
3753 EL_EXPANDABLE_WALL_HORIZONTAL,
3754 EL_EXPANDABLE_WALL_VERTICAL,
3755 EL_EXPANDABLE_WALL_ANY,
3756 EL_EXPANDABLE_WALL_GROWING,
3757 EL_BD_EXPANDABLE_WALL,
3764 EL_SP_HARDWARE_GRAY,
3765 EL_SP_HARDWARE_GREEN,
3766 EL_SP_HARDWARE_BLUE,
3768 EL_SP_HARDWARE_YELLOW,
3769 EL_SP_HARDWARE_BASE_1,
3770 EL_SP_HARDWARE_BASE_2,
3771 EL_SP_HARDWARE_BASE_3,
3772 EL_SP_HARDWARE_BASE_4,
3773 EL_SP_HARDWARE_BASE_5,
3774 EL_SP_HARDWARE_BASE_6,
3776 EL_SP_TERMINAL_ACTIVE,
3779 EL_INVISIBLE_STEELWALL,
3780 EL_INVISIBLE_STEELWALL_ACTIVE,
3782 EL_INVISIBLE_WALL_ACTIVE,
3783 EL_STEELWALL_SLIPPERY,
3800 static int ep_historic_solid[] =
3804 EL_EXPANDABLE_WALL_HORIZONTAL,
3805 EL_EXPANDABLE_WALL_VERTICAL,
3806 EL_EXPANDABLE_WALL_ANY,
3807 EL_BD_EXPANDABLE_WALL,
3820 EL_QUICKSAND_FILLING,
3821 EL_QUICKSAND_EMPTYING,
3823 EL_MAGIC_WALL_ACTIVE,
3824 EL_MAGIC_WALL_EMPTYING,
3825 EL_MAGIC_WALL_FILLING,
3829 EL_BD_MAGIC_WALL_ACTIVE,
3830 EL_BD_MAGIC_WALL_EMPTYING,
3831 EL_BD_MAGIC_WALL_FULL,
3832 EL_BD_MAGIC_WALL_FILLING,
3833 EL_BD_MAGIC_WALL_DEAD,
3842 EL_SP_TERMINAL_ACTIVE,
3846 EL_INVISIBLE_WALL_ACTIVE,
3847 EL_SWITCHGATE_SWITCH_UP,
3848 EL_SWITCHGATE_SWITCH_DOWN,
3849 EL_DC_SWITCHGATE_SWITCH_UP,
3850 EL_DC_SWITCHGATE_SWITCH_DOWN,
3852 EL_TIMEGATE_SWITCH_ACTIVE,
3853 EL_DC_TIMEGATE_SWITCH,
3854 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3866 /* the following elements are a direct copy of "indestructible" elements,
3867 except "EL_ACID", which is "indestructible", but not "solid"! */
3872 EL_ACID_POOL_TOPLEFT,
3873 EL_ACID_POOL_TOPRIGHT,
3874 EL_ACID_POOL_BOTTOMLEFT,
3875 EL_ACID_POOL_BOTTOM,
3876 EL_ACID_POOL_BOTTOMRIGHT,
3877 EL_SP_HARDWARE_GRAY,
3878 EL_SP_HARDWARE_GREEN,
3879 EL_SP_HARDWARE_BLUE,
3881 EL_SP_HARDWARE_YELLOW,
3882 EL_SP_HARDWARE_BASE_1,
3883 EL_SP_HARDWARE_BASE_2,
3884 EL_SP_HARDWARE_BASE_3,
3885 EL_SP_HARDWARE_BASE_4,
3886 EL_SP_HARDWARE_BASE_5,
3887 EL_SP_HARDWARE_BASE_6,
3888 EL_INVISIBLE_STEELWALL,
3889 EL_INVISIBLE_STEELWALL_ACTIVE,
3890 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3891 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3892 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3893 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3894 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3895 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3896 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3897 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3898 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3899 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3900 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3901 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3903 EL_LIGHT_SWITCH_ACTIVE,
3904 EL_SIGN_EXCLAMATION,
3905 EL_SIGN_RADIOACTIVITY,
3912 EL_SIGN_ENTRY_FORBIDDEN,
3913 EL_SIGN_EMERGENCY_EXIT,
3921 EL_STEEL_EXIT_CLOSED,
3923 EL_DC_STEELWALL_1_LEFT,
3924 EL_DC_STEELWALL_1_RIGHT,
3925 EL_DC_STEELWALL_1_TOP,
3926 EL_DC_STEELWALL_1_BOTTOM,
3927 EL_DC_STEELWALL_1_HORIZONTAL,
3928 EL_DC_STEELWALL_1_VERTICAL,
3929 EL_DC_STEELWALL_1_TOPLEFT,
3930 EL_DC_STEELWALL_1_TOPRIGHT,
3931 EL_DC_STEELWALL_1_BOTTOMLEFT,
3932 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3933 EL_DC_STEELWALL_1_TOPLEFT_2,
3934 EL_DC_STEELWALL_1_TOPRIGHT_2,
3935 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3936 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3937 EL_DC_STEELWALL_2_LEFT,
3938 EL_DC_STEELWALL_2_RIGHT,
3939 EL_DC_STEELWALL_2_TOP,
3940 EL_DC_STEELWALL_2_BOTTOM,
3941 EL_DC_STEELWALL_2_HORIZONTAL,
3942 EL_DC_STEELWALL_2_VERTICAL,
3943 EL_DC_STEELWALL_2_MIDDLE,
3944 EL_DC_STEELWALL_2_SINGLE,
3945 EL_STEELWALL_SLIPPERY,
3959 EL_GATE_1_GRAY_ACTIVE,
3960 EL_GATE_2_GRAY_ACTIVE,
3961 EL_GATE_3_GRAY_ACTIVE,
3962 EL_GATE_4_GRAY_ACTIVE,
3971 EL_EM_GATE_1_GRAY_ACTIVE,
3972 EL_EM_GATE_2_GRAY_ACTIVE,
3973 EL_EM_GATE_3_GRAY_ACTIVE,
3974 EL_EM_GATE_4_GRAY_ACTIVE,
3976 EL_SWITCHGATE_OPENING,
3977 EL_SWITCHGATE_CLOSED,
3978 EL_SWITCHGATE_CLOSING,
3980 EL_TIMEGATE_OPENING,
3982 EL_TIMEGATE_CLOSING,
3986 EL_TUBE_VERTICAL_LEFT,
3987 EL_TUBE_VERTICAL_RIGHT,
3988 EL_TUBE_HORIZONTAL_UP,
3989 EL_TUBE_HORIZONTAL_DOWN,
3998 static int ep_classic_enemy[] =
4015 static int ep_belt[] =
4017 EL_CONVEYOR_BELT_1_LEFT,
4018 EL_CONVEYOR_BELT_1_MIDDLE,
4019 EL_CONVEYOR_BELT_1_RIGHT,
4020 EL_CONVEYOR_BELT_2_LEFT,
4021 EL_CONVEYOR_BELT_2_MIDDLE,
4022 EL_CONVEYOR_BELT_2_RIGHT,
4023 EL_CONVEYOR_BELT_3_LEFT,
4024 EL_CONVEYOR_BELT_3_MIDDLE,
4025 EL_CONVEYOR_BELT_3_RIGHT,
4026 EL_CONVEYOR_BELT_4_LEFT,
4027 EL_CONVEYOR_BELT_4_MIDDLE,
4028 EL_CONVEYOR_BELT_4_RIGHT,
4033 static int ep_belt_active[] =
4035 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
4036 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
4037 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
4038 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
4039 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
4040 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
4041 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
4042 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
4043 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
4044 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
4045 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
4046 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
4051 static int ep_belt_switch[] =
4053 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4054 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4055 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4056 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4057 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4058 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4059 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4060 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4061 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4062 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4063 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4064 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4069 static int ep_tube[] =
4076 EL_TUBE_HORIZONTAL_UP,
4077 EL_TUBE_HORIZONTAL_DOWN,
4079 EL_TUBE_VERTICAL_LEFT,
4080 EL_TUBE_VERTICAL_RIGHT,
4086 static int ep_acid_pool[] =
4088 EL_ACID_POOL_TOPLEFT,
4089 EL_ACID_POOL_TOPRIGHT,
4090 EL_ACID_POOL_BOTTOMLEFT,
4091 EL_ACID_POOL_BOTTOM,
4092 EL_ACID_POOL_BOTTOMRIGHT,
4097 static int ep_keygate[] =
4107 EL_GATE_1_GRAY_ACTIVE,
4108 EL_GATE_2_GRAY_ACTIVE,
4109 EL_GATE_3_GRAY_ACTIVE,
4110 EL_GATE_4_GRAY_ACTIVE,
4119 EL_EM_GATE_1_GRAY_ACTIVE,
4120 EL_EM_GATE_2_GRAY_ACTIVE,
4121 EL_EM_GATE_3_GRAY_ACTIVE,
4122 EL_EM_GATE_4_GRAY_ACTIVE,
4131 EL_EMC_GATE_5_GRAY_ACTIVE,
4132 EL_EMC_GATE_6_GRAY_ACTIVE,
4133 EL_EMC_GATE_7_GRAY_ACTIVE,
4134 EL_EMC_GATE_8_GRAY_ACTIVE,
4136 EL_DC_GATE_WHITE_GRAY,
4137 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4142 static int ep_amoeboid[] =
4154 static int ep_amoebalive[] =
4165 static int ep_has_editor_content[] =
4187 static int ep_can_turn_each_move[] =
4189 /* !!! do something with this one !!! */
4193 static int ep_can_grow[] =
4207 static int ep_active_bomb[] =
4210 EL_EM_DYNAMITE_ACTIVE,
4211 EL_DYNABOMB_PLAYER_1_ACTIVE,
4212 EL_DYNABOMB_PLAYER_2_ACTIVE,
4213 EL_DYNABOMB_PLAYER_3_ACTIVE,
4214 EL_DYNABOMB_PLAYER_4_ACTIVE,
4215 EL_SP_DISK_RED_ACTIVE,
4220 static int ep_inactive[] =
4230 EL_QUICKSAND_FAST_EMPTY,
4253 EL_GATE_1_GRAY_ACTIVE,
4254 EL_GATE_2_GRAY_ACTIVE,
4255 EL_GATE_3_GRAY_ACTIVE,
4256 EL_GATE_4_GRAY_ACTIVE,
4265 EL_EM_GATE_1_GRAY_ACTIVE,
4266 EL_EM_GATE_2_GRAY_ACTIVE,
4267 EL_EM_GATE_3_GRAY_ACTIVE,
4268 EL_EM_GATE_4_GRAY_ACTIVE,
4277 EL_EMC_GATE_5_GRAY_ACTIVE,
4278 EL_EMC_GATE_6_GRAY_ACTIVE,
4279 EL_EMC_GATE_7_GRAY_ACTIVE,
4280 EL_EMC_GATE_8_GRAY_ACTIVE,
4282 EL_DC_GATE_WHITE_GRAY,
4283 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4284 EL_DC_GATE_FAKE_GRAY,
4287 EL_INVISIBLE_STEELWALL,
4295 EL_WALL_EMERALD_YELLOW,
4296 EL_DYNABOMB_INCREASE_NUMBER,
4297 EL_DYNABOMB_INCREASE_SIZE,
4298 EL_DYNABOMB_INCREASE_POWER,
4302 EL_SOKOBAN_FIELD_EMPTY,
4303 EL_SOKOBAN_FIELD_FULL,
4304 EL_WALL_EMERALD_RED,
4305 EL_WALL_EMERALD_PURPLE,
4306 EL_ACID_POOL_TOPLEFT,
4307 EL_ACID_POOL_TOPRIGHT,
4308 EL_ACID_POOL_BOTTOMLEFT,
4309 EL_ACID_POOL_BOTTOM,
4310 EL_ACID_POOL_BOTTOMRIGHT,
4314 EL_BD_MAGIC_WALL_DEAD,
4316 EL_DC_MAGIC_WALL_DEAD,
4317 EL_AMOEBA_TO_DIAMOND,
4325 EL_SP_GRAVITY_PORT_RIGHT,
4326 EL_SP_GRAVITY_PORT_DOWN,
4327 EL_SP_GRAVITY_PORT_LEFT,
4328 EL_SP_GRAVITY_PORT_UP,
4329 EL_SP_PORT_HORIZONTAL,
4330 EL_SP_PORT_VERTICAL,
4341 EL_SP_HARDWARE_GRAY,
4342 EL_SP_HARDWARE_GREEN,
4343 EL_SP_HARDWARE_BLUE,
4345 EL_SP_HARDWARE_YELLOW,
4346 EL_SP_HARDWARE_BASE_1,
4347 EL_SP_HARDWARE_BASE_2,
4348 EL_SP_HARDWARE_BASE_3,
4349 EL_SP_HARDWARE_BASE_4,
4350 EL_SP_HARDWARE_BASE_5,
4351 EL_SP_HARDWARE_BASE_6,
4352 EL_SP_GRAVITY_ON_PORT_LEFT,
4353 EL_SP_GRAVITY_ON_PORT_RIGHT,
4354 EL_SP_GRAVITY_ON_PORT_UP,
4355 EL_SP_GRAVITY_ON_PORT_DOWN,
4356 EL_SP_GRAVITY_OFF_PORT_LEFT,
4357 EL_SP_GRAVITY_OFF_PORT_RIGHT,
4358 EL_SP_GRAVITY_OFF_PORT_UP,
4359 EL_SP_GRAVITY_OFF_PORT_DOWN,
4360 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4361 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4362 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4363 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4364 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4365 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4366 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4367 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4368 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4369 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4370 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4371 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4372 EL_SIGN_EXCLAMATION,
4373 EL_SIGN_RADIOACTIVITY,
4380 EL_SIGN_ENTRY_FORBIDDEN,
4381 EL_SIGN_EMERGENCY_EXIT,
4389 EL_DC_STEELWALL_1_LEFT,
4390 EL_DC_STEELWALL_1_RIGHT,
4391 EL_DC_STEELWALL_1_TOP,
4392 EL_DC_STEELWALL_1_BOTTOM,
4393 EL_DC_STEELWALL_1_HORIZONTAL,
4394 EL_DC_STEELWALL_1_VERTICAL,
4395 EL_DC_STEELWALL_1_TOPLEFT,
4396 EL_DC_STEELWALL_1_TOPRIGHT,
4397 EL_DC_STEELWALL_1_BOTTOMLEFT,
4398 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4399 EL_DC_STEELWALL_1_TOPLEFT_2,
4400 EL_DC_STEELWALL_1_TOPRIGHT_2,
4401 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4402 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4403 EL_DC_STEELWALL_2_LEFT,
4404 EL_DC_STEELWALL_2_RIGHT,
4405 EL_DC_STEELWALL_2_TOP,
4406 EL_DC_STEELWALL_2_BOTTOM,
4407 EL_DC_STEELWALL_2_HORIZONTAL,
4408 EL_DC_STEELWALL_2_VERTICAL,
4409 EL_DC_STEELWALL_2_MIDDLE,
4410 EL_DC_STEELWALL_2_SINGLE,
4411 EL_STEELWALL_SLIPPERY,
4416 EL_EMC_WALL_SLIPPERY_1,
4417 EL_EMC_WALL_SLIPPERY_2,
4418 EL_EMC_WALL_SLIPPERY_3,
4419 EL_EMC_WALL_SLIPPERY_4,
4440 static int ep_em_slippery_wall[] =
4445 static int ep_gfx_crumbled[] =
4456 static int ep_editor_cascade_active[] =
4458 EL_INTERNAL_CASCADE_BD_ACTIVE,
4459 EL_INTERNAL_CASCADE_EM_ACTIVE,
4460 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4461 EL_INTERNAL_CASCADE_RND_ACTIVE,
4462 EL_INTERNAL_CASCADE_SB_ACTIVE,
4463 EL_INTERNAL_CASCADE_SP_ACTIVE,
4464 EL_INTERNAL_CASCADE_DC_ACTIVE,
4465 EL_INTERNAL_CASCADE_DX_ACTIVE,
4466 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4467 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4468 EL_INTERNAL_CASCADE_CE_ACTIVE,
4469 EL_INTERNAL_CASCADE_GE_ACTIVE,
4470 EL_INTERNAL_CASCADE_REF_ACTIVE,
4471 EL_INTERNAL_CASCADE_USER_ACTIVE,
4472 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4477 static int ep_editor_cascade_inactive[] =
4479 EL_INTERNAL_CASCADE_BD,
4480 EL_INTERNAL_CASCADE_EM,
4481 EL_INTERNAL_CASCADE_EMC,
4482 EL_INTERNAL_CASCADE_RND,
4483 EL_INTERNAL_CASCADE_SB,
4484 EL_INTERNAL_CASCADE_SP,
4485 EL_INTERNAL_CASCADE_DC,
4486 EL_INTERNAL_CASCADE_DX,
4487 EL_INTERNAL_CASCADE_CHARS,
4488 EL_INTERNAL_CASCADE_STEEL_CHARS,
4489 EL_INTERNAL_CASCADE_CE,
4490 EL_INTERNAL_CASCADE_GE,
4491 EL_INTERNAL_CASCADE_REF,
4492 EL_INTERNAL_CASCADE_USER,
4493 EL_INTERNAL_CASCADE_DYNAMIC,
4498 static int ep_obsolete[] =
4502 EL_EM_KEY_1_FILE_OBSOLETE,
4503 EL_EM_KEY_2_FILE_OBSOLETE,
4504 EL_EM_KEY_3_FILE_OBSOLETE,
4505 EL_EM_KEY_4_FILE_OBSOLETE,
4506 EL_ENVELOPE_OBSOLETE,
4515 } element_properties[] =
4517 { ep_diggable, EP_DIGGABLE },
4518 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4519 { ep_dont_run_into, EP_DONT_RUN_INTO },
4520 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4521 { ep_dont_touch, EP_DONT_TOUCH },
4522 { ep_indestructible, EP_INDESTRUCTIBLE },
4523 { ep_slippery, EP_SLIPPERY },
4524 { ep_can_change, EP_CAN_CHANGE },
4525 { ep_can_move, EP_CAN_MOVE },
4526 { ep_can_fall, EP_CAN_FALL },
4527 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4528 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4529 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4530 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4531 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4532 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4533 { ep_walkable_over, EP_WALKABLE_OVER },
4534 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4535 { ep_walkable_under, EP_WALKABLE_UNDER },
4536 { ep_passable_over, EP_PASSABLE_OVER },
4537 { ep_passable_inside, EP_PASSABLE_INSIDE },
4538 { ep_passable_under, EP_PASSABLE_UNDER },
4539 { ep_droppable, EP_DROPPABLE },
4540 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4541 { ep_pushable, EP_PUSHABLE },
4542 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4543 { ep_protected, EP_PROTECTED },
4544 { ep_throwable, EP_THROWABLE },
4545 { ep_can_explode, EP_CAN_EXPLODE },
4546 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4548 { ep_player, EP_PLAYER },
4549 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4550 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4551 { ep_switchable, EP_SWITCHABLE },
4552 { ep_bd_element, EP_BD_ELEMENT },
4553 { ep_sp_element, EP_SP_ELEMENT },
4554 { ep_sb_element, EP_SB_ELEMENT },
4556 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4557 { ep_food_penguin, EP_FOOD_PENGUIN },
4558 { ep_food_pig, EP_FOOD_PIG },
4559 { ep_historic_wall, EP_HISTORIC_WALL },
4560 { ep_historic_solid, EP_HISTORIC_SOLID },
4561 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4562 { ep_belt, EP_BELT },
4563 { ep_belt_active, EP_BELT_ACTIVE },
4564 { ep_belt_switch, EP_BELT_SWITCH },
4565 { ep_tube, EP_TUBE },
4566 { ep_acid_pool, EP_ACID_POOL },
4567 { ep_keygate, EP_KEYGATE },
4568 { ep_amoeboid, EP_AMOEBOID },
4569 { ep_amoebalive, EP_AMOEBALIVE },
4570 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4571 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4572 { ep_can_grow, EP_CAN_GROW },
4573 { ep_active_bomb, EP_ACTIVE_BOMB },
4574 { ep_inactive, EP_INACTIVE },
4576 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4578 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4580 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4581 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4583 { ep_obsolete, EP_OBSOLETE },
4590 /* always start with reliable default values (element has no properties) */
4591 /* (but never initialize clipboard elements after the very first time) */
4592 /* (to be able to use clipboard elements between several levels) */
4593 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4594 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4595 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4596 SET_PROPERTY(i, j, FALSE);
4598 /* set all base element properties from above array definitions */
4599 for (i = 0; element_properties[i].elements != NULL; i++)
4600 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4601 SET_PROPERTY((element_properties[i].elements)[j],
4602 element_properties[i].property, TRUE);
4604 /* copy properties to some elements that are only stored in level file */
4605 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4606 for (j = 0; copy_properties[j][0] != -1; j++)
4607 if (HAS_PROPERTY(copy_properties[j][0], i))
4608 for (k = 1; k <= 4; k++)
4609 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4611 /* set static element properties that are not listed in array definitions */
4612 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4613 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4615 clipboard_elements_initialized = TRUE;
4618 void InitElementPropertiesEngine(int engine_version)
4620 static int no_wall_properties[] =
4623 EP_COLLECTIBLE_ONLY,
4625 EP_DONT_COLLIDE_WITH,
4628 EP_CAN_SMASH_PLAYER,
4629 EP_CAN_SMASH_ENEMIES,
4630 EP_CAN_SMASH_EVERYTHING,
4635 EP_FOOD_DARK_YAMYAM,
4651 /* important: after initialization in InitElementPropertiesStatic(), the
4652 elements are not again initialized to a default value; therefore all
4653 changes have to make sure that they leave the element with a defined
4654 property (which means that conditional property changes must be set to
4655 a reliable default value before) */
4657 /* resolve group elements */
4658 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4659 ResolveGroupElement(EL_GROUP_START + i);
4661 /* set all special, combined or engine dependent element properties */
4662 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4664 /* do not change (already initialized) clipboard elements here */
4665 if (IS_CLIPBOARD_ELEMENT(i))
4668 /* ---------- INACTIVE ------------------------------------------------- */
4669 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4670 i <= EL_CHAR_END) ||
4671 (i >= EL_STEEL_CHAR_START &&
4672 i <= EL_STEEL_CHAR_END)));
4674 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4675 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4676 IS_WALKABLE_INSIDE(i) ||
4677 IS_WALKABLE_UNDER(i)));
4679 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4680 IS_PASSABLE_INSIDE(i) ||
4681 IS_PASSABLE_UNDER(i)));
4683 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4684 IS_PASSABLE_OVER(i)));
4686 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4687 IS_PASSABLE_INSIDE(i)));
4689 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4690 IS_PASSABLE_UNDER(i)));
4692 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4695 /* ---------- COLLECTIBLE ---------------------------------------------- */
4696 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4700 /* ---------- SNAPPABLE ------------------------------------------------ */
4701 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4702 IS_COLLECTIBLE(i) ||
4706 /* ---------- WALL ----------------------------------------------------- */
4707 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4709 for (j = 0; no_wall_properties[j] != -1; j++)
4710 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4711 i >= EL_FIRST_RUNTIME_UNREAL)
4712 SET_PROPERTY(i, EP_WALL, FALSE);
4714 if (IS_HISTORIC_WALL(i))
4715 SET_PROPERTY(i, EP_WALL, TRUE);
4717 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4718 if (engine_version < VERSION_IDENT(2,2,0,0))
4719 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4721 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4723 !IS_COLLECTIBLE(i)));
4725 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4726 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4727 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4729 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4730 IS_INDESTRUCTIBLE(i)));
4732 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4734 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4735 else if (engine_version < VERSION_IDENT(2,2,0,0))
4736 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4738 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4742 if (IS_CUSTOM_ELEMENT(i))
4744 /* these are additional properties which are initially false when set */
4746 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4748 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4749 if (DONT_COLLIDE_WITH(i))
4750 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4752 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4753 if (CAN_SMASH_EVERYTHING(i))
4754 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4755 if (CAN_SMASH_ENEMIES(i))
4756 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4759 /* ---------- CAN_SMASH ------------------------------------------------ */
4760 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4761 CAN_SMASH_ENEMIES(i) ||
4762 CAN_SMASH_EVERYTHING(i)));
4764 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4765 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4766 EXPLODES_BY_FIRE(i)));
4768 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4769 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4770 EXPLODES_SMASHED(i)));
4772 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4773 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4774 EXPLODES_IMPACT(i)));
4776 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4777 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4779 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4780 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4781 i == EL_BLACK_ORB));
4783 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4784 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4786 IS_CUSTOM_ELEMENT(i)));
4788 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4789 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4790 i == EL_SP_ELECTRON));
4792 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4793 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4794 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4795 getMoveIntoAcidProperty(&level, i));
4797 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4798 if (MAYBE_DONT_COLLIDE_WITH(i))
4799 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4800 getDontCollideWithProperty(&level, i));
4802 /* ---------- SP_PORT -------------------------------------------------- */
4803 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4804 IS_PASSABLE_INSIDE(i)));
4806 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4807 for (j = 0; j < level.num_android_clone_elements; j++)
4808 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4810 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4812 /* ---------- CAN_CHANGE ----------------------------------------------- */
4813 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4814 for (j = 0; j < element_info[i].num_change_pages; j++)
4815 if (element_info[i].change_page[j].can_change)
4816 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4818 /* ---------- HAS_ACTION ----------------------------------------------- */
4819 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4820 for (j = 0; j < element_info[i].num_change_pages; j++)
4821 if (element_info[i].change_page[j].has_action)
4822 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4824 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4825 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4828 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4830 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4831 element_info[i].crumbled[ACTION_DEFAULT] !=
4832 element_info[i].graphic[ACTION_DEFAULT]);
4834 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
4835 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4836 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
4839 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4840 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4841 IS_EDITOR_CASCADE_INACTIVE(i)));
4844 /* dynamically adjust element properties according to game engine version */
4846 static int ep_em_slippery_wall[] =
4851 EL_EXPANDABLE_WALL_HORIZONTAL,
4852 EL_EXPANDABLE_WALL_VERTICAL,
4853 EL_EXPANDABLE_WALL_ANY,
4854 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4855 EL_EXPANDABLE_STEELWALL_VERTICAL,
4856 EL_EXPANDABLE_STEELWALL_ANY,
4857 EL_EXPANDABLE_STEELWALL_GROWING,
4861 static int ep_em_explodes_by_fire[] =
4864 EL_EM_DYNAMITE_ACTIVE,
4869 /* special EM style gems behaviour */
4870 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4871 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4872 level.em_slippery_gems);
4874 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4875 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4876 (level.em_slippery_gems &&
4877 engine_version > VERSION_IDENT(2,0,1,0)));
4879 /* special EM style explosion behaviour regarding chain reactions */
4880 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4881 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4882 level.em_explodes_by_fire);
4885 /* this is needed because some graphics depend on element properties */
4886 if (game_status == GAME_MODE_PLAYING)
4887 InitElementGraphicInfo();
4890 void InitElementPropertiesAfterLoading(int engine_version)
4894 /* set some other uninitialized values of custom elements in older levels */
4895 if (engine_version < VERSION_IDENT(3,1,0,0))
4897 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4899 int element = EL_CUSTOM_START + i;
4901 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4903 element_info[element].explosion_delay = 17;
4904 element_info[element].ignition_delay = 8;
4909 void InitElementPropertiesGfxElement()
4913 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4915 struct ElementInfo *ei = &element_info[i];
4917 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4921 static void InitGlobal()
4926 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4928 /* check if element_name_info entry defined for each element in "main.h" */
4929 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4930 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4932 element_info[i].token_name = element_name_info[i].token_name;
4933 element_info[i].class_name = element_name_info[i].class_name;
4934 element_info[i].editor_description= element_name_info[i].editor_description;
4937 printf("%04d: %s\n", i, element_name_info[i].token_name);
4941 /* create hash from image config list */
4942 image_config_hash = newSetupFileHash();
4943 for (i = 0; image_config[i].token != NULL; i++)
4944 setHashEntry(image_config_hash,
4945 image_config[i].token,
4946 image_config[i].value);
4948 /* create hash from element token list */
4949 element_token_hash = newSetupFileHash();
4950 for (i = 0; element_name_info[i].token_name != NULL; i++)
4951 setHashEntry(element_token_hash,
4952 element_name_info[i].token_name,
4955 /* create hash from graphic token list */
4956 graphic_token_hash = newSetupFileHash();
4957 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4958 if (strSuffix(image_config[i].value, ".pcx") ||
4959 strSuffix(image_config[i].value, ".wav") ||
4960 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4961 setHashEntry(graphic_token_hash,
4962 image_config[i].token,
4963 int2str(graphic++, 0));
4965 /* create hash from font token list */
4966 font_token_hash = newSetupFileHash();
4967 for (i = 0; font_info[i].token_name != NULL; i++)
4968 setHashEntry(font_token_hash,
4969 font_info[i].token_name,
4972 /* always start with reliable default values (all elements) */
4973 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4974 ActiveElement[i] = i;
4976 /* now add all entries that have an active state (active elements) */
4977 for (i = 0; element_with_active_state[i].element != -1; i++)
4979 int element = element_with_active_state[i].element;
4980 int element_active = element_with_active_state[i].element_active;
4982 ActiveElement[element] = element_active;
4985 /* always start with reliable default values (all buttons) */
4986 for (i = 0; i < NUM_IMAGE_FILES; i++)
4987 ActiveButton[i] = i;
4989 /* now add all entries that have an active state (active buttons) */
4990 for (i = 0; button_with_active_state[i].button != -1; i++)
4992 int button = button_with_active_state[i].button;
4993 int button_active = button_with_active_state[i].button_active;
4995 ActiveButton[button] = button_active;
4998 /* always start with reliable default values (all fonts) */
4999 for (i = 0; i < NUM_FONTS; i++)
5002 /* now add all entries that have an active state (active fonts) */
5003 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
5005 int font = font_with_active_state[i].font_nr;
5006 int font_active = font_with_active_state[i].font_nr_active;
5008 ActiveFont[font] = font_active;
5011 global.autoplay_leveldir = NULL;
5012 global.convert_leveldir = NULL;
5013 global.create_images_dir = NULL;
5015 global.frames_per_second = 0;
5016 global.fps_slowdown = FALSE;
5017 global.fps_slowdown_factor = 1;
5019 global.border_status = GAME_MODE_MAIN;
5021 global.fading_status = GAME_MODE_MAIN;
5022 global.fading_type = TYPE_ENTER_MENU;
5026 void Execute_Command(char *command)
5030 if (strEqual(command, "print graphicsinfo.conf"))
5032 printf("# You can configure additional/alternative image files here.\n");
5033 printf("# (The entries below are default and therefore commented out.)\n");
5035 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
5037 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5040 for (i = 0; image_config[i].token != NULL; i++)
5041 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
5042 image_config[i].value));
5046 else if (strEqual(command, "print soundsinfo.conf"))
5048 printf("# You can configure additional/alternative sound files here.\n");
5049 printf("# (The entries below are default and therefore commented out.)\n");
5051 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
5053 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5056 for (i = 0; sound_config[i].token != NULL; i++)
5057 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
5058 sound_config[i].value));
5062 else if (strEqual(command, "print musicinfo.conf"))
5064 printf("# You can configure additional/alternative music files here.\n");
5065 printf("# (The entries below are default and therefore commented out.)\n");
5067 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
5069 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5072 for (i = 0; music_config[i].token != NULL; i++)
5073 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
5074 music_config[i].value));
5078 else if (strEqual(command, "print editorsetup.conf"))
5080 printf("# You can configure your personal editor element list here.\n");
5081 printf("# (The entries below are default and therefore commented out.)\n");
5084 /* this is needed to be able to check element list for cascade elements */
5085 InitElementPropertiesStatic();
5086 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5088 PrintEditorElementList();
5092 else if (strEqual(command, "print helpanim.conf"))
5094 printf("# You can configure different element help animations here.\n");
5095 printf("# (The entries below are default and therefore commented out.)\n");
5098 for (i = 0; helpanim_config[i].token != NULL; i++)
5100 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
5101 helpanim_config[i].value));
5103 if (strEqual(helpanim_config[i].token, "end"))
5109 else if (strEqual(command, "print helptext.conf"))
5111 printf("# You can configure different element help text here.\n");
5112 printf("# (The entries below are default and therefore commented out.)\n");
5115 for (i = 0; helptext_config[i].token != NULL; i++)
5116 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
5117 helptext_config[i].value));
5121 else if (strncmp(command, "dump level ", 11) == 0)
5123 char *filename = &command[11];
5125 if (!fileExists(filename))
5126 Error(ERR_EXIT, "cannot open file '%s'", filename);
5128 LoadLevelFromFilename(&level, filename);
5133 else if (strncmp(command, "dump tape ", 10) == 0)
5135 char *filename = &command[10];
5137 if (!fileExists(filename))
5138 Error(ERR_EXIT, "cannot open file '%s'", filename);
5140 LoadTapeFromFilename(filename);
5145 else if (strncmp(command, "autoplay ", 9) == 0)
5147 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
5149 while (*str_ptr != '\0') /* continue parsing string */
5151 /* cut leading whitespace from string, replace it by string terminator */
5152 while (*str_ptr == ' ' || *str_ptr == '\t')
5155 if (*str_ptr == '\0') /* end of string reached */
5158 if (global.autoplay_leveldir == NULL) /* read level set string */
5160 global.autoplay_leveldir = str_ptr;
5161 global.autoplay_all = TRUE; /* default: play all tapes */
5163 for (i = 0; i < MAX_TAPES_PER_SET; i++)
5164 global.autoplay_level[i] = FALSE;
5166 else /* read level number string */
5168 int level_nr = atoi(str_ptr); /* get level_nr value */
5170 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5171 global.autoplay_level[level_nr] = TRUE;
5173 global.autoplay_all = FALSE;
5176 /* advance string pointer to the next whitespace (or end of string) */
5177 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5181 else if (strncmp(command, "convert ", 8) == 0)
5183 char *str_copy = getStringCopy(&command[8]);
5184 char *str_ptr = strchr(str_copy, ' ');
5186 global.convert_leveldir = str_copy;
5187 global.convert_level_nr = -1;
5189 if (str_ptr != NULL) /* level number follows */
5191 *str_ptr++ = '\0'; /* terminate leveldir string */
5192 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
5195 else if (strncmp(command, "create images ", 14) == 0)
5197 #if defined(TARGET_SDL)
5198 global.create_images_dir = getStringCopy(&command[14]);
5200 if (access(global.create_images_dir, W_OK) != 0)
5201 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
5202 global.create_images_dir);
5204 Error(ERR_EXIT, "command only available for SDL target");
5209 #if defined(TARGET_SDL)
5210 else if (strEqual(command, "SDL_ListModes"))
5215 SDL_Init(SDL_INIT_VIDEO);
5217 /* get available fullscreen/hardware modes */
5218 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
5220 /* check if there are any modes available */
5223 printf("No modes available!\n");
5228 /* check if our resolution is restricted */
5229 if (modes == (SDL_Rect **)-1)
5231 printf("All resolutions available.\n");
5235 printf("Available Modes:\n");
5237 for(i = 0; modes[i]; i++)
5238 printf(" %d x %d\n", modes[i]->w, modes[i]->h);
5248 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
5252 static void InitSetup()
5254 LoadSetup(); /* global setup info */
5256 /* set some options from setup file */
5258 if (setup.options.verbose)
5259 options.verbose = TRUE;
5262 static void InitGameInfo()
5264 game.restart_level = FALSE;
5267 static void InitPlayerInfo()
5271 /* choose default local player */
5272 local_player = &stored_player[0];
5274 for (i = 0; i < MAX_PLAYERS; i++)
5275 stored_player[i].connected = FALSE;
5277 local_player->connected = TRUE;
5280 static void InitArtworkInfo()
5285 static char *get_string_in_brackets(char *string)
5287 char *string_in_brackets = checked_malloc(strlen(string) + 3);
5289 sprintf(string_in_brackets, "[%s]", string);
5291 return string_in_brackets;
5294 static char *get_level_id_suffix(int id_nr)
5296 char *id_suffix = checked_malloc(1 + 3 + 1);
5298 if (id_nr < 0 || id_nr > 999)
5301 sprintf(id_suffix, ".%03d", id_nr);
5307 static char *get_element_class_token(int element)
5309 char *element_class_name = element_info[element].class_name;
5310 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
5312 sprintf(element_class_token, "[%s]", element_class_name);
5314 return element_class_token;
5317 static char *get_action_class_token(int action)
5319 char *action_class_name = &element_action_info[action].suffix[1];
5320 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
5322 sprintf(action_class_token, "[%s]", action_class_name);
5324 return action_class_token;
5328 static void InitArtworkConfig()
5330 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
5331 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
5332 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
5333 static char *action_id_suffix[NUM_ACTIONS + 1];
5334 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5335 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5336 static char *level_id_suffix[MAX_LEVELS + 1];
5337 static char *dummy[1] = { NULL };
5338 static char *ignore_generic_tokens[] =
5344 static char **ignore_image_tokens;
5345 static char **ignore_sound_tokens;
5346 static char **ignore_music_tokens;
5347 int num_ignore_generic_tokens;
5348 int num_ignore_image_tokens;
5349 int num_ignore_sound_tokens;
5350 int num_ignore_music_tokens;
5353 /* dynamically determine list of generic tokens to be ignored */
5354 num_ignore_generic_tokens = 0;
5355 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5356 num_ignore_generic_tokens++;
5358 /* dynamically determine list of image tokens to be ignored */
5359 num_ignore_image_tokens = num_ignore_generic_tokens;
5360 for (i = 0; image_config_vars[i].token != NULL; i++)
5361 num_ignore_image_tokens++;
5362 ignore_image_tokens =
5363 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5364 for (i = 0; i < num_ignore_generic_tokens; i++)
5365 ignore_image_tokens[i] = ignore_generic_tokens[i];
5366 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5367 ignore_image_tokens[num_ignore_generic_tokens + i] =
5368 image_config_vars[i].token;
5369 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5371 /* dynamically determine list of sound tokens to be ignored */
5372 num_ignore_sound_tokens = num_ignore_generic_tokens;
5373 ignore_sound_tokens =
5374 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5375 for (i = 0; i < num_ignore_generic_tokens; i++)
5376 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5377 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5379 /* dynamically determine list of music tokens to be ignored */
5380 num_ignore_music_tokens = num_ignore_generic_tokens;
5381 ignore_music_tokens =
5382 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5383 for (i = 0; i < num_ignore_generic_tokens; i++)
5384 ignore_music_tokens[i] = ignore_generic_tokens[i];
5385 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5387 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5388 image_id_prefix[i] = element_info[i].token_name;
5389 for (i = 0; i < NUM_FONTS; i++)
5390 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5391 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
5393 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5394 sound_id_prefix[i] = element_info[i].token_name;
5395 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5396 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5397 get_string_in_brackets(element_info[i].class_name);
5398 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
5400 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5401 music_id_prefix[i] = music_prefix_info[i].prefix;
5402 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
5404 for (i = 0; i < NUM_ACTIONS; i++)
5405 action_id_suffix[i] = element_action_info[i].suffix;
5406 action_id_suffix[NUM_ACTIONS] = NULL;
5408 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5409 direction_id_suffix[i] = element_direction_info[i].suffix;
5410 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5412 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5413 special_id_suffix[i] = special_suffix_info[i].suffix;
5414 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5416 for (i = 0; i < MAX_LEVELS; i++)
5417 level_id_suffix[i] = get_level_id_suffix(i);
5418 level_id_suffix[MAX_LEVELS] = NULL;
5420 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5421 image_id_prefix, action_id_suffix, direction_id_suffix,
5422 special_id_suffix, ignore_image_tokens);
5423 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5424 sound_id_prefix, action_id_suffix, dummy,
5425 special_id_suffix, ignore_sound_tokens);
5426 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5427 music_id_prefix, special_id_suffix, level_id_suffix,
5428 dummy, ignore_music_tokens);
5431 static void InitMixer()
5440 struct GraphicInfo *graphic_info_last = graphic_info;
5441 char *filename_font_initial = NULL;
5442 char *filename_anim_initial = NULL;
5443 Bitmap *bitmap_font_initial = NULL;
5447 /* determine settings for initial font (for displaying startup messages) */
5448 for (i = 0; image_config[i].token != NULL; i++)
5450 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5452 char font_token[128];
5455 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5456 len_font_token = strlen(font_token);
5458 if (strEqual(image_config[i].token, font_token))
5459 filename_font_initial = image_config[i].value;
5460 else if (strlen(image_config[i].token) > len_font_token &&
5461 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5463 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5464 font_initial[j].src_x = atoi(image_config[i].value);
5465 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5466 font_initial[j].src_y = atoi(image_config[i].value);
5467 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5468 font_initial[j].width = atoi(image_config[i].value);
5469 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5470 font_initial[j].height = atoi(image_config[i].value);
5475 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5477 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5478 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5481 if (filename_font_initial == NULL) /* should not happen */
5482 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5484 /* create additional image buffers for double-buffering and cross-fading */
5485 bitmap_db_cross = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5486 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
5487 bitmap_db_panel = CreateBitmap(DXSIZE, DYSIZE, DEFAULT_DEPTH);
5488 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
5489 bitmap_db_toons = CreateBitmap(FULL_SXSIZE, FULL_SYSIZE, DEFAULT_DEPTH);
5491 /* initialize screen properties */
5492 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5493 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5495 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5496 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5497 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5498 InitGfxCustomArtworkInfo();
5500 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5502 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5503 font_initial[j].bitmap = bitmap_font_initial;
5505 InitFontGraphicInfo();
5507 font_height = getFontHeight(FC_RED);
5510 DrawInitText(getWindowTitleString(), 20, FC_YELLOW);
5512 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
5514 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
5515 DrawInitText(PROGRAM_WEBSITE_STRING, WIN_YSIZE - 20 - font_height, FC_RED);
5517 DrawInitText("Loading graphics", 120, FC_GREEN);
5521 /* initialize busy animation with default values */
5522 int parameter[NUM_GFX_ARGS];
5523 for (i = 0; i < NUM_GFX_ARGS; i++)
5524 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5525 image_config_suffix[i].token,
5526 image_config_suffix[i].type);
5528 for (i = 0; i < NUM_GFX_ARGS; i++)
5529 printf("::: '%s' => %d\n", image_config_suffix[i].token, parameter[i]);
5533 /* determine settings for busy animation (when displaying startup messages) */
5534 for (i = 0; image_config[i].token != NULL; i++)
5536 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5537 int len_anim_token = strlen(anim_token);
5539 if (strEqual(image_config[i].token, anim_token))
5540 filename_anim_initial = image_config[i].value;
5541 else if (strlen(image_config[i].token) > len_anim_token &&
5542 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5545 for (j = 0; image_config_suffix[j].token != NULL; j++)
5547 if (strEqual(&image_config[i].token[len_anim_token],
5548 image_config_suffix[j].token))
5550 get_graphic_parameter_value(image_config[i].value,
5551 image_config_suffix[j].token,
5552 image_config_suffix[j].type);
5555 if (strEqual(&image_config[i].token[len_anim_token], ".x"))
5556 anim_initial.src_x = atoi(image_config[i].value);
5557 else if (strEqual(&image_config[i].token[len_anim_token], ".y"))
5558 anim_initial.src_y = atoi(image_config[i].value);
5559 else if (strEqual(&image_config[i].token[len_anim_token], ".width"))
5560 anim_initial.width = atoi(image_config[i].value);
5561 else if (strEqual(&image_config[i].token[len_anim_token], ".height"))
5562 anim_initial.height = atoi(image_config[i].value);
5563 else if (strEqual(&image_config[i].token[len_anim_token], ".frames"))
5564 anim_initial.anim_frames = atoi(image_config[i].value);
5565 else if (strEqual(&image_config[i].token[len_anim_token],
5566 ".frames_per_line"))
5567 anim_initial.anim_frames_per_line = atoi(image_config[i].value);
5568 else if (strEqual(&image_config[i].token[len_anim_token], ".delay"))
5569 anim_initial.anim_delay = atoi(image_config[i].value);
5574 #if defined(CREATE_SPECIAL_EDITION_RND_JUE)
5575 filename_anim_initial = "loading.pcx";
5577 parameter[GFX_ARG_X] = 0;
5578 parameter[GFX_ARG_Y] = 0;
5579 parameter[GFX_ARG_WIDTH] = 128;
5580 parameter[GFX_ARG_HEIGHT] = 40;
5581 parameter[GFX_ARG_FRAMES] = 32;
5582 parameter[GFX_ARG_DELAY] = 4;
5583 parameter[GFX_ARG_FRAMES_PER_LINE] = ARG_UNDEFINED_VALUE;
5586 if (filename_anim_initial == NULL) /* should not happen */
5587 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5589 anim_initial.bitmap = LoadCustomImage(filename_anim_initial);
5591 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
5593 set_graphic_parameters_ext(0, parameter, anim_initial.bitmap);
5596 printf("::: INIT_GFX: anim_frames_per_line == %d [%d / %d] [%d, %d]\n",
5597 graphic_info[0].anim_frames_per_line,
5598 get_scaled_graphic_width(0),
5599 graphic_info[0].width,
5600 getOriginalImageWidthFromImageID(0),
5601 graphic_info[0].scale_up_factor);
5604 graphic_info = graphic_info_last;
5606 init.busy.width = anim_initial.width;
5607 init.busy.height = anim_initial.height;
5609 InitMenuDesignSettings_Static();
5610 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5614 void RedrawBackground()
5616 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
5617 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
5619 redraw_mask = REDRAW_ALL;
5622 void InitGfxBackground()
5626 fieldbuffer = bitmap_db_field;
5627 SetDrawtoField(DRAW_BACKBUFFER);
5630 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5634 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
5635 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
5638 for (x = 0; x < MAX_BUF_XSIZE; x++)
5639 for (y = 0; y < MAX_BUF_YSIZE; y++)
5642 redraw_mask = REDRAW_ALL;
5645 static void InitLevelInfo()
5647 LoadLevelInfo(); /* global level info */
5648 LoadLevelSetup_LastSeries(); /* last played series info */
5649 LoadLevelSetup_SeriesInfo(); /* last played level info */
5652 static void InitLevelArtworkInfo()
5654 LoadLevelArtworkInfo();
5657 static void InitImages()
5659 print_timestamp_init("InitImages");
5662 printf("::: leveldir_current->identifier == '%s'\n",
5663 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5664 printf("::: leveldir_current->graphics_path == '%s'\n",
5665 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5666 printf("::: leveldir_current->graphics_set == '%s'\n",
5667 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5668 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5669 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5672 setLevelArtworkDir(artwork.gfx_first);
5675 printf("::: leveldir_current->identifier == '%s'\n",
5676 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5677 printf("::: leveldir_current->graphics_path == '%s'\n",
5678 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5679 printf("::: leveldir_current->graphics_set == '%s'\n",
5680 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5681 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5682 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5686 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5687 leveldir_current->identifier,
5688 artwork.gfx_current_identifier,
5689 artwork.gfx_current->identifier,
5690 leveldir_current->graphics_set,
5691 leveldir_current->graphics_path);
5694 UPDATE_BUSY_STATE();
5696 ReloadCustomImages();
5697 print_timestamp_time("ReloadCustomImages");
5699 UPDATE_BUSY_STATE();
5701 LoadCustomElementDescriptions();
5702 print_timestamp_time("LoadCustomElementDescriptions");
5704 UPDATE_BUSY_STATE();
5706 LoadMenuDesignSettings();
5707 print_timestamp_time("LoadMenuDesignSettings");
5709 UPDATE_BUSY_STATE();
5711 ReinitializeGraphics();
5712 print_timestamp_time("ReinitializeGraphics");
5714 UPDATE_BUSY_STATE();
5716 print_timestamp_done("InitImages");
5719 static void InitSound(char *identifier)
5721 print_timestamp_init("InitSound");
5723 if (identifier == NULL)
5724 identifier = artwork.snd_current->identifier;
5726 /* set artwork path to send it to the sound server process */
5727 setLevelArtworkDir(artwork.snd_first);
5729 InitReloadCustomSounds(identifier);
5730 print_timestamp_time("InitReloadCustomSounds");
5732 ReinitializeSounds();
5733 print_timestamp_time("ReinitializeSounds");
5735 print_timestamp_done("InitSound");
5738 static void InitMusic(char *identifier)
5740 print_timestamp_init("InitMusic");
5742 if (identifier == NULL)
5743 identifier = artwork.mus_current->identifier;
5745 /* set artwork path to send it to the sound server process */
5746 setLevelArtworkDir(artwork.mus_first);
5748 InitReloadCustomMusic(identifier);
5749 print_timestamp_time("InitReloadCustomMusic");
5751 ReinitializeMusic();
5752 print_timestamp_time("ReinitializeMusic");
5754 print_timestamp_done("InitMusic");
5757 void InitNetworkServer()
5759 #if defined(NETWORK_AVALIABLE)
5763 if (!options.network)
5766 #if defined(NETWORK_AVALIABLE)
5767 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5769 if (!ConnectToServer(options.server_host, options.server_port))
5770 Error(ERR_EXIT, "cannot connect to network game server");
5772 SendToServer_PlayerName(setup.player_name);
5773 SendToServer_ProtocolVersion();
5776 SendToServer_NrWanted(nr_wanted);
5780 static boolean CheckArtworkConfigForCustomElements(char *filename)
5782 SetupFileHash *setup_file_hash;
5783 boolean redefined_ce_found = FALSE;
5785 /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */
5787 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5789 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5791 char *token = HASH_ITERATION_TOKEN(itr);
5793 if (strPrefix(token, "custom_"))
5795 redefined_ce_found = TRUE;
5800 END_HASH_ITERATION(setup_file_hash, itr)
5802 freeSetupFileHash(setup_file_hash);
5805 return redefined_ce_found;
5808 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5810 char *filename_base, *filename_local;
5811 boolean redefined_ce_found = FALSE;
5813 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5816 printf("::: leveldir_current->identifier == '%s'\n",
5817 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5818 printf("::: leveldir_current->graphics_path == '%s'\n",
5819 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5820 printf("::: leveldir_current->graphics_set == '%s'\n",
5821 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5822 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5823 leveldir_current == NULL ? "[NULL]" :
5824 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5827 /* first look for special artwork configured in level series config */
5828 filename_base = getCustomArtworkLevelConfigFilename(type);
5831 printf("::: filename_base == '%s'\n", filename_base);
5834 if (fileExists(filename_base))
5835 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5837 filename_local = getCustomArtworkConfigFilename(type);
5840 printf("::: filename_local == '%s'\n", filename_local);
5843 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5844 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5847 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5850 return redefined_ce_found;
5853 static void InitOverrideArtwork()
5855 boolean redefined_ce_found = FALSE;
5857 /* to check if this level set redefines any CEs, do not use overriding */
5858 gfx.override_level_graphics = FALSE;
5859 gfx.override_level_sounds = FALSE;
5860 gfx.override_level_music = FALSE;
5862 /* now check if this level set has definitions for custom elements */
5863 if (setup.override_level_graphics == AUTO ||
5864 setup.override_level_sounds == AUTO ||
5865 setup.override_level_music == AUTO)
5866 redefined_ce_found =
5867 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5868 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5869 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5872 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5875 if (redefined_ce_found)
5877 /* this level set has CE definitions: change "AUTO" to "FALSE" */
5878 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5879 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
5880 gfx.override_level_music = (setup.override_level_music == TRUE);
5884 /* this level set has no CE definitions: change "AUTO" to "TRUE" */
5885 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5886 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
5887 gfx.override_level_music = (setup.override_level_music != FALSE);
5891 printf("::: => %d, %d, %d\n",
5892 gfx.override_level_graphics,
5893 gfx.override_level_sounds,
5894 gfx.override_level_music);
5898 static char *getNewArtworkIdentifier(int type)
5900 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5901 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5902 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5903 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5904 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5906 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5908 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
5910 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5911 char *leveldir_identifier = leveldir_current->identifier;
5913 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
5914 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5916 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
5918 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5919 char *artwork_current_identifier;
5920 char *artwork_new_identifier = NULL; /* default: nothing has changed */
5922 /* leveldir_current may be invalid (level group, parent link) */
5923 if (!validLevelSeries(leveldir_current))
5926 /* 1st step: determine artwork set to be activated in descending order:
5927 --------------------------------------------------------------------
5928 1. setup artwork (when configured to override everything else)
5929 2. artwork set configured in "levelinfo.conf" of current level set
5930 (artwork in level directory will have priority when loading later)
5931 3. artwork in level directory (stored in artwork sub-directory)
5932 4. setup artwork (currently configured in setup menu) */
5934 if (setup_override_artwork)
5935 artwork_current_identifier = setup_artwork_set;
5936 else if (leveldir_artwork_set != NULL)
5937 artwork_current_identifier = leveldir_artwork_set;
5938 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5939 artwork_current_identifier = leveldir_identifier;
5941 artwork_current_identifier = setup_artwork_set;
5944 /* 2nd step: check if it is really needed to reload artwork set
5945 ------------------------------------------------------------ */
5948 if (type == ARTWORK_TYPE_GRAPHICS)
5949 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
5950 artwork_new_identifier,
5951 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5952 artwork_current_identifier,
5953 leveldir_current->graphics_set,
5954 leveldir_current->identifier);
5957 /* ---------- reload if level set and also artwork set has changed ------- */
5958 if (leveldir_current_identifier[type] != leveldir_identifier &&
5959 (last_has_level_artwork_set[type] || has_level_artwork_set))
5960 artwork_new_identifier = artwork_current_identifier;
5962 leveldir_current_identifier[type] = leveldir_identifier;
5963 last_has_level_artwork_set[type] = has_level_artwork_set;
5966 if (type == ARTWORK_TYPE_GRAPHICS)
5967 printf("::: 1: '%s'\n", artwork_new_identifier);
5970 /* ---------- reload if "override artwork" setting has changed ----------- */
5971 if (last_override_level_artwork[type] != setup_override_artwork)
5972 artwork_new_identifier = artwork_current_identifier;
5974 last_override_level_artwork[type] = setup_override_artwork;
5977 if (type == ARTWORK_TYPE_GRAPHICS)
5978 printf("::: 2: '%s'\n", artwork_new_identifier);
5981 /* ---------- reload if current artwork identifier has changed ----------- */
5982 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5983 artwork_current_identifier))
5984 artwork_new_identifier = artwork_current_identifier;
5986 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5989 if (type == ARTWORK_TYPE_GRAPHICS)
5990 printf("::: 3: '%s'\n", artwork_new_identifier);
5993 /* ---------- do not reload directly after starting ---------------------- */
5994 if (!initialized[type])
5995 artwork_new_identifier = NULL;
5997 initialized[type] = TRUE;
6000 if (type == ARTWORK_TYPE_GRAPHICS)
6001 printf("::: 4: '%s'\n", artwork_new_identifier);
6005 if (type == ARTWORK_TYPE_GRAPHICS)
6006 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
6007 artwork.gfx_current_identifier, artwork_current_identifier,
6008 artwork.gfx_current->identifier, leveldir_current->graphics_set,
6009 artwork_new_identifier);
6012 return artwork_new_identifier;
6015 void ReloadCustomArtwork(int force_reload)
6017 int last_game_status = game_status; /* save current game status */
6018 char *gfx_new_identifier;
6019 char *snd_new_identifier;
6020 char *mus_new_identifier;
6021 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
6022 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
6023 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
6024 boolean reload_needed;
6026 InitOverrideArtwork();
6028 force_reload_gfx |= AdjustGraphicsForEMC();
6030 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
6031 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
6032 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
6034 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
6035 snd_new_identifier != NULL || force_reload_snd ||
6036 mus_new_identifier != NULL || force_reload_mus);
6041 print_timestamp_init("ReloadCustomArtwork");
6043 game_status = GAME_MODE_LOADING;
6045 FadeOut(REDRAW_ALL);
6048 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6050 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
6052 print_timestamp_time("ClearRectangle");
6055 printf("::: fading in ... %d\n", fading.fade_mode);
6059 printf("::: done\n");
6062 if (gfx_new_identifier != NULL || force_reload_gfx)
6065 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
6066 artwork.gfx_current_identifier,
6068 artwork.gfx_current->identifier,
6069 leveldir_current->graphics_set);
6073 print_timestamp_time("InitImages");
6076 if (snd_new_identifier != NULL || force_reload_snd)
6078 InitSound(snd_new_identifier);
6079 print_timestamp_time("InitSound");
6082 if (mus_new_identifier != NULL || force_reload_mus)
6084 InitMusic(mus_new_identifier);
6085 print_timestamp_time("InitMusic");
6088 game_status = last_game_status; /* restore current game status */
6091 printf("::: ----------------DELAY 1 ...\n");
6096 printf("::: FadeOut @ ReloadCustomArtwork ...\n");
6098 FadeOut(REDRAW_ALL);
6100 printf("::: FadeOut @ ReloadCustomArtwork done\n");
6105 /* force redraw of (open or closed) door graphics */
6106 SetDoorState(DOOR_OPEN_ALL);
6107 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
6112 FadeSetEnterScreen();
6113 FadeSkipNextFadeOut();
6114 // FadeSetDisabled();
6119 fading = fading_none;
6124 redraw_mask = REDRAW_ALL;
6127 print_timestamp_done("ReloadCustomArtwork");
6130 void KeyboardAutoRepeatOffUnlessAutoplay()
6132 if (global.autoplay_leveldir == NULL)
6133 KeyboardAutoRepeatOff();
6137 /* ========================================================================= */
6139 /* ========================================================================= */
6143 print_timestamp_init("OpenAll");
6145 game_status = GAME_MODE_LOADING;
6147 InitGlobal(); /* initialize some global variables */
6149 if (options.execute_command)
6150 Execute_Command(options.execute_command);
6152 if (options.serveronly)
6154 #if defined(PLATFORM_UNIX)
6155 NetworkServer(options.server_port, options.serveronly);
6157 Error(ERR_WARN, "networking only supported in Unix version");
6160 exit(0); /* never reached, server loops forever */
6167 InitArtworkInfo(); /* needed before loading gfx, sound & music */
6168 InitArtworkConfig(); /* needed before forking sound child process */
6173 InitRND(NEW_RANDOMIZE);
6174 InitSimpleRandom(NEW_RANDOMIZE);
6178 print_timestamp_time("[pre-video]");
6181 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
6183 InitEventFilter(FilterMouseMotionEvents);
6185 InitElementPropertiesStatic();
6186 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
6188 print_timestamp_time("[post-video]");
6192 print_timestamp_time("InitGfx");
6195 print_timestamp_time("InitLevelInfo");
6197 InitLevelArtworkInfo();
6198 print_timestamp_time("InitLevelArtworkInfo");
6200 InitOverrideArtwork(); /* needs to know current level directory */
6201 print_timestamp_time("InitOverrideArtwork");
6203 InitImages(); /* needs to know current level directory */
6204 print_timestamp_time("InitImages");
6206 InitSound(NULL); /* needs to know current level directory */
6207 print_timestamp_time("InitSound");
6209 InitMusic(NULL); /* needs to know current level directory */
6210 print_timestamp_time("InitMusic");
6212 InitGfxBackground();
6218 if (global.autoplay_leveldir)
6223 else if (global.convert_leveldir)
6228 else if (global.create_images_dir)
6230 CreateLevelSketchImages();
6234 game_status = GAME_MODE_MAIN;
6237 FadeSetEnterScreen();
6238 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
6239 FadeSkipNextFadeOut();
6240 // FadeSetDisabled();
6242 fading = fading_none;
6245 print_timestamp_time("[post-artwork]");
6247 print_timestamp_done("OpenAll");
6251 InitNetworkServer();
6254 void CloseAllAndExit(int exit_value)
6259 CloseAudio(); /* called after freeing sounds (needed for SDL) */
6267 #if defined(TARGET_SDL)
6268 if (network_server) /* terminate network server */
6269 SDL_KillThread(server_thread);
6272 CloseVideoDisplay();
6273 ClosePlatformDependentStuff();
6275 if (exit_value != 0)
6276 NotifyUserAboutErrorFile();