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,
3162 EL_EM_STEEL_EXIT_OPEN,
3164 EL_EM_STEEL_EXIT_OPENING,
3174 EL_GATE_1_GRAY_ACTIVE,
3175 EL_GATE_2_GRAY_ACTIVE,
3176 EL_GATE_3_GRAY_ACTIVE,
3177 EL_GATE_4_GRAY_ACTIVE,
3185 static int ep_walkable_inside[] =
3190 EL_TUBE_VERTICAL_LEFT,
3191 EL_TUBE_VERTICAL_RIGHT,
3192 EL_TUBE_HORIZONTAL_UP,
3193 EL_TUBE_HORIZONTAL_DOWN,
3202 static int ep_walkable_under[] =
3207 static int ep_passable_over[] =
3217 EL_EM_GATE_1_GRAY_ACTIVE,
3218 EL_EM_GATE_2_GRAY_ACTIVE,
3219 EL_EM_GATE_3_GRAY_ACTIVE,
3220 EL_EM_GATE_4_GRAY_ACTIVE,
3229 EL_EMC_GATE_5_GRAY_ACTIVE,
3230 EL_EMC_GATE_6_GRAY_ACTIVE,
3231 EL_EMC_GATE_7_GRAY_ACTIVE,
3232 EL_EMC_GATE_8_GRAY_ACTIVE,
3234 EL_DC_GATE_WHITE_GRAY,
3235 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3242 static int ep_passable_inside[] =
3248 EL_SP_PORT_HORIZONTAL,
3249 EL_SP_PORT_VERTICAL,
3251 EL_SP_GRAVITY_PORT_LEFT,
3252 EL_SP_GRAVITY_PORT_RIGHT,
3253 EL_SP_GRAVITY_PORT_UP,
3254 EL_SP_GRAVITY_PORT_DOWN,
3255 EL_SP_GRAVITY_ON_PORT_LEFT,
3256 EL_SP_GRAVITY_ON_PORT_RIGHT,
3257 EL_SP_GRAVITY_ON_PORT_UP,
3258 EL_SP_GRAVITY_ON_PORT_DOWN,
3259 EL_SP_GRAVITY_OFF_PORT_LEFT,
3260 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3261 EL_SP_GRAVITY_OFF_PORT_UP,
3262 EL_SP_GRAVITY_OFF_PORT_DOWN,
3267 static int ep_passable_under[] =
3272 static int ep_droppable[] =
3277 static int ep_explodes_1x1_old[] =
3282 static int ep_pushable[] =
3294 EL_SOKOBAN_FIELD_FULL,
3303 static int ep_explodes_cross_old[] =
3308 static int ep_protected[] =
3310 /* same elements as in 'ep_walkable_inside' */
3314 EL_TUBE_VERTICAL_LEFT,
3315 EL_TUBE_VERTICAL_RIGHT,
3316 EL_TUBE_HORIZONTAL_UP,
3317 EL_TUBE_HORIZONTAL_DOWN,
3323 /* same elements as in 'ep_passable_over' */
3332 EL_EM_GATE_1_GRAY_ACTIVE,
3333 EL_EM_GATE_2_GRAY_ACTIVE,
3334 EL_EM_GATE_3_GRAY_ACTIVE,
3335 EL_EM_GATE_4_GRAY_ACTIVE,
3344 EL_EMC_GATE_5_GRAY_ACTIVE,
3345 EL_EMC_GATE_6_GRAY_ACTIVE,
3346 EL_EMC_GATE_7_GRAY_ACTIVE,
3347 EL_EMC_GATE_8_GRAY_ACTIVE,
3349 EL_DC_GATE_WHITE_GRAY,
3350 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3354 /* same elements as in 'ep_passable_inside' */
3359 EL_SP_PORT_HORIZONTAL,
3360 EL_SP_PORT_VERTICAL,
3362 EL_SP_GRAVITY_PORT_LEFT,
3363 EL_SP_GRAVITY_PORT_RIGHT,
3364 EL_SP_GRAVITY_PORT_UP,
3365 EL_SP_GRAVITY_PORT_DOWN,
3366 EL_SP_GRAVITY_ON_PORT_LEFT,
3367 EL_SP_GRAVITY_ON_PORT_RIGHT,
3368 EL_SP_GRAVITY_ON_PORT_UP,
3369 EL_SP_GRAVITY_ON_PORT_DOWN,
3370 EL_SP_GRAVITY_OFF_PORT_LEFT,
3371 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3372 EL_SP_GRAVITY_OFF_PORT_UP,
3373 EL_SP_GRAVITY_OFF_PORT_DOWN,
3378 static int ep_throwable[] =
3383 static int ep_can_explode[] =
3385 /* same elements as in 'ep_explodes_impact' */
3390 /* same elements as in 'ep_explodes_smashed' */
3396 /* elements that can explode by explosion or by dragonfire */
3400 EL_EM_DYNAMITE_ACTIVE,
3401 EL_DYNABOMB_PLAYER_1_ACTIVE,
3402 EL_DYNABOMB_PLAYER_2_ACTIVE,
3403 EL_DYNABOMB_PLAYER_3_ACTIVE,
3404 EL_DYNABOMB_PLAYER_4_ACTIVE,
3405 EL_DYNABOMB_INCREASE_NUMBER,
3406 EL_DYNABOMB_INCREASE_SIZE,
3407 EL_DYNABOMB_INCREASE_POWER,
3408 EL_SP_DISK_RED_ACTIVE,
3416 /* elements that can explode only by explosion */
3422 static int ep_gravity_reachable[] =
3428 EL_INVISIBLE_SAND_ACTIVE,
3433 EL_SP_PORT_HORIZONTAL,
3434 EL_SP_PORT_VERTICAL,
3436 EL_SP_GRAVITY_PORT_LEFT,
3437 EL_SP_GRAVITY_PORT_RIGHT,
3438 EL_SP_GRAVITY_PORT_UP,
3439 EL_SP_GRAVITY_PORT_DOWN,
3440 EL_SP_GRAVITY_ON_PORT_LEFT,
3441 EL_SP_GRAVITY_ON_PORT_RIGHT,
3442 EL_SP_GRAVITY_ON_PORT_UP,
3443 EL_SP_GRAVITY_ON_PORT_DOWN,
3444 EL_SP_GRAVITY_OFF_PORT_LEFT,
3445 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3446 EL_SP_GRAVITY_OFF_PORT_UP,
3447 EL_SP_GRAVITY_OFF_PORT_DOWN,
3453 static int ep_player[] =
3460 EL_SOKOBAN_FIELD_PLAYER,
3466 static int ep_can_pass_magic_wall[] =
3480 static int ep_can_pass_dc_magic_wall[] =
3496 static int ep_switchable[] =
3500 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3501 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3502 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3503 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3504 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3505 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3506 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3507 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3508 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3509 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3510 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3511 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3512 EL_SWITCHGATE_SWITCH_UP,
3513 EL_SWITCHGATE_SWITCH_DOWN,
3514 EL_DC_SWITCHGATE_SWITCH_UP,
3515 EL_DC_SWITCHGATE_SWITCH_DOWN,
3517 EL_LIGHT_SWITCH_ACTIVE,
3519 EL_DC_TIMEGATE_SWITCH,
3520 EL_BALLOON_SWITCH_LEFT,
3521 EL_BALLOON_SWITCH_RIGHT,
3522 EL_BALLOON_SWITCH_UP,
3523 EL_BALLOON_SWITCH_DOWN,
3524 EL_BALLOON_SWITCH_ANY,
3525 EL_BALLOON_SWITCH_NONE,
3528 EL_EMC_MAGIC_BALL_SWITCH,
3529 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3534 static int ep_bd_element[] =
3568 static int ep_sp_element[] =
3570 /* should always be valid */
3573 /* standard classic Supaplex elements */
3580 EL_SP_HARDWARE_GRAY,
3588 EL_SP_GRAVITY_PORT_RIGHT,
3589 EL_SP_GRAVITY_PORT_DOWN,
3590 EL_SP_GRAVITY_PORT_LEFT,
3591 EL_SP_GRAVITY_PORT_UP,
3596 EL_SP_PORT_VERTICAL,
3597 EL_SP_PORT_HORIZONTAL,
3603 EL_SP_HARDWARE_BASE_1,
3604 EL_SP_HARDWARE_GREEN,
3605 EL_SP_HARDWARE_BLUE,
3607 EL_SP_HARDWARE_YELLOW,
3608 EL_SP_HARDWARE_BASE_2,
3609 EL_SP_HARDWARE_BASE_3,
3610 EL_SP_HARDWARE_BASE_4,
3611 EL_SP_HARDWARE_BASE_5,
3612 EL_SP_HARDWARE_BASE_6,
3616 /* additional elements that appeared in newer Supaplex levels */
3619 /* additional gravity port elements (not switching, but setting gravity) */
3620 EL_SP_GRAVITY_ON_PORT_LEFT,
3621 EL_SP_GRAVITY_ON_PORT_RIGHT,
3622 EL_SP_GRAVITY_ON_PORT_UP,
3623 EL_SP_GRAVITY_ON_PORT_DOWN,
3624 EL_SP_GRAVITY_OFF_PORT_LEFT,
3625 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3626 EL_SP_GRAVITY_OFF_PORT_UP,
3627 EL_SP_GRAVITY_OFF_PORT_DOWN,
3629 /* more than one Murphy in a level results in an inactive clone */
3632 /* runtime Supaplex elements */
3633 EL_SP_DISK_RED_ACTIVE,
3634 EL_SP_TERMINAL_ACTIVE,
3635 EL_SP_BUGGY_BASE_ACTIVATING,
3636 EL_SP_BUGGY_BASE_ACTIVE,
3643 static int ep_sb_element[] =
3648 EL_SOKOBAN_FIELD_EMPTY,
3649 EL_SOKOBAN_FIELD_FULL,
3650 EL_SOKOBAN_FIELD_PLAYER,
3655 EL_INVISIBLE_STEELWALL,
3660 static int ep_gem[] =
3672 static int ep_food_dark_yamyam[] =
3700 static int ep_food_penguin[] =
3714 static int ep_food_pig[] =
3726 static int ep_historic_wall[] =
3737 EL_GATE_1_GRAY_ACTIVE,
3738 EL_GATE_2_GRAY_ACTIVE,
3739 EL_GATE_3_GRAY_ACTIVE,
3740 EL_GATE_4_GRAY_ACTIVE,
3749 EL_EM_GATE_1_GRAY_ACTIVE,
3750 EL_EM_GATE_2_GRAY_ACTIVE,
3751 EL_EM_GATE_3_GRAY_ACTIVE,
3752 EL_EM_GATE_4_GRAY_ACTIVE,
3759 EL_EXPANDABLE_WALL_HORIZONTAL,
3760 EL_EXPANDABLE_WALL_VERTICAL,
3761 EL_EXPANDABLE_WALL_ANY,
3762 EL_EXPANDABLE_WALL_GROWING,
3763 EL_BD_EXPANDABLE_WALL,
3770 EL_SP_HARDWARE_GRAY,
3771 EL_SP_HARDWARE_GREEN,
3772 EL_SP_HARDWARE_BLUE,
3774 EL_SP_HARDWARE_YELLOW,
3775 EL_SP_HARDWARE_BASE_1,
3776 EL_SP_HARDWARE_BASE_2,
3777 EL_SP_HARDWARE_BASE_3,
3778 EL_SP_HARDWARE_BASE_4,
3779 EL_SP_HARDWARE_BASE_5,
3780 EL_SP_HARDWARE_BASE_6,
3782 EL_SP_TERMINAL_ACTIVE,
3785 EL_INVISIBLE_STEELWALL,
3786 EL_INVISIBLE_STEELWALL_ACTIVE,
3788 EL_INVISIBLE_WALL_ACTIVE,
3789 EL_STEELWALL_SLIPPERY,
3806 static int ep_historic_solid[] =
3810 EL_EXPANDABLE_WALL_HORIZONTAL,
3811 EL_EXPANDABLE_WALL_VERTICAL,
3812 EL_EXPANDABLE_WALL_ANY,
3813 EL_BD_EXPANDABLE_WALL,
3826 EL_QUICKSAND_FILLING,
3827 EL_QUICKSAND_EMPTYING,
3829 EL_MAGIC_WALL_ACTIVE,
3830 EL_MAGIC_WALL_EMPTYING,
3831 EL_MAGIC_WALL_FILLING,
3835 EL_BD_MAGIC_WALL_ACTIVE,
3836 EL_BD_MAGIC_WALL_EMPTYING,
3837 EL_BD_MAGIC_WALL_FULL,
3838 EL_BD_MAGIC_WALL_FILLING,
3839 EL_BD_MAGIC_WALL_DEAD,
3848 EL_SP_TERMINAL_ACTIVE,
3852 EL_INVISIBLE_WALL_ACTIVE,
3853 EL_SWITCHGATE_SWITCH_UP,
3854 EL_SWITCHGATE_SWITCH_DOWN,
3855 EL_DC_SWITCHGATE_SWITCH_UP,
3856 EL_DC_SWITCHGATE_SWITCH_DOWN,
3858 EL_TIMEGATE_SWITCH_ACTIVE,
3859 EL_DC_TIMEGATE_SWITCH,
3860 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3872 /* the following elements are a direct copy of "indestructible" elements,
3873 except "EL_ACID", which is "indestructible", but not "solid"! */
3878 EL_ACID_POOL_TOPLEFT,
3879 EL_ACID_POOL_TOPRIGHT,
3880 EL_ACID_POOL_BOTTOMLEFT,
3881 EL_ACID_POOL_BOTTOM,
3882 EL_ACID_POOL_BOTTOMRIGHT,
3883 EL_SP_HARDWARE_GRAY,
3884 EL_SP_HARDWARE_GREEN,
3885 EL_SP_HARDWARE_BLUE,
3887 EL_SP_HARDWARE_YELLOW,
3888 EL_SP_HARDWARE_BASE_1,
3889 EL_SP_HARDWARE_BASE_2,
3890 EL_SP_HARDWARE_BASE_3,
3891 EL_SP_HARDWARE_BASE_4,
3892 EL_SP_HARDWARE_BASE_5,
3893 EL_SP_HARDWARE_BASE_6,
3894 EL_INVISIBLE_STEELWALL,
3895 EL_INVISIBLE_STEELWALL_ACTIVE,
3896 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3897 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3898 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3899 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3900 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3901 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3902 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3903 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3904 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3905 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3906 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3907 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3909 EL_LIGHT_SWITCH_ACTIVE,
3910 EL_SIGN_EXCLAMATION,
3911 EL_SIGN_RADIOACTIVITY,
3918 EL_SIGN_ENTRY_FORBIDDEN,
3919 EL_SIGN_EMERGENCY_EXIT,
3927 EL_STEEL_EXIT_CLOSED,
3929 EL_DC_STEELWALL_1_LEFT,
3930 EL_DC_STEELWALL_1_RIGHT,
3931 EL_DC_STEELWALL_1_TOP,
3932 EL_DC_STEELWALL_1_BOTTOM,
3933 EL_DC_STEELWALL_1_HORIZONTAL,
3934 EL_DC_STEELWALL_1_VERTICAL,
3935 EL_DC_STEELWALL_1_TOPLEFT,
3936 EL_DC_STEELWALL_1_TOPRIGHT,
3937 EL_DC_STEELWALL_1_BOTTOMLEFT,
3938 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3939 EL_DC_STEELWALL_1_TOPLEFT_2,
3940 EL_DC_STEELWALL_1_TOPRIGHT_2,
3941 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3942 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3943 EL_DC_STEELWALL_2_LEFT,
3944 EL_DC_STEELWALL_2_RIGHT,
3945 EL_DC_STEELWALL_2_TOP,
3946 EL_DC_STEELWALL_2_BOTTOM,
3947 EL_DC_STEELWALL_2_HORIZONTAL,
3948 EL_DC_STEELWALL_2_VERTICAL,
3949 EL_DC_STEELWALL_2_MIDDLE,
3950 EL_DC_STEELWALL_2_SINGLE,
3951 EL_STEELWALL_SLIPPERY,
3965 EL_GATE_1_GRAY_ACTIVE,
3966 EL_GATE_2_GRAY_ACTIVE,
3967 EL_GATE_3_GRAY_ACTIVE,
3968 EL_GATE_4_GRAY_ACTIVE,
3977 EL_EM_GATE_1_GRAY_ACTIVE,
3978 EL_EM_GATE_2_GRAY_ACTIVE,
3979 EL_EM_GATE_3_GRAY_ACTIVE,
3980 EL_EM_GATE_4_GRAY_ACTIVE,
3982 EL_SWITCHGATE_OPENING,
3983 EL_SWITCHGATE_CLOSED,
3984 EL_SWITCHGATE_CLOSING,
3986 EL_TIMEGATE_OPENING,
3988 EL_TIMEGATE_CLOSING,
3992 EL_TUBE_VERTICAL_LEFT,
3993 EL_TUBE_VERTICAL_RIGHT,
3994 EL_TUBE_HORIZONTAL_UP,
3995 EL_TUBE_HORIZONTAL_DOWN,
4004 static int ep_classic_enemy[] =
4021 static int ep_belt[] =
4023 EL_CONVEYOR_BELT_1_LEFT,
4024 EL_CONVEYOR_BELT_1_MIDDLE,
4025 EL_CONVEYOR_BELT_1_RIGHT,
4026 EL_CONVEYOR_BELT_2_LEFT,
4027 EL_CONVEYOR_BELT_2_MIDDLE,
4028 EL_CONVEYOR_BELT_2_RIGHT,
4029 EL_CONVEYOR_BELT_3_LEFT,
4030 EL_CONVEYOR_BELT_3_MIDDLE,
4031 EL_CONVEYOR_BELT_3_RIGHT,
4032 EL_CONVEYOR_BELT_4_LEFT,
4033 EL_CONVEYOR_BELT_4_MIDDLE,
4034 EL_CONVEYOR_BELT_4_RIGHT,
4039 static int ep_belt_active[] =
4041 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
4042 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
4043 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
4044 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
4045 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
4046 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
4047 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
4048 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
4049 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
4050 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
4051 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
4052 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
4057 static int ep_belt_switch[] =
4059 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4060 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4061 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4062 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4063 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4064 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4065 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4066 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4067 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4068 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4069 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4070 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4075 static int ep_tube[] =
4082 EL_TUBE_HORIZONTAL_UP,
4083 EL_TUBE_HORIZONTAL_DOWN,
4085 EL_TUBE_VERTICAL_LEFT,
4086 EL_TUBE_VERTICAL_RIGHT,
4092 static int ep_acid_pool[] =
4094 EL_ACID_POOL_TOPLEFT,
4095 EL_ACID_POOL_TOPRIGHT,
4096 EL_ACID_POOL_BOTTOMLEFT,
4097 EL_ACID_POOL_BOTTOM,
4098 EL_ACID_POOL_BOTTOMRIGHT,
4103 static int ep_keygate[] =
4113 EL_GATE_1_GRAY_ACTIVE,
4114 EL_GATE_2_GRAY_ACTIVE,
4115 EL_GATE_3_GRAY_ACTIVE,
4116 EL_GATE_4_GRAY_ACTIVE,
4125 EL_EM_GATE_1_GRAY_ACTIVE,
4126 EL_EM_GATE_2_GRAY_ACTIVE,
4127 EL_EM_GATE_3_GRAY_ACTIVE,
4128 EL_EM_GATE_4_GRAY_ACTIVE,
4137 EL_EMC_GATE_5_GRAY_ACTIVE,
4138 EL_EMC_GATE_6_GRAY_ACTIVE,
4139 EL_EMC_GATE_7_GRAY_ACTIVE,
4140 EL_EMC_GATE_8_GRAY_ACTIVE,
4142 EL_DC_GATE_WHITE_GRAY,
4143 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4148 static int ep_amoeboid[] =
4160 static int ep_amoebalive[] =
4171 static int ep_has_editor_content[] =
4193 static int ep_can_turn_each_move[] =
4195 /* !!! do something with this one !!! */
4199 static int ep_can_grow[] =
4213 static int ep_active_bomb[] =
4216 EL_EM_DYNAMITE_ACTIVE,
4217 EL_DYNABOMB_PLAYER_1_ACTIVE,
4218 EL_DYNABOMB_PLAYER_2_ACTIVE,
4219 EL_DYNABOMB_PLAYER_3_ACTIVE,
4220 EL_DYNABOMB_PLAYER_4_ACTIVE,
4221 EL_SP_DISK_RED_ACTIVE,
4226 static int ep_inactive[] =
4236 EL_QUICKSAND_FAST_EMPTY,
4259 EL_GATE_1_GRAY_ACTIVE,
4260 EL_GATE_2_GRAY_ACTIVE,
4261 EL_GATE_3_GRAY_ACTIVE,
4262 EL_GATE_4_GRAY_ACTIVE,
4271 EL_EM_GATE_1_GRAY_ACTIVE,
4272 EL_EM_GATE_2_GRAY_ACTIVE,
4273 EL_EM_GATE_3_GRAY_ACTIVE,
4274 EL_EM_GATE_4_GRAY_ACTIVE,
4283 EL_EMC_GATE_5_GRAY_ACTIVE,
4284 EL_EMC_GATE_6_GRAY_ACTIVE,
4285 EL_EMC_GATE_7_GRAY_ACTIVE,
4286 EL_EMC_GATE_8_GRAY_ACTIVE,
4288 EL_DC_GATE_WHITE_GRAY,
4289 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4290 EL_DC_GATE_FAKE_GRAY,
4293 EL_INVISIBLE_STEELWALL,
4301 EL_WALL_EMERALD_YELLOW,
4302 EL_DYNABOMB_INCREASE_NUMBER,
4303 EL_DYNABOMB_INCREASE_SIZE,
4304 EL_DYNABOMB_INCREASE_POWER,
4308 EL_SOKOBAN_FIELD_EMPTY,
4309 EL_SOKOBAN_FIELD_FULL,
4310 EL_WALL_EMERALD_RED,
4311 EL_WALL_EMERALD_PURPLE,
4312 EL_ACID_POOL_TOPLEFT,
4313 EL_ACID_POOL_TOPRIGHT,
4314 EL_ACID_POOL_BOTTOMLEFT,
4315 EL_ACID_POOL_BOTTOM,
4316 EL_ACID_POOL_BOTTOMRIGHT,
4320 EL_BD_MAGIC_WALL_DEAD,
4322 EL_DC_MAGIC_WALL_DEAD,
4323 EL_AMOEBA_TO_DIAMOND,
4331 EL_SP_GRAVITY_PORT_RIGHT,
4332 EL_SP_GRAVITY_PORT_DOWN,
4333 EL_SP_GRAVITY_PORT_LEFT,
4334 EL_SP_GRAVITY_PORT_UP,
4335 EL_SP_PORT_HORIZONTAL,
4336 EL_SP_PORT_VERTICAL,
4347 EL_SP_HARDWARE_GRAY,
4348 EL_SP_HARDWARE_GREEN,
4349 EL_SP_HARDWARE_BLUE,
4351 EL_SP_HARDWARE_YELLOW,
4352 EL_SP_HARDWARE_BASE_1,
4353 EL_SP_HARDWARE_BASE_2,
4354 EL_SP_HARDWARE_BASE_3,
4355 EL_SP_HARDWARE_BASE_4,
4356 EL_SP_HARDWARE_BASE_5,
4357 EL_SP_HARDWARE_BASE_6,
4358 EL_SP_GRAVITY_ON_PORT_LEFT,
4359 EL_SP_GRAVITY_ON_PORT_RIGHT,
4360 EL_SP_GRAVITY_ON_PORT_UP,
4361 EL_SP_GRAVITY_ON_PORT_DOWN,
4362 EL_SP_GRAVITY_OFF_PORT_LEFT,
4363 EL_SP_GRAVITY_OFF_PORT_RIGHT,
4364 EL_SP_GRAVITY_OFF_PORT_UP,
4365 EL_SP_GRAVITY_OFF_PORT_DOWN,
4366 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4367 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4368 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4369 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4370 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4371 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4372 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4373 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4374 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4375 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4376 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4377 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4378 EL_SIGN_EXCLAMATION,
4379 EL_SIGN_RADIOACTIVITY,
4386 EL_SIGN_ENTRY_FORBIDDEN,
4387 EL_SIGN_EMERGENCY_EXIT,
4395 EL_DC_STEELWALL_1_LEFT,
4396 EL_DC_STEELWALL_1_RIGHT,
4397 EL_DC_STEELWALL_1_TOP,
4398 EL_DC_STEELWALL_1_BOTTOM,
4399 EL_DC_STEELWALL_1_HORIZONTAL,
4400 EL_DC_STEELWALL_1_VERTICAL,
4401 EL_DC_STEELWALL_1_TOPLEFT,
4402 EL_DC_STEELWALL_1_TOPRIGHT,
4403 EL_DC_STEELWALL_1_BOTTOMLEFT,
4404 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4405 EL_DC_STEELWALL_1_TOPLEFT_2,
4406 EL_DC_STEELWALL_1_TOPRIGHT_2,
4407 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4408 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4409 EL_DC_STEELWALL_2_LEFT,
4410 EL_DC_STEELWALL_2_RIGHT,
4411 EL_DC_STEELWALL_2_TOP,
4412 EL_DC_STEELWALL_2_BOTTOM,
4413 EL_DC_STEELWALL_2_HORIZONTAL,
4414 EL_DC_STEELWALL_2_VERTICAL,
4415 EL_DC_STEELWALL_2_MIDDLE,
4416 EL_DC_STEELWALL_2_SINGLE,
4417 EL_STEELWALL_SLIPPERY,
4422 EL_EMC_WALL_SLIPPERY_1,
4423 EL_EMC_WALL_SLIPPERY_2,
4424 EL_EMC_WALL_SLIPPERY_3,
4425 EL_EMC_WALL_SLIPPERY_4,
4446 static int ep_em_slippery_wall[] =
4451 static int ep_gfx_crumbled[] =
4462 static int ep_editor_cascade_active[] =
4464 EL_INTERNAL_CASCADE_BD_ACTIVE,
4465 EL_INTERNAL_CASCADE_EM_ACTIVE,
4466 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4467 EL_INTERNAL_CASCADE_RND_ACTIVE,
4468 EL_INTERNAL_CASCADE_SB_ACTIVE,
4469 EL_INTERNAL_CASCADE_SP_ACTIVE,
4470 EL_INTERNAL_CASCADE_DC_ACTIVE,
4471 EL_INTERNAL_CASCADE_DX_ACTIVE,
4472 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4473 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4474 EL_INTERNAL_CASCADE_CE_ACTIVE,
4475 EL_INTERNAL_CASCADE_GE_ACTIVE,
4476 EL_INTERNAL_CASCADE_REF_ACTIVE,
4477 EL_INTERNAL_CASCADE_USER_ACTIVE,
4478 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4483 static int ep_editor_cascade_inactive[] =
4485 EL_INTERNAL_CASCADE_BD,
4486 EL_INTERNAL_CASCADE_EM,
4487 EL_INTERNAL_CASCADE_EMC,
4488 EL_INTERNAL_CASCADE_RND,
4489 EL_INTERNAL_CASCADE_SB,
4490 EL_INTERNAL_CASCADE_SP,
4491 EL_INTERNAL_CASCADE_DC,
4492 EL_INTERNAL_CASCADE_DX,
4493 EL_INTERNAL_CASCADE_CHARS,
4494 EL_INTERNAL_CASCADE_STEEL_CHARS,
4495 EL_INTERNAL_CASCADE_CE,
4496 EL_INTERNAL_CASCADE_GE,
4497 EL_INTERNAL_CASCADE_REF,
4498 EL_INTERNAL_CASCADE_USER,
4499 EL_INTERNAL_CASCADE_DYNAMIC,
4504 static int ep_obsolete[] =
4508 EL_EM_KEY_1_FILE_OBSOLETE,
4509 EL_EM_KEY_2_FILE_OBSOLETE,
4510 EL_EM_KEY_3_FILE_OBSOLETE,
4511 EL_EM_KEY_4_FILE_OBSOLETE,
4512 EL_ENVELOPE_OBSOLETE,
4521 } element_properties[] =
4523 { ep_diggable, EP_DIGGABLE },
4524 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4525 { ep_dont_run_into, EP_DONT_RUN_INTO },
4526 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4527 { ep_dont_touch, EP_DONT_TOUCH },
4528 { ep_indestructible, EP_INDESTRUCTIBLE },
4529 { ep_slippery, EP_SLIPPERY },
4530 { ep_can_change, EP_CAN_CHANGE },
4531 { ep_can_move, EP_CAN_MOVE },
4532 { ep_can_fall, EP_CAN_FALL },
4533 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4534 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4535 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4536 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4537 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4538 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4539 { ep_walkable_over, EP_WALKABLE_OVER },
4540 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4541 { ep_walkable_under, EP_WALKABLE_UNDER },
4542 { ep_passable_over, EP_PASSABLE_OVER },
4543 { ep_passable_inside, EP_PASSABLE_INSIDE },
4544 { ep_passable_under, EP_PASSABLE_UNDER },
4545 { ep_droppable, EP_DROPPABLE },
4546 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4547 { ep_pushable, EP_PUSHABLE },
4548 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4549 { ep_protected, EP_PROTECTED },
4550 { ep_throwable, EP_THROWABLE },
4551 { ep_can_explode, EP_CAN_EXPLODE },
4552 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4554 { ep_player, EP_PLAYER },
4555 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4556 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4557 { ep_switchable, EP_SWITCHABLE },
4558 { ep_bd_element, EP_BD_ELEMENT },
4559 { ep_sp_element, EP_SP_ELEMENT },
4560 { ep_sb_element, EP_SB_ELEMENT },
4562 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4563 { ep_food_penguin, EP_FOOD_PENGUIN },
4564 { ep_food_pig, EP_FOOD_PIG },
4565 { ep_historic_wall, EP_HISTORIC_WALL },
4566 { ep_historic_solid, EP_HISTORIC_SOLID },
4567 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4568 { ep_belt, EP_BELT },
4569 { ep_belt_active, EP_BELT_ACTIVE },
4570 { ep_belt_switch, EP_BELT_SWITCH },
4571 { ep_tube, EP_TUBE },
4572 { ep_acid_pool, EP_ACID_POOL },
4573 { ep_keygate, EP_KEYGATE },
4574 { ep_amoeboid, EP_AMOEBOID },
4575 { ep_amoebalive, EP_AMOEBALIVE },
4576 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4577 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4578 { ep_can_grow, EP_CAN_GROW },
4579 { ep_active_bomb, EP_ACTIVE_BOMB },
4580 { ep_inactive, EP_INACTIVE },
4582 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4584 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4586 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4587 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4589 { ep_obsolete, EP_OBSOLETE },
4596 /* always start with reliable default values (element has no properties) */
4597 /* (but never initialize clipboard elements after the very first time) */
4598 /* (to be able to use clipboard elements between several levels) */
4599 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4600 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4601 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4602 SET_PROPERTY(i, j, FALSE);
4604 /* set all base element properties from above array definitions */
4605 for (i = 0; element_properties[i].elements != NULL; i++)
4606 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4607 SET_PROPERTY((element_properties[i].elements)[j],
4608 element_properties[i].property, TRUE);
4610 /* copy properties to some elements that are only stored in level file */
4611 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4612 for (j = 0; copy_properties[j][0] != -1; j++)
4613 if (HAS_PROPERTY(copy_properties[j][0], i))
4614 for (k = 1; k <= 4; k++)
4615 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4617 /* set static element properties that are not listed in array definitions */
4618 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4619 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4621 clipboard_elements_initialized = TRUE;
4624 void InitElementPropertiesEngine(int engine_version)
4626 static int no_wall_properties[] =
4629 EP_COLLECTIBLE_ONLY,
4631 EP_DONT_COLLIDE_WITH,
4634 EP_CAN_SMASH_PLAYER,
4635 EP_CAN_SMASH_ENEMIES,
4636 EP_CAN_SMASH_EVERYTHING,
4641 EP_FOOD_DARK_YAMYAM,
4657 /* important: after initialization in InitElementPropertiesStatic(), the
4658 elements are not again initialized to a default value; therefore all
4659 changes have to make sure that they leave the element with a defined
4660 property (which means that conditional property changes must be set to
4661 a reliable default value before) */
4663 /* resolve group elements */
4664 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4665 ResolveGroupElement(EL_GROUP_START + i);
4667 /* set all special, combined or engine dependent element properties */
4668 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4670 /* do not change (already initialized) clipboard elements here */
4671 if (IS_CLIPBOARD_ELEMENT(i))
4674 /* ---------- INACTIVE ------------------------------------------------- */
4675 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4676 i <= EL_CHAR_END) ||
4677 (i >= EL_STEEL_CHAR_START &&
4678 i <= EL_STEEL_CHAR_END)));
4680 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4681 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4682 IS_WALKABLE_INSIDE(i) ||
4683 IS_WALKABLE_UNDER(i)));
4685 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4686 IS_PASSABLE_INSIDE(i) ||
4687 IS_PASSABLE_UNDER(i)));
4689 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4690 IS_PASSABLE_OVER(i)));
4692 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4693 IS_PASSABLE_INSIDE(i)));
4695 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4696 IS_PASSABLE_UNDER(i)));
4698 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4701 /* ---------- COLLECTIBLE ---------------------------------------------- */
4702 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4706 /* ---------- SNAPPABLE ------------------------------------------------ */
4707 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4708 IS_COLLECTIBLE(i) ||
4712 /* ---------- WALL ----------------------------------------------------- */
4713 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4715 for (j = 0; no_wall_properties[j] != -1; j++)
4716 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4717 i >= EL_FIRST_RUNTIME_UNREAL)
4718 SET_PROPERTY(i, EP_WALL, FALSE);
4720 if (IS_HISTORIC_WALL(i))
4721 SET_PROPERTY(i, EP_WALL, TRUE);
4723 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4724 if (engine_version < VERSION_IDENT(2,2,0,0))
4725 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4727 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4729 !IS_COLLECTIBLE(i)));
4731 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4732 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4733 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4735 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4736 IS_INDESTRUCTIBLE(i)));
4738 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4740 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4741 else if (engine_version < VERSION_IDENT(2,2,0,0))
4742 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4744 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4748 if (IS_CUSTOM_ELEMENT(i))
4750 /* these are additional properties which are initially false when set */
4752 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4754 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4755 if (DONT_COLLIDE_WITH(i))
4756 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4758 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4759 if (CAN_SMASH_EVERYTHING(i))
4760 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4761 if (CAN_SMASH_ENEMIES(i))
4762 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4765 /* ---------- CAN_SMASH ------------------------------------------------ */
4766 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4767 CAN_SMASH_ENEMIES(i) ||
4768 CAN_SMASH_EVERYTHING(i)));
4770 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4771 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4772 EXPLODES_BY_FIRE(i)));
4774 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4775 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4776 EXPLODES_SMASHED(i)));
4778 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4779 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4780 EXPLODES_IMPACT(i)));
4782 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4783 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4785 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4786 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4787 i == EL_BLACK_ORB));
4789 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4790 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4792 IS_CUSTOM_ELEMENT(i)));
4794 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4795 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4796 i == EL_SP_ELECTRON));
4798 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4799 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4800 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4801 getMoveIntoAcidProperty(&level, i));
4803 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4804 if (MAYBE_DONT_COLLIDE_WITH(i))
4805 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4806 getDontCollideWithProperty(&level, i));
4808 /* ---------- SP_PORT -------------------------------------------------- */
4809 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4810 IS_PASSABLE_INSIDE(i)));
4812 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4813 for (j = 0; j < level.num_android_clone_elements; j++)
4814 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4816 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4818 /* ---------- CAN_CHANGE ----------------------------------------------- */
4819 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4820 for (j = 0; j < element_info[i].num_change_pages; j++)
4821 if (element_info[i].change_page[j].can_change)
4822 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4824 /* ---------- HAS_ACTION ----------------------------------------------- */
4825 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4826 for (j = 0; j < element_info[i].num_change_pages; j++)
4827 if (element_info[i].change_page[j].has_action)
4828 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4830 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4831 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4834 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4836 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4837 element_info[i].crumbled[ACTION_DEFAULT] !=
4838 element_info[i].graphic[ACTION_DEFAULT]);
4840 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
4841 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4842 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
4845 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4846 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4847 IS_EDITOR_CASCADE_INACTIVE(i)));
4850 /* dynamically adjust element properties according to game engine version */
4852 static int ep_em_slippery_wall[] =
4857 EL_EXPANDABLE_WALL_HORIZONTAL,
4858 EL_EXPANDABLE_WALL_VERTICAL,
4859 EL_EXPANDABLE_WALL_ANY,
4860 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4861 EL_EXPANDABLE_STEELWALL_VERTICAL,
4862 EL_EXPANDABLE_STEELWALL_ANY,
4863 EL_EXPANDABLE_STEELWALL_GROWING,
4867 static int ep_em_explodes_by_fire[] =
4870 EL_EM_DYNAMITE_ACTIVE,
4875 /* special EM style gems behaviour */
4876 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4877 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4878 level.em_slippery_gems);
4880 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4881 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4882 (level.em_slippery_gems &&
4883 engine_version > VERSION_IDENT(2,0,1,0)));
4885 /* special EM style explosion behaviour regarding chain reactions */
4886 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4887 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4888 level.em_explodes_by_fire);
4891 /* this is needed because some graphics depend on element properties */
4892 if (game_status == GAME_MODE_PLAYING)
4893 InitElementGraphicInfo();
4896 void InitElementPropertiesAfterLoading(int engine_version)
4900 /* set some other uninitialized values of custom elements in older levels */
4901 if (engine_version < VERSION_IDENT(3,1,0,0))
4903 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4905 int element = EL_CUSTOM_START + i;
4907 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4909 element_info[element].explosion_delay = 17;
4910 element_info[element].ignition_delay = 8;
4915 void InitElementPropertiesGfxElement()
4919 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4921 struct ElementInfo *ei = &element_info[i];
4923 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4927 static void InitGlobal()
4932 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4934 /* check if element_name_info entry defined for each element in "main.h" */
4935 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4936 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4938 element_info[i].token_name = element_name_info[i].token_name;
4939 element_info[i].class_name = element_name_info[i].class_name;
4940 element_info[i].editor_description= element_name_info[i].editor_description;
4943 printf("%04d: %s\n", i, element_name_info[i].token_name);
4947 /* create hash from image config list */
4948 image_config_hash = newSetupFileHash();
4949 for (i = 0; image_config[i].token != NULL; i++)
4950 setHashEntry(image_config_hash,
4951 image_config[i].token,
4952 image_config[i].value);
4954 /* create hash from element token list */
4955 element_token_hash = newSetupFileHash();
4956 for (i = 0; element_name_info[i].token_name != NULL; i++)
4957 setHashEntry(element_token_hash,
4958 element_name_info[i].token_name,
4961 /* create hash from graphic token list */
4962 graphic_token_hash = newSetupFileHash();
4963 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4964 if (strSuffix(image_config[i].value, ".pcx") ||
4965 strSuffix(image_config[i].value, ".wav") ||
4966 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4967 setHashEntry(graphic_token_hash,
4968 image_config[i].token,
4969 int2str(graphic++, 0));
4971 /* create hash from font token list */
4972 font_token_hash = newSetupFileHash();
4973 for (i = 0; font_info[i].token_name != NULL; i++)
4974 setHashEntry(font_token_hash,
4975 font_info[i].token_name,
4978 /* always start with reliable default values (all elements) */
4979 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4980 ActiveElement[i] = i;
4982 /* now add all entries that have an active state (active elements) */
4983 for (i = 0; element_with_active_state[i].element != -1; i++)
4985 int element = element_with_active_state[i].element;
4986 int element_active = element_with_active_state[i].element_active;
4988 ActiveElement[element] = element_active;
4991 /* always start with reliable default values (all buttons) */
4992 for (i = 0; i < NUM_IMAGE_FILES; i++)
4993 ActiveButton[i] = i;
4995 /* now add all entries that have an active state (active buttons) */
4996 for (i = 0; button_with_active_state[i].button != -1; i++)
4998 int button = button_with_active_state[i].button;
4999 int button_active = button_with_active_state[i].button_active;
5001 ActiveButton[button] = button_active;
5004 /* always start with reliable default values (all fonts) */
5005 for (i = 0; i < NUM_FONTS; i++)
5008 /* now add all entries that have an active state (active fonts) */
5009 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
5011 int font = font_with_active_state[i].font_nr;
5012 int font_active = font_with_active_state[i].font_nr_active;
5014 ActiveFont[font] = font_active;
5017 global.autoplay_leveldir = NULL;
5018 global.convert_leveldir = NULL;
5019 global.create_images_dir = NULL;
5021 global.frames_per_second = 0;
5022 global.fps_slowdown = FALSE;
5023 global.fps_slowdown_factor = 1;
5025 global.border_status = GAME_MODE_MAIN;
5027 global.fading_status = GAME_MODE_MAIN;
5028 global.fading_type = TYPE_ENTER_MENU;
5032 void Execute_Command(char *command)
5036 if (strEqual(command, "print graphicsinfo.conf"))
5038 printf("# You can configure additional/alternative image files here.\n");
5039 printf("# (The entries below are default and therefore commented out.)\n");
5041 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
5043 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5046 for (i = 0; image_config[i].token != NULL; i++)
5047 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
5048 image_config[i].value));
5052 else if (strEqual(command, "print soundsinfo.conf"))
5054 printf("# You can configure additional/alternative sound files here.\n");
5055 printf("# (The entries below are default and therefore commented out.)\n");
5057 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
5059 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5062 for (i = 0; sound_config[i].token != NULL; i++)
5063 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
5064 sound_config[i].value));
5068 else if (strEqual(command, "print musicinfo.conf"))
5070 printf("# You can configure additional/alternative music files here.\n");
5071 printf("# (The entries below are default and therefore commented out.)\n");
5073 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
5075 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5078 for (i = 0; music_config[i].token != NULL; i++)
5079 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
5080 music_config[i].value));
5084 else if (strEqual(command, "print editorsetup.conf"))
5086 printf("# You can configure your personal editor element list here.\n");
5087 printf("# (The entries below are default and therefore commented out.)\n");
5090 /* this is needed to be able to check element list for cascade elements */
5091 InitElementPropertiesStatic();
5092 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5094 PrintEditorElementList();
5098 else if (strEqual(command, "print helpanim.conf"))
5100 printf("# You can configure different element help animations here.\n");
5101 printf("# (The entries below are default and therefore commented out.)\n");
5104 for (i = 0; helpanim_config[i].token != NULL; i++)
5106 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
5107 helpanim_config[i].value));
5109 if (strEqual(helpanim_config[i].token, "end"))
5115 else if (strEqual(command, "print helptext.conf"))
5117 printf("# You can configure different element help text here.\n");
5118 printf("# (The entries below are default and therefore commented out.)\n");
5121 for (i = 0; helptext_config[i].token != NULL; i++)
5122 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
5123 helptext_config[i].value));
5127 else if (strncmp(command, "dump level ", 11) == 0)
5129 char *filename = &command[11];
5131 if (!fileExists(filename))
5132 Error(ERR_EXIT, "cannot open file '%s'", filename);
5134 LoadLevelFromFilename(&level, filename);
5139 else if (strncmp(command, "dump tape ", 10) == 0)
5141 char *filename = &command[10];
5143 if (!fileExists(filename))
5144 Error(ERR_EXIT, "cannot open file '%s'", filename);
5146 LoadTapeFromFilename(filename);
5151 else if (strncmp(command, "autoplay ", 9) == 0)
5153 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
5155 while (*str_ptr != '\0') /* continue parsing string */
5157 /* cut leading whitespace from string, replace it by string terminator */
5158 while (*str_ptr == ' ' || *str_ptr == '\t')
5161 if (*str_ptr == '\0') /* end of string reached */
5164 if (global.autoplay_leveldir == NULL) /* read level set string */
5166 global.autoplay_leveldir = str_ptr;
5167 global.autoplay_all = TRUE; /* default: play all tapes */
5169 for (i = 0; i < MAX_TAPES_PER_SET; i++)
5170 global.autoplay_level[i] = FALSE;
5172 else /* read level number string */
5174 int level_nr = atoi(str_ptr); /* get level_nr value */
5176 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5177 global.autoplay_level[level_nr] = TRUE;
5179 global.autoplay_all = FALSE;
5182 /* advance string pointer to the next whitespace (or end of string) */
5183 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5187 else if (strncmp(command, "convert ", 8) == 0)
5189 char *str_copy = getStringCopy(&command[8]);
5190 char *str_ptr = strchr(str_copy, ' ');
5192 global.convert_leveldir = str_copy;
5193 global.convert_level_nr = -1;
5195 if (str_ptr != NULL) /* level number follows */
5197 *str_ptr++ = '\0'; /* terminate leveldir string */
5198 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
5201 else if (strncmp(command, "create images ", 14) == 0)
5203 #if defined(TARGET_SDL)
5204 global.create_images_dir = getStringCopy(&command[14]);
5206 if (access(global.create_images_dir, W_OK) != 0)
5207 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
5208 global.create_images_dir);
5210 Error(ERR_EXIT, "command only available for SDL target");
5215 #if defined(TARGET_SDL)
5216 else if (strEqual(command, "SDL_ListModes"))
5221 SDL_Init(SDL_INIT_VIDEO);
5223 /* get available fullscreen/hardware modes */
5224 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
5226 /* check if there are any modes available */
5229 printf("No modes available!\n");
5234 /* check if our resolution is restricted */
5235 if (modes == (SDL_Rect **)-1)
5237 printf("All resolutions available.\n");
5241 printf("Available Modes:\n");
5243 for(i = 0; modes[i]; i++)
5244 printf(" %d x %d\n", modes[i]->w, modes[i]->h);
5254 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
5258 static void InitSetup()
5260 LoadSetup(); /* global setup info */
5262 /* set some options from setup file */
5264 if (setup.options.verbose)
5265 options.verbose = TRUE;
5268 static void InitGameInfo()
5270 game.restart_level = FALSE;
5273 static void InitPlayerInfo()
5277 /* choose default local player */
5278 local_player = &stored_player[0];
5280 for (i = 0; i < MAX_PLAYERS; i++)
5281 stored_player[i].connected = FALSE;
5283 local_player->connected = TRUE;
5286 static void InitArtworkInfo()
5291 static char *get_string_in_brackets(char *string)
5293 char *string_in_brackets = checked_malloc(strlen(string) + 3);
5295 sprintf(string_in_brackets, "[%s]", string);
5297 return string_in_brackets;
5300 static char *get_level_id_suffix(int id_nr)
5302 char *id_suffix = checked_malloc(1 + 3 + 1);
5304 if (id_nr < 0 || id_nr > 999)
5307 sprintf(id_suffix, ".%03d", id_nr);
5313 static char *get_element_class_token(int element)
5315 char *element_class_name = element_info[element].class_name;
5316 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
5318 sprintf(element_class_token, "[%s]", element_class_name);
5320 return element_class_token;
5323 static char *get_action_class_token(int action)
5325 char *action_class_name = &element_action_info[action].suffix[1];
5326 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
5328 sprintf(action_class_token, "[%s]", action_class_name);
5330 return action_class_token;
5334 static void InitArtworkConfig()
5336 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
5337 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
5338 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
5339 static char *action_id_suffix[NUM_ACTIONS + 1];
5340 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5341 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5342 static char *level_id_suffix[MAX_LEVELS + 1];
5343 static char *dummy[1] = { NULL };
5344 static char *ignore_generic_tokens[] =
5350 static char **ignore_image_tokens;
5351 static char **ignore_sound_tokens;
5352 static char **ignore_music_tokens;
5353 int num_ignore_generic_tokens;
5354 int num_ignore_image_tokens;
5355 int num_ignore_sound_tokens;
5356 int num_ignore_music_tokens;
5359 /* dynamically determine list of generic tokens to be ignored */
5360 num_ignore_generic_tokens = 0;
5361 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5362 num_ignore_generic_tokens++;
5364 /* dynamically determine list of image tokens to be ignored */
5365 num_ignore_image_tokens = num_ignore_generic_tokens;
5366 for (i = 0; image_config_vars[i].token != NULL; i++)
5367 num_ignore_image_tokens++;
5368 ignore_image_tokens =
5369 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5370 for (i = 0; i < num_ignore_generic_tokens; i++)
5371 ignore_image_tokens[i] = ignore_generic_tokens[i];
5372 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5373 ignore_image_tokens[num_ignore_generic_tokens + i] =
5374 image_config_vars[i].token;
5375 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5377 /* dynamically determine list of sound tokens to be ignored */
5378 num_ignore_sound_tokens = num_ignore_generic_tokens;
5379 ignore_sound_tokens =
5380 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5381 for (i = 0; i < num_ignore_generic_tokens; i++)
5382 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5383 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5385 /* dynamically determine list of music tokens to be ignored */
5386 num_ignore_music_tokens = num_ignore_generic_tokens;
5387 ignore_music_tokens =
5388 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5389 for (i = 0; i < num_ignore_generic_tokens; i++)
5390 ignore_music_tokens[i] = ignore_generic_tokens[i];
5391 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5393 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5394 image_id_prefix[i] = element_info[i].token_name;
5395 for (i = 0; i < NUM_FONTS; i++)
5396 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5397 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
5399 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5400 sound_id_prefix[i] = element_info[i].token_name;
5401 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5402 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5403 get_string_in_brackets(element_info[i].class_name);
5404 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
5406 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5407 music_id_prefix[i] = music_prefix_info[i].prefix;
5408 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
5410 for (i = 0; i < NUM_ACTIONS; i++)
5411 action_id_suffix[i] = element_action_info[i].suffix;
5412 action_id_suffix[NUM_ACTIONS] = NULL;
5414 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5415 direction_id_suffix[i] = element_direction_info[i].suffix;
5416 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5418 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5419 special_id_suffix[i] = special_suffix_info[i].suffix;
5420 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5422 for (i = 0; i < MAX_LEVELS; i++)
5423 level_id_suffix[i] = get_level_id_suffix(i);
5424 level_id_suffix[MAX_LEVELS] = NULL;
5426 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5427 image_id_prefix, action_id_suffix, direction_id_suffix,
5428 special_id_suffix, ignore_image_tokens);
5429 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5430 sound_id_prefix, action_id_suffix, dummy,
5431 special_id_suffix, ignore_sound_tokens);
5432 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5433 music_id_prefix, special_id_suffix, level_id_suffix,
5434 dummy, ignore_music_tokens);
5437 static void InitMixer()
5446 struct GraphicInfo *graphic_info_last = graphic_info;
5447 char *filename_font_initial = NULL;
5448 char *filename_anim_initial = NULL;
5449 Bitmap *bitmap_font_initial = NULL;
5453 /* determine settings for initial font (for displaying startup messages) */
5454 for (i = 0; image_config[i].token != NULL; i++)
5456 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5458 char font_token[128];
5461 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5462 len_font_token = strlen(font_token);
5464 if (strEqual(image_config[i].token, font_token))
5465 filename_font_initial = image_config[i].value;
5466 else if (strlen(image_config[i].token) > len_font_token &&
5467 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5469 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5470 font_initial[j].src_x = atoi(image_config[i].value);
5471 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5472 font_initial[j].src_y = atoi(image_config[i].value);
5473 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5474 font_initial[j].width = atoi(image_config[i].value);
5475 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5476 font_initial[j].height = atoi(image_config[i].value);
5481 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5483 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5484 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5487 if (filename_font_initial == NULL) /* should not happen */
5488 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5490 /* create additional image buffers for double-buffering and cross-fading */
5491 bitmap_db_cross = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5492 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
5493 bitmap_db_panel = CreateBitmap(DXSIZE, DYSIZE, DEFAULT_DEPTH);
5494 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
5495 bitmap_db_toons = CreateBitmap(FULL_SXSIZE, FULL_SYSIZE, DEFAULT_DEPTH);
5497 /* initialize screen properties */
5498 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5499 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5501 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5502 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5503 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5504 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5505 InitGfxCustomArtworkInfo();
5507 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5509 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5510 font_initial[j].bitmap = bitmap_font_initial;
5512 InitFontGraphicInfo();
5514 font_height = getFontHeight(FC_RED);
5517 DrawInitText(getWindowTitleString(), 20, FC_YELLOW);
5519 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
5521 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
5522 DrawInitText(PROGRAM_WEBSITE_STRING, WIN_YSIZE - 20 - font_height, FC_RED);
5524 DrawInitText("Loading graphics", 120, FC_GREEN);
5528 /* initialize busy animation with default values */
5529 int parameter[NUM_GFX_ARGS];
5530 for (i = 0; i < NUM_GFX_ARGS; i++)
5531 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5532 image_config_suffix[i].token,
5533 image_config_suffix[i].type);
5535 for (i = 0; i < NUM_GFX_ARGS; i++)
5536 printf("::: '%s' => %d\n", image_config_suffix[i].token, parameter[i]);
5540 /* determine settings for busy animation (when displaying startup messages) */
5541 for (i = 0; image_config[i].token != NULL; i++)
5543 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5544 int len_anim_token = strlen(anim_token);
5546 if (strEqual(image_config[i].token, anim_token))
5547 filename_anim_initial = image_config[i].value;
5548 else if (strlen(image_config[i].token) > len_anim_token &&
5549 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5552 for (j = 0; image_config_suffix[j].token != NULL; j++)
5554 if (strEqual(&image_config[i].token[len_anim_token],
5555 image_config_suffix[j].token))
5557 get_graphic_parameter_value(image_config[i].value,
5558 image_config_suffix[j].token,
5559 image_config_suffix[j].type);
5562 if (strEqual(&image_config[i].token[len_anim_token], ".x"))
5563 anim_initial.src_x = atoi(image_config[i].value);
5564 else if (strEqual(&image_config[i].token[len_anim_token], ".y"))
5565 anim_initial.src_y = atoi(image_config[i].value);
5566 else if (strEqual(&image_config[i].token[len_anim_token], ".width"))
5567 anim_initial.width = atoi(image_config[i].value);
5568 else if (strEqual(&image_config[i].token[len_anim_token], ".height"))
5569 anim_initial.height = atoi(image_config[i].value);
5570 else if (strEqual(&image_config[i].token[len_anim_token], ".frames"))
5571 anim_initial.anim_frames = atoi(image_config[i].value);
5572 else if (strEqual(&image_config[i].token[len_anim_token],
5573 ".frames_per_line"))
5574 anim_initial.anim_frames_per_line = atoi(image_config[i].value);
5575 else if (strEqual(&image_config[i].token[len_anim_token], ".delay"))
5576 anim_initial.anim_delay = atoi(image_config[i].value);
5581 #if defined(CREATE_SPECIAL_EDITION_RND_JUE)
5582 filename_anim_initial = "loading.pcx";
5584 parameter[GFX_ARG_X] = 0;
5585 parameter[GFX_ARG_Y] = 0;
5586 parameter[GFX_ARG_WIDTH] = 128;
5587 parameter[GFX_ARG_HEIGHT] = 40;
5588 parameter[GFX_ARG_FRAMES] = 32;
5589 parameter[GFX_ARG_DELAY] = 4;
5590 parameter[GFX_ARG_FRAMES_PER_LINE] = ARG_UNDEFINED_VALUE;
5593 if (filename_anim_initial == NULL) /* should not happen */
5594 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5596 anim_initial.bitmap = LoadCustomImage(filename_anim_initial);
5598 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
5600 set_graphic_parameters_ext(0, parameter, anim_initial.bitmap);
5603 printf("::: INIT_GFX: anim_frames_per_line == %d [%d / %d] [%d, %d]\n",
5604 graphic_info[0].anim_frames_per_line,
5605 get_scaled_graphic_width(0),
5606 graphic_info[0].width,
5607 getOriginalImageWidthFromImageID(0),
5608 graphic_info[0].scale_up_factor);
5611 graphic_info = graphic_info_last;
5613 init.busy.width = anim_initial.width;
5614 init.busy.height = anim_initial.height;
5616 InitMenuDesignSettings_Static();
5617 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5621 void RedrawBackground()
5623 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
5624 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
5626 redraw_mask = REDRAW_ALL;
5629 void InitGfxBackground()
5633 fieldbuffer = bitmap_db_field;
5634 SetDrawtoField(DRAW_BACKBUFFER);
5637 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5641 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
5642 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
5645 for (x = 0; x < MAX_BUF_XSIZE; x++)
5646 for (y = 0; y < MAX_BUF_YSIZE; y++)
5649 redraw_mask = REDRAW_ALL;
5652 static void InitLevelInfo()
5654 LoadLevelInfo(); /* global level info */
5655 LoadLevelSetup_LastSeries(); /* last played series info */
5656 LoadLevelSetup_SeriesInfo(); /* last played level info */
5659 static void InitLevelArtworkInfo()
5661 LoadLevelArtworkInfo();
5664 static void InitImages()
5666 print_timestamp_init("InitImages");
5669 printf("::: leveldir_current->identifier == '%s'\n",
5670 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5671 printf("::: leveldir_current->graphics_path == '%s'\n",
5672 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5673 printf("::: leveldir_current->graphics_set == '%s'\n",
5674 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5675 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5676 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5679 setLevelArtworkDir(artwork.gfx_first);
5682 printf("::: leveldir_current->identifier == '%s'\n",
5683 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5684 printf("::: leveldir_current->graphics_path == '%s'\n",
5685 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5686 printf("::: leveldir_current->graphics_set == '%s'\n",
5687 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5688 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5689 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5693 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5694 leveldir_current->identifier,
5695 artwork.gfx_current_identifier,
5696 artwork.gfx_current->identifier,
5697 leveldir_current->graphics_set,
5698 leveldir_current->graphics_path);
5701 UPDATE_BUSY_STATE();
5703 ReloadCustomImages();
5704 print_timestamp_time("ReloadCustomImages");
5706 UPDATE_BUSY_STATE();
5708 LoadCustomElementDescriptions();
5709 print_timestamp_time("LoadCustomElementDescriptions");
5711 UPDATE_BUSY_STATE();
5713 LoadMenuDesignSettings();
5714 print_timestamp_time("LoadMenuDesignSettings");
5716 UPDATE_BUSY_STATE();
5718 ReinitializeGraphics();
5719 print_timestamp_time("ReinitializeGraphics");
5721 UPDATE_BUSY_STATE();
5723 print_timestamp_done("InitImages");
5726 static void InitSound(char *identifier)
5728 print_timestamp_init("InitSound");
5730 if (identifier == NULL)
5731 identifier = artwork.snd_current->identifier;
5733 /* set artwork path to send it to the sound server process */
5734 setLevelArtworkDir(artwork.snd_first);
5736 InitReloadCustomSounds(identifier);
5737 print_timestamp_time("InitReloadCustomSounds");
5739 ReinitializeSounds();
5740 print_timestamp_time("ReinitializeSounds");
5742 print_timestamp_done("InitSound");
5745 static void InitMusic(char *identifier)
5747 print_timestamp_init("InitMusic");
5749 if (identifier == NULL)
5750 identifier = artwork.mus_current->identifier;
5752 /* set artwork path to send it to the sound server process */
5753 setLevelArtworkDir(artwork.mus_first);
5755 InitReloadCustomMusic(identifier);
5756 print_timestamp_time("InitReloadCustomMusic");
5758 ReinitializeMusic();
5759 print_timestamp_time("ReinitializeMusic");
5761 print_timestamp_done("InitMusic");
5764 void InitNetworkServer()
5766 #if defined(NETWORK_AVALIABLE)
5770 if (!options.network)
5773 #if defined(NETWORK_AVALIABLE)
5774 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5776 if (!ConnectToServer(options.server_host, options.server_port))
5777 Error(ERR_EXIT, "cannot connect to network game server");
5779 SendToServer_PlayerName(setup.player_name);
5780 SendToServer_ProtocolVersion();
5783 SendToServer_NrWanted(nr_wanted);
5787 static boolean CheckArtworkConfigForCustomElements(char *filename)
5789 SetupFileHash *setup_file_hash;
5790 boolean redefined_ce_found = FALSE;
5792 /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */
5794 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5796 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5798 char *token = HASH_ITERATION_TOKEN(itr);
5800 if (strPrefix(token, "custom_"))
5802 redefined_ce_found = TRUE;
5807 END_HASH_ITERATION(setup_file_hash, itr)
5809 freeSetupFileHash(setup_file_hash);
5812 return redefined_ce_found;
5815 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5817 char *filename_base, *filename_local;
5818 boolean redefined_ce_found = FALSE;
5820 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5823 printf("::: leveldir_current->identifier == '%s'\n",
5824 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5825 printf("::: leveldir_current->graphics_path == '%s'\n",
5826 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5827 printf("::: leveldir_current->graphics_set == '%s'\n",
5828 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5829 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5830 leveldir_current == NULL ? "[NULL]" :
5831 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5834 /* first look for special artwork configured in level series config */
5835 filename_base = getCustomArtworkLevelConfigFilename(type);
5838 printf("::: filename_base == '%s'\n", filename_base);
5841 if (fileExists(filename_base))
5842 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5844 filename_local = getCustomArtworkConfigFilename(type);
5847 printf("::: filename_local == '%s'\n", filename_local);
5850 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5851 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5854 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5857 return redefined_ce_found;
5860 static void InitOverrideArtwork()
5862 boolean redefined_ce_found = FALSE;
5864 /* to check if this level set redefines any CEs, do not use overriding */
5865 gfx.override_level_graphics = FALSE;
5866 gfx.override_level_sounds = FALSE;
5867 gfx.override_level_music = FALSE;
5869 /* now check if this level set has definitions for custom elements */
5870 if (setup.override_level_graphics == AUTO ||
5871 setup.override_level_sounds == AUTO ||
5872 setup.override_level_music == AUTO)
5873 redefined_ce_found =
5874 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5875 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5876 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5879 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5882 if (redefined_ce_found)
5884 /* this level set has CE definitions: change "AUTO" to "FALSE" */
5885 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5886 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
5887 gfx.override_level_music = (setup.override_level_music == TRUE);
5891 /* this level set has no CE definitions: change "AUTO" to "TRUE" */
5892 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5893 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
5894 gfx.override_level_music = (setup.override_level_music != FALSE);
5898 printf("::: => %d, %d, %d\n",
5899 gfx.override_level_graphics,
5900 gfx.override_level_sounds,
5901 gfx.override_level_music);
5905 static char *getNewArtworkIdentifier(int type)
5907 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5908 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5909 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5910 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5911 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5913 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5915 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
5917 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5918 char *leveldir_identifier = leveldir_current->identifier;
5920 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
5921 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5923 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
5925 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5926 char *artwork_current_identifier;
5927 char *artwork_new_identifier = NULL; /* default: nothing has changed */
5929 /* leveldir_current may be invalid (level group, parent link) */
5930 if (!validLevelSeries(leveldir_current))
5933 /* 1st step: determine artwork set to be activated in descending order:
5934 --------------------------------------------------------------------
5935 1. setup artwork (when configured to override everything else)
5936 2. artwork set configured in "levelinfo.conf" of current level set
5937 (artwork in level directory will have priority when loading later)
5938 3. artwork in level directory (stored in artwork sub-directory)
5939 4. setup artwork (currently configured in setup menu) */
5941 if (setup_override_artwork)
5942 artwork_current_identifier = setup_artwork_set;
5943 else if (leveldir_artwork_set != NULL)
5944 artwork_current_identifier = leveldir_artwork_set;
5945 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5946 artwork_current_identifier = leveldir_identifier;
5948 artwork_current_identifier = setup_artwork_set;
5951 /* 2nd step: check if it is really needed to reload artwork set
5952 ------------------------------------------------------------ */
5955 if (type == ARTWORK_TYPE_GRAPHICS)
5956 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
5957 artwork_new_identifier,
5958 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5959 artwork_current_identifier,
5960 leveldir_current->graphics_set,
5961 leveldir_current->identifier);
5964 /* ---------- reload if level set and also artwork set has changed ------- */
5965 if (leveldir_current_identifier[type] != leveldir_identifier &&
5966 (last_has_level_artwork_set[type] || has_level_artwork_set))
5967 artwork_new_identifier = artwork_current_identifier;
5969 leveldir_current_identifier[type] = leveldir_identifier;
5970 last_has_level_artwork_set[type] = has_level_artwork_set;
5973 if (type == ARTWORK_TYPE_GRAPHICS)
5974 printf("::: 1: '%s'\n", artwork_new_identifier);
5977 /* ---------- reload if "override artwork" setting has changed ----------- */
5978 if (last_override_level_artwork[type] != setup_override_artwork)
5979 artwork_new_identifier = artwork_current_identifier;
5981 last_override_level_artwork[type] = setup_override_artwork;
5984 if (type == ARTWORK_TYPE_GRAPHICS)
5985 printf("::: 2: '%s'\n", artwork_new_identifier);
5988 /* ---------- reload if current artwork identifier has changed ----------- */
5989 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5990 artwork_current_identifier))
5991 artwork_new_identifier = artwork_current_identifier;
5993 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5996 if (type == ARTWORK_TYPE_GRAPHICS)
5997 printf("::: 3: '%s'\n", artwork_new_identifier);
6000 /* ---------- do not reload directly after starting ---------------------- */
6001 if (!initialized[type])
6002 artwork_new_identifier = NULL;
6004 initialized[type] = TRUE;
6007 if (type == ARTWORK_TYPE_GRAPHICS)
6008 printf("::: 4: '%s'\n", artwork_new_identifier);
6012 if (type == ARTWORK_TYPE_GRAPHICS)
6013 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
6014 artwork.gfx_current_identifier, artwork_current_identifier,
6015 artwork.gfx_current->identifier, leveldir_current->graphics_set,
6016 artwork_new_identifier);
6019 return artwork_new_identifier;
6022 void ReloadCustomArtwork(int force_reload)
6024 int last_game_status = game_status; /* save current game status */
6025 char *gfx_new_identifier;
6026 char *snd_new_identifier;
6027 char *mus_new_identifier;
6028 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
6029 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
6030 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
6031 boolean reload_needed;
6033 InitOverrideArtwork();
6035 force_reload_gfx |= AdjustGraphicsForEMC();
6037 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
6038 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
6039 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
6041 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
6042 snd_new_identifier != NULL || force_reload_snd ||
6043 mus_new_identifier != NULL || force_reload_mus);
6048 print_timestamp_init("ReloadCustomArtwork");
6050 game_status = GAME_MODE_LOADING;
6052 FadeOut(REDRAW_ALL);
6055 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6057 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
6059 print_timestamp_time("ClearRectangle");
6062 printf("::: fading in ... %d\n", fading.fade_mode);
6066 printf("::: done\n");
6069 if (gfx_new_identifier != NULL || force_reload_gfx)
6072 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
6073 artwork.gfx_current_identifier,
6075 artwork.gfx_current->identifier,
6076 leveldir_current->graphics_set);
6080 print_timestamp_time("InitImages");
6083 if (snd_new_identifier != NULL || force_reload_snd)
6085 InitSound(snd_new_identifier);
6086 print_timestamp_time("InitSound");
6089 if (mus_new_identifier != NULL || force_reload_mus)
6091 InitMusic(mus_new_identifier);
6092 print_timestamp_time("InitMusic");
6095 game_status = last_game_status; /* restore current game status */
6098 printf("::: ----------------DELAY 1 ...\n");
6103 printf("::: FadeOut @ ReloadCustomArtwork ...\n");
6105 FadeOut(REDRAW_ALL);
6107 printf("::: FadeOut @ ReloadCustomArtwork done\n");
6112 /* force redraw of (open or closed) door graphics */
6113 SetDoorState(DOOR_OPEN_ALL);
6114 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
6119 FadeSetEnterScreen();
6120 FadeSkipNextFadeOut();
6121 // FadeSetDisabled();
6126 fading = fading_none;
6131 redraw_mask = REDRAW_ALL;
6134 print_timestamp_done("ReloadCustomArtwork");
6137 void KeyboardAutoRepeatOffUnlessAutoplay()
6139 if (global.autoplay_leveldir == NULL)
6140 KeyboardAutoRepeatOff();
6144 /* ========================================================================= */
6146 /* ========================================================================= */
6150 print_timestamp_init("OpenAll");
6152 game_status = GAME_MODE_LOADING;
6154 InitGlobal(); /* initialize some global variables */
6156 if (options.execute_command)
6157 Execute_Command(options.execute_command);
6159 if (options.serveronly)
6161 #if defined(PLATFORM_UNIX)
6162 NetworkServer(options.server_port, options.serveronly);
6164 Error(ERR_WARN, "networking only supported in Unix version");
6167 exit(0); /* never reached, server loops forever */
6174 InitArtworkInfo(); /* needed before loading gfx, sound & music */
6175 InitArtworkConfig(); /* needed before forking sound child process */
6180 InitRND(NEW_RANDOMIZE);
6181 InitSimpleRandom(NEW_RANDOMIZE);
6185 print_timestamp_time("[pre-video]");
6188 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
6190 InitEventFilter(FilterMouseMotionEvents);
6192 InitElementPropertiesStatic();
6193 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
6194 InitElementPropertiesGfxElement();
6196 print_timestamp_time("[post-video]");
6200 print_timestamp_time("InitGfx");
6203 print_timestamp_time("InitLevelInfo");
6205 InitLevelArtworkInfo();
6206 print_timestamp_time("InitLevelArtworkInfo");
6208 InitOverrideArtwork(); /* needs to know current level directory */
6209 print_timestamp_time("InitOverrideArtwork");
6211 InitImages(); /* needs to know current level directory */
6212 print_timestamp_time("InitImages");
6214 InitSound(NULL); /* needs to know current level directory */
6215 print_timestamp_time("InitSound");
6217 InitMusic(NULL); /* needs to know current level directory */
6218 print_timestamp_time("InitMusic");
6220 InitGfxBackground();
6226 if (global.autoplay_leveldir)
6231 else if (global.convert_leveldir)
6236 else if (global.create_images_dir)
6238 CreateLevelSketchImages();
6242 game_status = GAME_MODE_MAIN;
6245 FadeSetEnterScreen();
6246 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
6247 FadeSkipNextFadeOut();
6248 // FadeSetDisabled();
6250 fading = fading_none;
6253 print_timestamp_time("[post-artwork]");
6255 print_timestamp_done("OpenAll");
6259 InitNetworkServer();
6262 void CloseAllAndExit(int exit_value)
6267 CloseAudio(); /* called after freeing sounds (needed for SDL) */
6275 #if defined(TARGET_SDL)
6276 if (network_server) /* terminate network server */
6277 SDL_KillThread(server_thread);
6280 CloseVideoDisplay();
6281 ClosePlatformDependentStuff();
6283 if (exit_value != 0)
6284 NotifyUserAboutErrorFile();