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;
348 return font_info[font_nr].special_bitmap_id[special];
353 static int getFontFromToken(char *token)
356 char *value = getHashEntry(font_token_hash, token);
363 /* !!! OPTIMIZE THIS BY USING HASH !!! */
364 for (i = 0; i < NUM_FONTS; i++)
365 if (strEqual(token, font_info[i].token_name))
369 /* if font not found, use reliable default value */
370 return FONT_INITIAL_1;
373 void InitFontGraphicInfo()
375 static struct FontBitmapInfo *font_bitmap_info = NULL;
376 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
377 int num_property_mappings = getImageListPropertyMappingSize();
378 int num_font_bitmaps = NUM_FONTS;
381 if (graphic_info == NULL) /* still at startup phase */
383 InitFontInfo(font_initial, NUM_INITIAL_FONTS,
384 getFontBitmapID, getFontFromToken);
389 /* ---------- initialize font graphic definitions ---------- */
391 /* always start with reliable default values (normal font graphics) */
392 for (i = 0; i < NUM_FONTS; i++)
393 font_info[i].graphic = IMG_FONT_INITIAL_1;
395 /* initialize normal font/graphic mapping from static configuration */
396 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
398 int font_nr = font_to_graphic[i].font_nr;
399 int special = font_to_graphic[i].special;
400 int graphic = font_to_graphic[i].graphic;
405 font_info[font_nr].graphic = graphic;
408 /* always start with reliable default values (special font graphics) */
409 for (i = 0; i < NUM_FONTS; i++)
411 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
413 font_info[i].special_graphic[j] = font_info[i].graphic;
414 font_info[i].special_bitmap_id[j] = i;
418 /* initialize special font/graphic mapping from static configuration */
419 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
421 int font_nr = font_to_graphic[i].font_nr;
422 int special = font_to_graphic[i].special;
423 int graphic = font_to_graphic[i].graphic;
424 int base_graphic = font2baseimg(font_nr);
426 if (IS_SPECIAL_GFX_ARG(special))
428 boolean base_redefined =
429 getImageListEntryFromImageID(base_graphic)->redefined;
430 boolean special_redefined =
431 getImageListEntryFromImageID(graphic)->redefined;
432 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
434 /* if the base font ("font.title_1", for example) has been redefined,
435 but not the special font ("font.title_1.LEVELS", for example), do not
436 use an existing (in this case considered obsolete) special font
437 anymore, but use the automatically determined default font */
438 /* special case: cloned special fonts must be explicitly redefined,
439 but are not automatically redefined by redefining base font */
440 if (base_redefined && !special_redefined && !special_cloned)
443 font_info[font_nr].special_graphic[special] = graphic;
444 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
449 /* initialize special font/graphic mapping from dynamic configuration */
450 for (i = 0; i < num_property_mappings; i++)
452 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
453 int special = property_mapping[i].ext3_index;
454 int graphic = property_mapping[i].artwork_index;
459 if (IS_SPECIAL_GFX_ARG(special))
461 font_info[font_nr].special_graphic[special] = graphic;
462 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
467 /* correct special font/graphic mapping for cloned fonts for downwards
468 compatibility of PREVIEW fonts -- this is only needed for implicit
469 redefinition of special font by redefined base font, and only if other
470 fonts are cloned from this special font (like in the "Zelda" level set) */
471 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
473 int font_nr = font_to_graphic[i].font_nr;
474 int special = font_to_graphic[i].special;
475 int graphic = font_to_graphic[i].graphic;
477 if (IS_SPECIAL_GFX_ARG(special))
479 boolean special_redefined =
480 getImageListEntryFromImageID(graphic)->redefined;
481 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
483 if (special_cloned && !special_redefined)
487 for (j = 0; font_to_graphic[j].font_nr > -1; j++)
489 int font_nr2 = font_to_graphic[j].font_nr;
490 int special2 = font_to_graphic[j].special;
491 int graphic2 = font_to_graphic[j].graphic;
493 if (IS_SPECIAL_GFX_ARG(special2) &&
494 graphic2 == graphic_info[graphic].clone_from)
496 font_info[font_nr].special_graphic[special] =
497 font_info[font_nr2].special_graphic[special2];
498 font_info[font_nr].special_bitmap_id[special] =
499 font_info[font_nr2].special_bitmap_id[special2];
506 /* reset non-redefined ".active" font graphics if normal font is redefined */
507 /* (this different treatment is needed because normal and active fonts are
508 independently defined ("active" is not a property of font definitions!) */
509 for (i = 0; i < NUM_FONTS; i++)
511 int font_nr_base = i;
512 int font_nr_active = FONT_ACTIVE(font_nr_base);
514 /* check only those fonts with exist as normal and ".active" variant */
515 if (font_nr_base != font_nr_active)
517 int base_graphic = font_info[font_nr_base].graphic;
518 int active_graphic = font_info[font_nr_active].graphic;
519 boolean base_redefined =
520 getImageListEntryFromImageID(base_graphic)->redefined;
521 boolean active_redefined =
522 getImageListEntryFromImageID(active_graphic)->redefined;
524 /* if the base font ("font.menu_1", for example) has been redefined,
525 but not the active font ("font.menu_1.active", for example), do not
526 use an existing (in this case considered obsolete) active font
527 anymore, but use the automatically determined default font */
528 if (base_redefined && !active_redefined)
529 font_info[font_nr_active].graphic = base_graphic;
531 /* now also check each "special" font (which may be the same as above) */
532 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
534 int base_graphic = font_info[font_nr_base].special_graphic[j];
535 int active_graphic = font_info[font_nr_active].special_graphic[j];
536 boolean base_redefined =
537 getImageListEntryFromImageID(base_graphic)->redefined;
538 boolean active_redefined =
539 getImageListEntryFromImageID(active_graphic)->redefined;
541 /* same as above, but check special graphic definitions, for example:
542 redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN" */
543 if (base_redefined && !active_redefined)
545 font_info[font_nr_active].special_graphic[j] =
546 font_info[font_nr_base].special_graphic[j];
547 font_info[font_nr_active].special_bitmap_id[j] =
548 font_info[font_nr_base].special_bitmap_id[j];
554 /* ---------- initialize font bitmap array ---------- */
556 if (font_bitmap_info != NULL)
557 FreeFontInfo(font_bitmap_info);
560 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
562 /* ---------- initialize font bitmap definitions ---------- */
564 for (i = 0; i < NUM_FONTS; i++)
566 if (i < NUM_INITIAL_FONTS)
568 font_bitmap_info[i] = font_initial[i];
572 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
574 int font_bitmap_id = font_info[i].special_bitmap_id[j];
575 int graphic = font_info[i].special_graphic[j];
577 /* set 'graphic_info' for font entries, if uninitialized (guessed) */
578 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
580 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
581 graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
584 /* copy font relevant information from graphics information */
585 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
586 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
587 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
588 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
589 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
591 font_bitmap_info[font_bitmap_id].draw_xoffset =
592 graphic_info[graphic].draw_xoffset;
593 font_bitmap_info[font_bitmap_id].draw_yoffset =
594 graphic_info[graphic].draw_yoffset;
596 font_bitmap_info[font_bitmap_id].num_chars =
597 graphic_info[graphic].anim_frames;
598 font_bitmap_info[font_bitmap_id].num_chars_per_line =
599 graphic_info[graphic].anim_frames_per_line;
603 InitFontInfo(font_bitmap_info, num_font_bitmaps,
604 getFontBitmapID, getFontFromToken);
607 void InitElementGraphicInfo()
609 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
610 int num_property_mappings = getImageListPropertyMappingSize();
613 if (graphic_info == NULL) /* still at startup phase */
616 /* set values to -1 to identify later as "uninitialized" values */
617 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
619 for (act = 0; act < NUM_ACTIONS; act++)
621 element_info[i].graphic[act] = -1;
622 element_info[i].crumbled[act] = -1;
624 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
626 element_info[i].direction_graphic[act][dir] = -1;
627 element_info[i].direction_crumbled[act][dir] = -1;
634 /* initialize normal element/graphic mapping from static configuration */
635 for (i = 0; element_to_graphic[i].element > -1; i++)
637 int element = element_to_graphic[i].element;
638 int action = element_to_graphic[i].action;
639 int direction = element_to_graphic[i].direction;
640 boolean crumbled = element_to_graphic[i].crumbled;
641 int graphic = element_to_graphic[i].graphic;
642 int base_graphic = el2baseimg(element);
644 if (graphic_info[graphic].bitmap == NULL)
647 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
650 boolean base_redefined =
651 getImageListEntryFromImageID(base_graphic)->redefined;
652 boolean act_dir_redefined =
653 getImageListEntryFromImageID(graphic)->redefined;
655 /* if the base graphic ("emerald", for example) has been redefined,
656 but not the action graphic ("emerald.falling", for example), do not
657 use an existing (in this case considered obsolete) action graphic
658 anymore, but use the automatically determined default graphic */
659 if (base_redefined && !act_dir_redefined)
664 action = ACTION_DEFAULT;
669 element_info[element].direction_crumbled[action][direction] = graphic;
671 element_info[element].crumbled[action] = graphic;
676 element_info[element].direction_graphic[action][direction] = graphic;
678 element_info[element].graphic[action] = graphic;
682 /* initialize normal element/graphic mapping from dynamic configuration */
683 for (i = 0; i < num_property_mappings; i++)
685 int element = property_mapping[i].base_index;
686 int action = property_mapping[i].ext1_index;
687 int direction = property_mapping[i].ext2_index;
688 int special = property_mapping[i].ext3_index;
689 int graphic = property_mapping[i].artwork_index;
690 boolean crumbled = FALSE;
693 if ((element == EL_EM_DYNAMITE ||
694 element == EL_EM_DYNAMITE_ACTIVE) &&
695 action == ACTION_ACTIVE &&
696 (special == GFX_SPECIAL_ARG_EDITOR ||
697 special == GFX_SPECIAL_ARG_PANEL))
698 printf("::: DYNAMIC: %d, %d, %d -> %d\n",
699 element, action, special, graphic);
702 if (special == GFX_SPECIAL_ARG_CRUMBLED)
708 if (graphic_info[graphic].bitmap == NULL)
711 if (element >= MAX_NUM_ELEMENTS || special != -1)
715 action = ACTION_DEFAULT;
720 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
721 element_info[element].direction_crumbled[action][dir] = -1;
724 element_info[element].direction_crumbled[action][direction] = graphic;
726 element_info[element].crumbled[action] = graphic;
731 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
732 element_info[element].direction_graphic[action][dir] = -1;
735 element_info[element].direction_graphic[action][direction] = graphic;
737 element_info[element].graphic[action] = graphic;
741 /* now copy all graphics that are defined to be cloned from other graphics */
742 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
744 int graphic = element_info[i].graphic[ACTION_DEFAULT];
745 int crumbled_like, diggable_like;
750 crumbled_like = graphic_info[graphic].crumbled_like;
751 diggable_like = graphic_info[graphic].diggable_like;
753 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
755 for (act = 0; act < NUM_ACTIONS; act++)
756 element_info[i].crumbled[act] =
757 element_info[crumbled_like].crumbled[act];
758 for (act = 0; act < NUM_ACTIONS; act++)
759 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
760 element_info[i].direction_crumbled[act][dir] =
761 element_info[crumbled_like].direction_crumbled[act][dir];
764 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
766 element_info[i].graphic[ACTION_DIGGING] =
767 element_info[diggable_like].graphic[ACTION_DIGGING];
768 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
769 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
770 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
775 /* set hardcoded definitions for some runtime elements without graphic */
776 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
780 /* set hardcoded definitions for some internal elements without graphic */
781 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
783 if (IS_EDITOR_CASCADE_INACTIVE(i))
784 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
785 else if (IS_EDITOR_CASCADE_ACTIVE(i))
786 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
790 /* now set all undefined/invalid graphics to -1 to set to default after it */
791 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
793 for (act = 0; act < NUM_ACTIONS; act++)
797 graphic = element_info[i].graphic[act];
798 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
799 element_info[i].graphic[act] = -1;
801 graphic = element_info[i].crumbled[act];
802 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
803 element_info[i].crumbled[act] = -1;
805 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
807 graphic = element_info[i].direction_graphic[act][dir];
808 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
809 element_info[i].direction_graphic[act][dir] = -1;
811 graphic = element_info[i].direction_crumbled[act][dir];
812 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
813 element_info[i].direction_crumbled[act][dir] = -1;
820 /* adjust graphics with 2nd tile for movement according to direction
821 (do this before correcting '-1' values to minimize calculations) */
822 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
824 for (act = 0; act < NUM_ACTIONS; act++)
826 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
828 int graphic = element_info[i].direction_graphic[act][dir];
829 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
831 if (act == ACTION_FALLING) /* special case */
832 graphic = element_info[i].graphic[act];
835 graphic_info[graphic].double_movement &&
836 graphic_info[graphic].swap_double_tiles != 0)
838 struct GraphicInfo *g = &graphic_info[graphic];
839 int src_x_front = g->src_x;
840 int src_y_front = g->src_y;
841 int src_x_back = g->src_x + g->offset2_x;
842 int src_y_back = g->src_y + g->offset2_y;
843 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
845 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
846 src_y_front < src_y_back);
847 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
848 boolean swap_movement_tiles_autodetected =
849 (!frames_are_ordered_diagonally &&
850 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
851 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
852 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
853 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
856 /* swap frontside and backside graphic tile coordinates, if needed */
857 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
859 /* get current (wrong) backside tile coordinates */
860 getGraphicSourceExt(graphic, 0, &dummy, &src_x_back, &src_y_back,
863 /* set frontside tile coordinates to backside tile coordinates */
864 g->src_x = src_x_back;
865 g->src_y = src_y_back;
867 /* invert tile offset to point to new backside tile coordinates */
871 /* do not swap front and backside tiles again after correction */
872 g->swap_double_tiles = 0;
881 /* now set all '-1' values to element specific default values */
882 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
884 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
885 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
886 int default_direction_graphic[NUM_DIRECTIONS_FULL];
887 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
889 if (default_graphic == -1)
890 default_graphic = IMG_UNKNOWN;
892 if (default_crumbled == -1)
893 default_crumbled = default_graphic;
895 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
896 if (default_crumbled == -1)
897 default_crumbled = IMG_EMPTY;
900 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
902 default_direction_graphic[dir] =
903 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
904 default_direction_crumbled[dir] =
905 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
907 if (default_direction_graphic[dir] == -1)
908 default_direction_graphic[dir] = default_graphic;
910 if (default_direction_crumbled[dir] == -1)
911 default_direction_crumbled[dir] = default_direction_graphic[dir];
913 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
914 if (default_direction_crumbled[dir] == -1)
915 default_direction_crumbled[dir] = default_crumbled;
919 for (act = 0; act < NUM_ACTIONS; act++)
921 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
922 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
923 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
924 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
925 act == ACTION_TURNING_FROM_RIGHT ||
926 act == ACTION_TURNING_FROM_UP ||
927 act == ACTION_TURNING_FROM_DOWN);
929 /* generic default action graphic (defined by "[default]" directive) */
930 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
931 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
932 int default_remove_graphic = IMG_EMPTY;
934 if (act_remove && default_action_graphic != -1)
935 default_remove_graphic = default_action_graphic;
937 /* look for special default action graphic (classic game specific) */
938 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
939 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
940 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
941 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
942 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
943 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
945 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
946 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
947 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
948 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
949 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
950 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
953 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
954 /* !!! make this better !!! */
955 if (i == EL_EMPTY_SPACE)
957 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
958 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
962 if (default_action_graphic == -1)
963 default_action_graphic = default_graphic;
965 if (default_action_crumbled == -1)
966 default_action_crumbled = default_action_graphic;
968 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
969 if (default_action_crumbled == -1)
970 default_action_crumbled = default_crumbled;
973 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
975 /* use action graphic as the default direction graphic, if undefined */
976 int default_action_direction_graphic = element_info[i].graphic[act];
977 int default_action_direction_crumbled = element_info[i].crumbled[act];
979 /* no graphic for current action -- use default direction graphic */
980 if (default_action_direction_graphic == -1)
981 default_action_direction_graphic =
982 (act_remove ? default_remove_graphic :
984 element_info[i].direction_graphic[ACTION_TURNING][dir] :
985 default_action_graphic != default_graphic ?
986 default_action_graphic :
987 default_direction_graphic[dir]);
989 if (element_info[i].direction_graphic[act][dir] == -1)
990 element_info[i].direction_graphic[act][dir] =
991 default_action_direction_graphic;
994 if (default_action_direction_crumbled == -1)
995 default_action_direction_crumbled =
996 element_info[i].direction_graphic[act][dir];
998 if (default_action_direction_crumbled == -1)
999 default_action_direction_crumbled =
1000 (act_remove ? default_remove_graphic :
1002 element_info[i].direction_crumbled[ACTION_TURNING][dir] :
1003 default_action_crumbled != default_crumbled ?
1004 default_action_crumbled :
1005 default_direction_crumbled[dir]);
1008 if (element_info[i].direction_crumbled[act][dir] == -1)
1009 element_info[i].direction_crumbled[act][dir] =
1010 default_action_direction_crumbled;
1013 /* no graphic for this specific action -- use default action graphic */
1014 if (element_info[i].graphic[act] == -1)
1015 element_info[i].graphic[act] =
1016 (act_remove ? default_remove_graphic :
1017 act_turning ? element_info[i].graphic[ACTION_TURNING] :
1018 default_action_graphic);
1020 if (element_info[i].crumbled[act] == -1)
1021 element_info[i].crumbled[act] = element_info[i].graphic[act];
1023 if (element_info[i].crumbled[act] == -1)
1024 element_info[i].crumbled[act] =
1025 (act_remove ? default_remove_graphic :
1026 act_turning ? element_info[i].crumbled[ACTION_TURNING] :
1027 default_action_crumbled);
1032 UPDATE_BUSY_STATE();
1035 /* !!! THIS ALSO CLEARS SPECIAL FLAGS (AND IS NOT NEEDED ANYWAY) !!! */
1036 /* set animation mode to "none" for each graphic with only 1 frame */
1037 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1039 for (act = 0; act < NUM_ACTIONS; act++)
1041 int graphic = element_info[i].graphic[act];
1042 int crumbled = element_info[i].crumbled[act];
1044 if (graphic_info[graphic].anim_frames == 1)
1045 graphic_info[graphic].anim_mode = ANIM_NONE;
1046 if (graphic_info[crumbled].anim_frames == 1)
1047 graphic_info[crumbled].anim_mode = ANIM_NONE;
1049 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1051 graphic = element_info[i].direction_graphic[act][dir];
1052 crumbled = element_info[i].direction_crumbled[act][dir];
1054 if (graphic_info[graphic].anim_frames == 1)
1055 graphic_info[graphic].anim_mode = ANIM_NONE;
1056 if (graphic_info[crumbled].anim_frames == 1)
1057 graphic_info[crumbled].anim_mode = ANIM_NONE;
1065 if (options.verbose)
1067 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1068 if (element_info[i].graphic[ACTION_DEFAULT] == IMG_UNKNOWN &&
1070 Error(ERR_INFO, "warning: no graphic for element '%s' (%d)",
1071 element_info[i].token_name, i);
1077 void InitElementSpecialGraphicInfo()
1079 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
1080 int num_property_mappings = getImageListPropertyMappingSize();
1083 /* always start with reliable default values */
1084 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1085 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1086 element_info[i].special_graphic[j] =
1087 element_info[i].graphic[ACTION_DEFAULT];
1089 /* initialize special element/graphic mapping from static configuration */
1090 for (i = 0; element_to_special_graphic[i].element > -1; i++)
1092 int element = element_to_special_graphic[i].element;
1093 int special = element_to_special_graphic[i].special;
1094 int graphic = element_to_special_graphic[i].graphic;
1095 int base_graphic = el2baseimg(element);
1096 boolean base_redefined =
1097 getImageListEntryFromImageID(base_graphic)->redefined;
1098 boolean special_redefined =
1099 getImageListEntryFromImageID(graphic)->redefined;
1102 if ((element == EL_EM_DYNAMITE ||
1103 element == EL_EM_DYNAMITE_ACTIVE) &&
1104 (special == GFX_SPECIAL_ARG_EDITOR ||
1105 special == GFX_SPECIAL_ARG_PANEL))
1106 printf("::: SPECIAL STATIC: %d, %d -> %d\n",
1107 element, special, graphic);
1110 /* if the base graphic ("emerald", for example) has been redefined,
1111 but not the special graphic ("emerald.EDITOR", for example), do not
1112 use an existing (in this case considered obsolete) special graphic
1113 anymore, but use the automatically created (down-scaled) graphic */
1114 if (base_redefined && !special_redefined)
1117 element_info[element].special_graphic[special] = graphic;
1120 /* initialize special element/graphic mapping from dynamic configuration */
1121 for (i = 0; i < num_property_mappings; i++)
1123 int element = property_mapping[i].base_index;
1124 int action = property_mapping[i].ext1_index;
1125 int direction = property_mapping[i].ext2_index;
1126 int special = property_mapping[i].ext3_index;
1127 int graphic = property_mapping[i].artwork_index;
1130 if ((element == EL_EM_DYNAMITE ||
1131 element == EL_EM_DYNAMITE_ACTIVE ||
1132 element == EL_CONVEYOR_BELT_1_MIDDLE ||
1133 element == EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE) &&
1134 (special == GFX_SPECIAL_ARG_EDITOR ||
1135 special == GFX_SPECIAL_ARG_PANEL))
1136 printf("::: SPECIAL DYNAMIC: %d, %d -> %d [%d]\n",
1137 element, special, graphic, property_mapping[i].ext1_index);
1141 if (element == EL_CONVEYOR_BELT_1_MIDDLE &&
1142 action == ACTION_ACTIVE)
1144 element = EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE;
1150 if (element == EL_MAGIC_WALL &&
1151 action == ACTION_ACTIVE)
1153 element = EL_MAGIC_WALL_ACTIVE;
1159 /* for action ".active", replace element with active element, if exists */
1160 if (action == ACTION_ACTIVE && element != ELEMENT_ACTIVE(element))
1162 element = ELEMENT_ACTIVE(element);
1167 if (element >= MAX_NUM_ELEMENTS)
1170 /* do not change special graphic if action or direction was specified */
1171 if (action != -1 || direction != -1)
1174 if (IS_SPECIAL_GFX_ARG(special))
1175 element_info[element].special_graphic[special] = graphic;
1178 /* now set all undefined/invalid graphics to default */
1179 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1180 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1181 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
1182 element_info[i].special_graphic[j] =
1183 element_info[i].graphic[ACTION_DEFAULT];
1186 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
1188 if (type != TYPE_ELEMENT && type != TYPE_GRAPHIC)
1189 return get_parameter_value(value_raw, suffix, type);
1191 if (strEqual(value_raw, ARG_UNDEFINED))
1192 return ARG_UNDEFINED_VALUE;
1195 if (type == TYPE_ELEMENT)
1197 char *value = getHashEntry(element_token_hash, value_raw);
1199 return (value != NULL ? atoi(value) : EL_UNDEFINED);
1201 else if (type == TYPE_GRAPHIC)
1203 char *value = getHashEntry(graphic_token_hash, value_raw);
1205 return (value != NULL ? atoi(value) : IMG_UNDEFINED);
1213 /* !!! THIS IS BUGGY !!! NOT SURE IF YOU GET ELEMENT ID OR GRAPHIC ID !!! */
1214 /* !!! (possible reason why ".clone_from" with elements doesn't work) !!! */
1216 /* !!! OPTIMIZE THIS BY USING HASH !!! */
1217 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1218 if (strEqual(element_info[i].token_name, value_raw))
1221 /* !!! OPTIMIZE THIS BY USING HASH !!! */
1222 for (i = 0; image_config[i].token != NULL; i++)
1224 int len_config_value = strlen(image_config[i].value);
1226 if (!strEqual(&image_config[i].value[len_config_value - 4], ".pcx") &&
1227 !strEqual(&image_config[i].value[len_config_value - 4], ".wav") &&
1228 !strEqual(image_config[i].value, UNDEFINED_FILENAME))
1231 if (strEqual(image_config[i].token, value_raw))
1241 static int get_scaled_graphic_width(int graphic)
1243 int original_width = getOriginalImageWidthFromImageID(graphic);
1244 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1246 return original_width * scale_up_factor;
1249 static int get_scaled_graphic_height(int graphic)
1251 int original_height = getOriginalImageHeightFromImageID(graphic);
1252 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1254 return original_height * scale_up_factor;
1257 static void set_graphic_parameters_ext(int graphic, int *parameter,
1260 struct GraphicInfo *g = &graphic_info[graphic];
1261 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1262 int anim_frames_per_line = 1;
1264 /* always start with reliable default values */
1265 g->src_image_width = 0;
1266 g->src_image_height = 0;
1269 g->width = TILEX; /* default for element graphics */
1270 g->height = TILEY; /* default for element graphics */
1271 g->offset_x = 0; /* one or both of these values ... */
1272 g->offset_y = 0; /* ... will be corrected later */
1273 g->offset2_x = 0; /* one or both of these values ... */
1274 g->offset2_y = 0; /* ... will be corrected later */
1275 g->swap_double_tiles = -1; /* auto-detect tile swapping */
1276 g->crumbled_like = -1; /* do not use clone element */
1277 g->diggable_like = -1; /* do not use clone element */
1278 g->border_size = TILEX / 8; /* "CRUMBLED" border size */
1279 g->scale_up_factor = 1; /* default: no scaling up */
1280 g->clone_from = -1; /* do not use clone graphic */
1281 g->anim_delay_fixed = 0;
1282 g->anim_delay_random = 0;
1283 g->post_delay_fixed = 0;
1284 g->post_delay_random = 0;
1285 g->fade_mode = FADE_MODE_DEFAULT;
1289 g->align = ALIGN_CENTER; /* default for title screens */
1290 g->valign = VALIGN_MIDDLE; /* default for title screens */
1291 g->sort_priority = 0; /* default for title screens */
1293 g->bitmap = src_bitmap;
1296 /* optional zoom factor for scaling up the image to a larger size */
1297 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1298 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1299 if (g->scale_up_factor < 1)
1300 g->scale_up_factor = 1; /* no scaling */
1304 if (g->use_image_size)
1306 /* set new default bitmap size (with scaling, but without small images) */
1307 g->width = get_scaled_graphic_width(graphic);
1308 g->height = get_scaled_graphic_height(graphic);
1312 /* optional x and y tile position of animation frame sequence */
1313 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1314 g->src_x = parameter[GFX_ARG_XPOS] * TILEX;
1315 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1316 g->src_y = parameter[GFX_ARG_YPOS] * TILEY;
1318 /* optional x and y pixel position of animation frame sequence */
1319 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1320 g->src_x = parameter[GFX_ARG_X];
1321 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1322 g->src_y = parameter[GFX_ARG_Y];
1324 /* optional width and height of each animation frame */
1325 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1326 g->width = parameter[GFX_ARG_WIDTH];
1327 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1328 g->height = parameter[GFX_ARG_HEIGHT];
1331 /* optional zoom factor for scaling up the image to a larger size */
1332 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1333 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1334 if (g->scale_up_factor < 1)
1335 g->scale_up_factor = 1; /* no scaling */
1340 /* get final bitmap size (with scaling, but without small images) */
1341 int src_image_width = get_scaled_graphic_width(graphic);
1342 int src_image_height = get_scaled_graphic_height(graphic);
1344 if (src_image_width == 0 || src_image_height == 0)
1346 /* only happens when loaded outside artwork system (like "global.busy") */
1347 src_image_width = src_bitmap->width;
1348 src_image_height = src_bitmap->height;
1351 anim_frames_per_row = src_image_width / g->width;
1352 anim_frames_per_col = src_image_height / g->height;
1354 g->src_image_width = src_image_width;
1355 g->src_image_height = src_image_height;
1358 /* correct x or y offset dependent of vertical or horizontal frame order */
1359 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1361 g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1362 parameter[GFX_ARG_OFFSET] : g->height);
1363 anim_frames_per_line = anim_frames_per_col;
1365 else /* frames are ordered horizontally */
1367 g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1368 parameter[GFX_ARG_OFFSET] : g->width);
1369 anim_frames_per_line = anim_frames_per_row;
1372 /* optionally, the x and y offset of frames can be specified directly */
1373 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1374 g->offset_x = parameter[GFX_ARG_XOFFSET];
1375 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1376 g->offset_y = parameter[GFX_ARG_YOFFSET];
1378 /* optionally, moving animations may have separate start and end graphics */
1379 g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1381 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1382 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1384 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1385 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1386 g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1387 parameter[GFX_ARG_2ND_OFFSET] : g->height);
1388 else /* frames are ordered horizontally */
1389 g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1390 parameter[GFX_ARG_2ND_OFFSET] : g->width);
1392 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1393 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1394 g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1395 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1396 g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1398 /* optionally, the second movement tile can be specified as start tile */
1399 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1400 g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1402 /* automatically determine correct number of frames, if not defined */
1403 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1404 g->anim_frames = parameter[GFX_ARG_FRAMES];
1405 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1406 g->anim_frames = anim_frames_per_row;
1407 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1408 g->anim_frames = anim_frames_per_col;
1412 if (g->anim_frames == 0) /* frames must be at least 1 */
1415 g->anim_frames_per_line =
1416 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1417 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1419 g->anim_delay = parameter[GFX_ARG_DELAY];
1420 if (g->anim_delay == 0) /* delay must be at least 1 */
1423 g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1425 if (g->anim_frames == 1)
1426 g->anim_mode = ANIM_NONE;
1429 /* automatically determine correct start frame, if not defined */
1430 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1431 g->anim_start_frame = 0;
1432 else if (g->anim_mode & ANIM_REVERSE)
1433 g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1435 g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1437 /* animation synchronized with global frame counter, not move position */
1438 g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1440 /* optional element for cloning crumble graphics */
1441 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1442 g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1444 /* optional element for cloning digging graphics */
1445 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1446 g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1448 /* optional border size for "crumbling" diggable graphics */
1449 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1450 g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1452 /* this is only used for player "boring" and "sleeping" actions */
1453 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1454 g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1455 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1456 g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1457 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1458 g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1459 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1460 g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1462 /* this is only used for toon animations */
1463 g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1464 g->step_delay = parameter[GFX_ARG_STEP_DELAY];
1466 /* this is only used for drawing font characters */
1467 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1468 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1470 /* this is only used for drawing envelope graphics */
1471 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1473 /* optional graphic for cloning all graphics settings */
1474 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1475 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1477 /* optional settings for drawing title screens and title messages */
1478 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1479 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1480 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1481 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1482 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1483 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1484 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1485 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1486 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1487 g->align = parameter[GFX_ARG_ALIGN];
1488 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1489 g->valign = parameter[GFX_ARG_VALIGN];
1490 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1491 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1494 static void set_graphic_parameters(int graphic)
1497 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1498 char **parameter_raw = image->parameter;
1499 Bitmap *src_bitmap = getBitmapFromImageID(graphic);
1500 int parameter[NUM_GFX_ARGS];
1503 /* if fallback to default artwork is done, also use the default parameters */
1504 if (image->fallback_to_default)
1505 parameter_raw = image->default_parameter;
1507 /* get integer values from string parameters */
1508 for (i = 0; i < NUM_GFX_ARGS; i++)
1509 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1510 image_config_suffix[i].token,
1511 image_config_suffix[i].type);
1513 set_graphic_parameters_ext(graphic, parameter, src_bitmap);
1517 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1518 char **parameter_raw = image->parameter;
1519 Bitmap *src_bitmap = getBitmapFromImageID(graphic);
1520 int parameter[NUM_GFX_ARGS];
1521 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1522 int anim_frames_per_line = 1;
1525 /* if fallback to default artwork is done, also use the default parameters */
1526 if (image->fallback_to_default)
1527 parameter_raw = image->default_parameter;
1529 /* get integer values from string parameters */
1530 for (i = 0; i < NUM_GFX_ARGS; i++)
1531 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1532 image_config_suffix[i].token,
1533 image_config_suffix[i].type);
1535 graphic_info[graphic].bitmap = src_bitmap;
1537 /* always start with reliable default values */
1538 graphic_info[graphic].src_image_width = 0;
1539 graphic_info[graphic].src_image_height = 0;
1540 graphic_info[graphic].src_x = 0;
1541 graphic_info[graphic].src_y = 0;
1542 graphic_info[graphic].width = TILEX; /* default for element graphics */
1543 graphic_info[graphic].height = TILEY; /* default for element graphics */
1544 graphic_info[graphic].offset_x = 0; /* one or both of these values ... */
1545 graphic_info[graphic].offset_y = 0; /* ... will be corrected later */
1546 graphic_info[graphic].offset2_x = 0; /* one or both of these values ... */
1547 graphic_info[graphic].offset2_y = 0; /* ... will be corrected later */
1548 graphic_info[graphic].swap_double_tiles = -1; /* auto-detect tile swapping */
1549 graphic_info[graphic].crumbled_like = -1; /* do not use clone element */
1550 graphic_info[graphic].diggable_like = -1; /* do not use clone element */
1551 graphic_info[graphic].border_size = TILEX / 8; /* "CRUMBLED" border size */
1552 graphic_info[graphic].scale_up_factor = 1; /* default: no scaling up */
1553 graphic_info[graphic].clone_from = -1; /* do not use clone graphic */
1554 graphic_info[graphic].anim_delay_fixed = 0;
1555 graphic_info[graphic].anim_delay_random = 0;
1556 graphic_info[graphic].post_delay_fixed = 0;
1557 graphic_info[graphic].post_delay_random = 0;
1558 graphic_info[graphic].fade_mode = FADE_MODE_DEFAULT;
1559 graphic_info[graphic].fade_delay = -1;
1560 graphic_info[graphic].post_delay = -1;
1561 graphic_info[graphic].auto_delay = -1;
1562 graphic_info[graphic].align = ALIGN_CENTER; /* default for title screens */
1563 graphic_info[graphic].valign = VALIGN_MIDDLE; /* default for title screens */
1564 graphic_info[graphic].sort_priority = 0; /* default for title screens */
1567 /* optional zoom factor for scaling up the image to a larger size */
1568 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1569 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1570 if (graphic_info[graphic].scale_up_factor < 1)
1571 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
1575 if (graphic_info[graphic].use_image_size)
1577 /* set new default bitmap size (with scaling, but without small images) */
1578 graphic_info[graphic].width = get_scaled_graphic_width(graphic);
1579 graphic_info[graphic].height = get_scaled_graphic_height(graphic);
1583 /* optional x and y tile position of animation frame sequence */
1584 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1585 graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
1586 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1587 graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
1589 /* optional x and y pixel position of animation frame sequence */
1590 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1591 graphic_info[graphic].src_x = parameter[GFX_ARG_X];
1592 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1593 graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
1595 /* optional width and height of each animation frame */
1596 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1597 graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
1598 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1599 graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
1602 /* optional zoom factor for scaling up the image to a larger size */
1603 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1604 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1605 if (graphic_info[graphic].scale_up_factor < 1)
1606 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
1611 /* get final bitmap size (with scaling, but without small images) */
1612 int src_image_width = get_scaled_graphic_width(graphic);
1613 int src_image_height = get_scaled_graphic_height(graphic);
1615 anim_frames_per_row = src_image_width / graphic_info[graphic].width;
1616 anim_frames_per_col = src_image_height / graphic_info[graphic].height;
1618 graphic_info[graphic].src_image_width = src_image_width;
1619 graphic_info[graphic].src_image_height = src_image_height;
1622 /* correct x or y offset dependent of vertical or horizontal frame order */
1623 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1625 graphic_info[graphic].offset_y =
1626 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1627 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
1628 anim_frames_per_line = anim_frames_per_col;
1630 else /* frames are ordered horizontally */
1632 graphic_info[graphic].offset_x =
1633 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1634 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
1635 anim_frames_per_line = anim_frames_per_row;
1638 /* optionally, the x and y offset of frames can be specified directly */
1639 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1640 graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
1641 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1642 graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
1644 /* optionally, moving animations may have separate start and end graphics */
1645 graphic_info[graphic].double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1647 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1648 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1650 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1651 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1652 graphic_info[graphic].offset2_y =
1653 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1654 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].height);
1655 else /* frames are ordered horizontally */
1656 graphic_info[graphic].offset2_x =
1657 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1658 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].width);
1660 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1661 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1662 graphic_info[graphic].offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1663 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1664 graphic_info[graphic].offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1666 /* optionally, the second movement tile can be specified as start tile */
1667 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1668 graphic_info[graphic].swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1670 /* automatically determine correct number of frames, if not defined */
1671 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1672 graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
1673 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1674 graphic_info[graphic].anim_frames = anim_frames_per_row;
1675 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1676 graphic_info[graphic].anim_frames = anim_frames_per_col;
1678 graphic_info[graphic].anim_frames = 1;
1680 if (graphic_info[graphic].anim_frames == 0) /* frames must be at least 1 */
1681 graphic_info[graphic].anim_frames = 1;
1683 graphic_info[graphic].anim_frames_per_line =
1684 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1685 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1687 graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
1688 if (graphic_info[graphic].anim_delay == 0) /* delay must be at least 1 */
1689 graphic_info[graphic].anim_delay = 1;
1691 graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
1693 if (graphic_info[graphic].anim_frames == 1)
1694 graphic_info[graphic].anim_mode = ANIM_NONE;
1697 /* automatically determine correct start frame, if not defined */
1698 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1699 graphic_info[graphic].anim_start_frame = 0;
1700 else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
1701 graphic_info[graphic].anim_start_frame =
1702 graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1704 graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
1706 /* animation synchronized with global frame counter, not move position */
1707 graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1709 /* optional element for cloning crumble graphics */
1710 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1711 graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1713 /* optional element for cloning digging graphics */
1714 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1715 graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1717 /* optional border size for "crumbling" diggable graphics */
1718 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1719 graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
1721 /* this is only used for player "boring" and "sleeping" actions */
1722 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1723 graphic_info[graphic].anim_delay_fixed =
1724 parameter[GFX_ARG_ANIM_DELAY_FIXED];
1725 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1726 graphic_info[graphic].anim_delay_random =
1727 parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1728 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1729 graphic_info[graphic].post_delay_fixed =
1730 parameter[GFX_ARG_POST_DELAY_FIXED];
1731 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1732 graphic_info[graphic].post_delay_random =
1733 parameter[GFX_ARG_POST_DELAY_RANDOM];
1735 /* this is only used for toon animations */
1736 graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
1737 graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY];
1739 /* this is only used for drawing font characters */
1740 graphic_info[graphic].draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1741 graphic_info[graphic].draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1743 /* this is only used for drawing envelope graphics */
1744 graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1746 /* optional graphic for cloning all graphics settings */
1747 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1748 graphic_info[graphic].clone_from = parameter[GFX_ARG_CLONE_FROM];
1750 /* optional settings for drawing title screens and title messages */
1751 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1752 graphic_info[graphic].fade_mode = parameter[GFX_ARG_FADE_MODE];
1753 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1754 graphic_info[graphic].fade_delay = parameter[GFX_ARG_FADE_DELAY];
1755 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1756 graphic_info[graphic].post_delay = parameter[GFX_ARG_POST_DELAY];
1757 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1758 graphic_info[graphic].auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1759 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1760 graphic_info[graphic].align = parameter[GFX_ARG_ALIGN];
1761 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1762 graphic_info[graphic].valign = parameter[GFX_ARG_VALIGN];
1763 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1764 graphic_info[graphic].sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1767 UPDATE_BUSY_STATE();
1770 static void set_cloned_graphic_parameters(int graphic)
1772 int fallback_graphic = IMG_CHAR_EXCLAM;
1773 int max_num_images = getImageListSize();
1774 int clone_graphic = graphic_info[graphic].clone_from;
1775 int num_references_followed = 1;
1777 while (graphic_info[clone_graphic].clone_from != -1 &&
1778 num_references_followed < max_num_images)
1780 clone_graphic = graphic_info[clone_graphic].clone_from;
1782 num_references_followed++;
1785 if (num_references_followed >= max_num_images)
1787 Error(ERR_INFO_LINE, "-");
1788 Error(ERR_INFO, "warning: error found in config file:");
1789 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1790 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1791 Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1792 Error(ERR_INFO, "custom graphic rejected for this element/action");
1794 if (graphic == fallback_graphic)
1795 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1797 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1798 Error(ERR_INFO_LINE, "-");
1800 graphic_info[graphic] = graphic_info[fallback_graphic];
1804 graphic_info[graphic] = graphic_info[clone_graphic];
1805 graphic_info[graphic].clone_from = clone_graphic;
1809 static void InitGraphicInfo()
1811 int fallback_graphic = IMG_CHAR_EXCLAM;
1812 int num_images = getImageListSize();
1815 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1816 static boolean clipmasks_initialized = FALSE;
1818 XGCValues clip_gc_values;
1819 unsigned long clip_gc_valuemask;
1820 GC copy_clipmask_gc = None;
1823 /* use image size as default values for width and height for these images */
1824 static int full_size_graphics[] =
1829 IMG_BACKGROUND_ENVELOPE_1,
1830 IMG_BACKGROUND_ENVELOPE_2,
1831 IMG_BACKGROUND_ENVELOPE_3,
1832 IMG_BACKGROUND_ENVELOPE_4,
1835 IMG_BACKGROUND_TITLE_INITIAL,
1836 IMG_BACKGROUND_TITLE,
1837 IMG_BACKGROUND_MAIN,
1838 IMG_BACKGROUND_LEVELS,
1839 IMG_BACKGROUND_SCORES,
1840 IMG_BACKGROUND_EDITOR,
1841 IMG_BACKGROUND_INFO,
1842 IMG_BACKGROUND_INFO_ELEMENTS,
1843 IMG_BACKGROUND_INFO_MUSIC,
1844 IMG_BACKGROUND_INFO_CREDITS,
1845 IMG_BACKGROUND_INFO_PROGRAM,
1846 IMG_BACKGROUND_INFO_LEVELSET,
1847 IMG_BACKGROUND_SETUP,
1848 IMG_BACKGROUND_DOOR,
1850 IMG_TITLESCREEN_INITIAL_1,
1851 IMG_TITLESCREEN_INITIAL_2,
1852 IMG_TITLESCREEN_INITIAL_3,
1853 IMG_TITLESCREEN_INITIAL_4,
1854 IMG_TITLESCREEN_INITIAL_5,
1864 checked_free(graphic_info);
1866 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1869 /* initialize "use_image_size" flag with default value */
1870 for (i = 0; i < num_images; i++)
1871 graphic_info[i].use_image_size = FALSE;
1873 /* initialize "use_image_size" flag from static configuration above */
1874 for (i = 0; full_size_graphics[i] != -1; i++)
1875 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1878 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1879 if (clipmasks_initialized)
1881 for (i = 0; i < num_images; i++)
1883 if (graphic_info[i].clip_mask)
1884 XFreePixmap(display, graphic_info[i].clip_mask);
1885 if (graphic_info[i].clip_gc)
1886 XFreeGC(display, graphic_info[i].clip_gc);
1888 graphic_info[i].clip_mask = None;
1889 graphic_info[i].clip_gc = None;
1894 /* first set all graphic paramaters ... */
1895 for (i = 0; i < num_images; i++)
1896 set_graphic_parameters(i);
1898 /* ... then copy these parameters for cloned graphics */
1899 for (i = 0; i < num_images; i++)
1900 if (graphic_info[i].clone_from != -1)
1901 set_cloned_graphic_parameters(i);
1903 for (i = 0; i < num_images; i++)
1908 int first_frame, last_frame;
1909 int src_bitmap_width, src_bitmap_height;
1911 /* now check if no animation frames are outside of the loaded image */
1913 if (graphic_info[i].bitmap == NULL)
1914 continue; /* skip check for optional images that are undefined */
1916 /* get image size (this can differ from the standard element tile size!) */
1917 width = graphic_info[i].width;
1918 height = graphic_info[i].height;
1920 /* get final bitmap size (with scaling, but without small images) */
1921 src_bitmap_width = graphic_info[i].src_image_width;
1922 src_bitmap_height = graphic_info[i].src_image_height;
1924 /* check if first animation frame is inside specified bitmap */
1927 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1930 /* this avoids calculating wrong start position for out-of-bounds frame */
1931 src_x = graphic_info[i].src_x;
1932 src_y = graphic_info[i].src_y;
1935 if (src_x < 0 || src_y < 0 ||
1936 src_x + width > src_bitmap_width ||
1937 src_y + height > src_bitmap_height)
1939 Error(ERR_INFO_LINE, "-");
1940 Error(ERR_INFO, "warning: error found in config file:");
1941 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1942 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1943 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1945 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1946 src_x, src_y, src_bitmap_width, src_bitmap_height);
1947 Error(ERR_INFO, "custom graphic rejected for this element/action");
1949 if (i == fallback_graphic)
1950 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1952 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1953 Error(ERR_INFO_LINE, "-");
1955 graphic_info[i] = graphic_info[fallback_graphic];
1958 /* check if last animation frame is inside specified bitmap */
1960 last_frame = graphic_info[i].anim_frames - 1;
1961 getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1963 if (src_x < 0 || src_y < 0 ||
1964 src_x + width > src_bitmap_width ||
1965 src_y + height > src_bitmap_height)
1967 Error(ERR_INFO_LINE, "-");
1968 Error(ERR_INFO, "warning: error found in config file:");
1969 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1970 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1971 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1973 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1974 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1975 Error(ERR_INFO, "custom graphic rejected for this element/action");
1977 if (i == fallback_graphic)
1978 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1980 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1981 Error(ERR_INFO_LINE, "-");
1983 graphic_info[i] = graphic_info[fallback_graphic];
1986 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1987 /* currently we only need a tile clip mask from the first frame */
1988 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1990 if (copy_clipmask_gc == None)
1992 clip_gc_values.graphics_exposures = False;
1993 clip_gc_valuemask = GCGraphicsExposures;
1994 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
1995 clip_gc_valuemask, &clip_gc_values);
1998 graphic_info[i].clip_mask =
1999 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
2001 src_pixmap = src_bitmap->clip_mask;
2002 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
2003 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
2005 clip_gc_values.graphics_exposures = False;
2006 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
2007 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
2009 graphic_info[i].clip_gc =
2010 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
2014 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
2015 if (copy_clipmask_gc)
2016 XFreeGC(display, copy_clipmask_gc);
2018 clipmasks_initialized = TRUE;
2022 static void InitElementSoundInfo()
2024 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
2025 int num_property_mappings = getSoundListPropertyMappingSize();
2028 /* set values to -1 to identify later as "uninitialized" values */
2029 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2030 for (act = 0; act < NUM_ACTIONS; act++)
2031 element_info[i].sound[act] = -1;
2033 /* initialize element/sound mapping from static configuration */
2034 for (i = 0; element_to_sound[i].element > -1; i++)
2036 int element = element_to_sound[i].element;
2037 int action = element_to_sound[i].action;
2038 int sound = element_to_sound[i].sound;
2039 boolean is_class = element_to_sound[i].is_class;
2042 action = ACTION_DEFAULT;
2045 element_info[element].sound[action] = sound;
2047 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2048 if (strEqual(element_info[j].class_name,
2049 element_info[element].class_name))
2050 element_info[j].sound[action] = sound;
2053 /* initialize element class/sound mapping from dynamic configuration */
2054 for (i = 0; i < num_property_mappings; i++)
2056 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
2057 int action = property_mapping[i].ext1_index;
2058 int sound = property_mapping[i].artwork_index;
2060 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
2064 action = ACTION_DEFAULT;
2066 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2067 if (strEqual(element_info[j].class_name,
2068 element_info[element_class].class_name))
2069 element_info[j].sound[action] = sound;
2072 /* initialize element/sound mapping from dynamic configuration */
2073 for (i = 0; i < num_property_mappings; i++)
2075 int element = property_mapping[i].base_index;
2076 int action = property_mapping[i].ext1_index;
2077 int sound = property_mapping[i].artwork_index;
2079 if (element >= MAX_NUM_ELEMENTS)
2083 action = ACTION_DEFAULT;
2085 element_info[element].sound[action] = sound;
2088 /* now set all '-1' values to element specific default values */
2089 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2091 for (act = 0; act < NUM_ACTIONS; act++)
2093 /* generic default action sound (defined by "[default]" directive) */
2094 int default_action_sound = element_info[EL_DEFAULT].sound[act];
2096 /* look for special default action sound (classic game specific) */
2097 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
2098 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
2099 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
2100 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
2101 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
2102 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
2104 /* !!! there's no such thing as a "default action sound" !!! */
2106 /* look for element specific default sound (independent from action) */
2107 if (element_info[i].sound[ACTION_DEFAULT] != -1)
2108 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
2112 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
2113 /* !!! make this better !!! */
2114 if (i == EL_EMPTY_SPACE)
2115 default_action_sound = element_info[EL_DEFAULT].sound[act];
2118 /* no sound for this specific action -- use default action sound */
2119 if (element_info[i].sound[act] == -1)
2120 element_info[i].sound[act] = default_action_sound;
2124 /* copy sound settings to some elements that are only stored in level file
2125 in native R'n'D levels, but are used by game engine in native EM levels */
2126 for (i = 0; copy_properties[i][0] != -1; i++)
2127 for (j = 1; j <= 4; j++)
2128 for (act = 0; act < NUM_ACTIONS; act++)
2129 element_info[copy_properties[i][j]].sound[act] =
2130 element_info[copy_properties[i][0]].sound[act];
2133 static void InitGameModeSoundInfo()
2137 /* set values to -1 to identify later as "uninitialized" values */
2138 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2141 /* initialize gamemode/sound mapping from static configuration */
2142 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
2144 int gamemode = gamemode_to_sound[i].gamemode;
2145 int sound = gamemode_to_sound[i].sound;
2148 gamemode = GAME_MODE_DEFAULT;
2150 menu.sound[gamemode] = sound;
2153 /* now set all '-1' values to levelset specific default values */
2154 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2155 if (menu.sound[i] == -1)
2156 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
2159 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2160 if (menu.sound[i] != -1)
2161 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
2165 static void set_sound_parameters(int sound, char **parameter_raw)
2167 int parameter[NUM_SND_ARGS];
2170 /* get integer values from string parameters */
2171 for (i = 0; i < NUM_SND_ARGS; i++)
2173 get_parameter_value(parameter_raw[i],
2174 sound_config_suffix[i].token,
2175 sound_config_suffix[i].type);
2177 /* explicit loop mode setting in configuration overrides default value */
2178 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2179 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
2181 /* sound volume to change the original volume when loading the sound file */
2182 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
2184 /* sound priority to give certain sounds a higher or lower priority */
2185 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
2188 static void InitSoundInfo()
2190 int *sound_effect_properties;
2191 int num_sounds = getSoundListSize();
2194 checked_free(sound_info);
2196 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
2197 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
2199 /* initialize sound effect for all elements to "no sound" */
2200 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2201 for (j = 0; j < NUM_ACTIONS; j++)
2202 element_info[i].sound[j] = SND_UNDEFINED;
2204 for (i = 0; i < num_sounds; i++)
2206 struct FileInfo *sound = getSoundListEntry(i);
2207 int len_effect_text = strlen(sound->token);
2209 sound_effect_properties[i] = ACTION_OTHER;
2210 sound_info[i].loop = FALSE; /* default: play sound only once */
2213 printf("::: sound %d: '%s'\n", i, sound->token);
2216 /* determine all loop sounds and identify certain sound classes */
2218 for (j = 0; element_action_info[j].suffix; j++)
2220 int len_action_text = strlen(element_action_info[j].suffix);
2222 if (len_action_text < len_effect_text &&
2223 strEqual(&sound->token[len_effect_text - len_action_text],
2224 element_action_info[j].suffix))
2226 sound_effect_properties[i] = element_action_info[j].value;
2227 sound_info[i].loop = element_action_info[j].is_loop_sound;
2233 /* associate elements and some selected sound actions */
2235 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2237 if (element_info[j].class_name)
2239 int len_class_text = strlen(element_info[j].class_name);
2241 if (len_class_text + 1 < len_effect_text &&
2242 strncmp(sound->token,
2243 element_info[j].class_name, len_class_text) == 0 &&
2244 sound->token[len_class_text] == '.')
2246 int sound_action_value = sound_effect_properties[i];
2248 element_info[j].sound[sound_action_value] = i;
2253 set_sound_parameters(i, sound->parameter);
2256 free(sound_effect_properties);
2259 static void InitGameModeMusicInfo()
2261 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
2262 int num_property_mappings = getMusicListPropertyMappingSize();
2263 int default_levelset_music = -1;
2266 /* set values to -1 to identify later as "uninitialized" values */
2267 for (i = 0; i < MAX_LEVELS; i++)
2268 levelset.music[i] = -1;
2269 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2272 /* initialize gamemode/music mapping from static configuration */
2273 for (i = 0; gamemode_to_music[i].music > -1; i++)
2275 int gamemode = gamemode_to_music[i].gamemode;
2276 int music = gamemode_to_music[i].music;
2279 printf("::: gamemode == %d, music == %d\n", gamemode, music);
2283 gamemode = GAME_MODE_DEFAULT;
2285 menu.music[gamemode] = music;
2288 /* initialize gamemode/music mapping from dynamic configuration */
2289 for (i = 0; i < num_property_mappings; i++)
2291 int prefix = property_mapping[i].base_index;
2292 int gamemode = property_mapping[i].ext1_index;
2293 int level = property_mapping[i].ext2_index;
2294 int music = property_mapping[i].artwork_index;
2297 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
2298 prefix, gamemode, level, music);
2301 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
2305 gamemode = GAME_MODE_DEFAULT;
2307 /* level specific music only allowed for in-game music */
2308 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
2309 gamemode = GAME_MODE_PLAYING;
2314 default_levelset_music = music;
2317 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
2318 levelset.music[level] = music;
2319 if (gamemode != GAME_MODE_PLAYING)
2320 menu.music[gamemode] = music;
2323 /* now set all '-1' values to menu specific default values */
2324 /* (undefined values of "levelset.music[]" might stay at "-1" to
2325 allow dynamic selection of music files from music directory!) */
2326 for (i = 0; i < MAX_LEVELS; i++)
2327 if (levelset.music[i] == -1)
2328 levelset.music[i] = default_levelset_music;
2329 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2330 if (menu.music[i] == -1)
2331 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
2334 for (i = 0; i < MAX_LEVELS; i++)
2335 if (levelset.music[i] != -1)
2336 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
2337 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2338 if (menu.music[i] != -1)
2339 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
2343 static void set_music_parameters(int music, char **parameter_raw)
2345 int parameter[NUM_MUS_ARGS];
2348 /* get integer values from string parameters */
2349 for (i = 0; i < NUM_MUS_ARGS; i++)
2351 get_parameter_value(parameter_raw[i],
2352 music_config_suffix[i].token,
2353 music_config_suffix[i].type);
2355 /* explicit loop mode setting in configuration overrides default value */
2356 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2357 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
2360 static void InitMusicInfo()
2362 int num_music = getMusicListSize();
2365 checked_free(music_info);
2367 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
2369 for (i = 0; i < num_music; i++)
2371 struct FileInfo *music = getMusicListEntry(i);
2372 int len_music_text = strlen(music->token);
2374 music_info[i].loop = TRUE; /* default: play music in loop mode */
2376 /* determine all loop music */
2378 for (j = 0; music_prefix_info[j].prefix; j++)
2380 int len_prefix_text = strlen(music_prefix_info[j].prefix);
2382 if (len_prefix_text < len_music_text &&
2383 strncmp(music->token,
2384 music_prefix_info[j].prefix, len_prefix_text) == 0)
2386 music_info[i].loop = music_prefix_info[j].is_loop_music;
2392 set_music_parameters(i, music->parameter);
2396 static void ReinitializeGraphics()
2398 print_timestamp_init("ReinitializeGraphics");
2400 InitGraphicInfo(); /* graphic properties mapping */
2401 print_timestamp_time("InitGraphicInfo");
2402 InitElementGraphicInfo(); /* element game graphic mapping */
2403 print_timestamp_time("InitElementGraphicInfo");
2404 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
2405 print_timestamp_time("InitElementSpecialGraphicInfo");
2407 InitElementSmallImages(); /* scale elements to all needed sizes */
2408 print_timestamp_time("InitElementSmallImages");
2409 InitScaledImages(); /* scale all other images, if needed */
2410 print_timestamp_time("InitScaledImages");
2411 InitFontGraphicInfo(); /* initialize text drawing functions */
2412 print_timestamp_time("InitFontGraphicInfo");
2414 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
2415 print_timestamp_time("InitGraphicInfo_EM");
2417 SetMainBackgroundImage(IMG_BACKGROUND);
2418 print_timestamp_time("SetMainBackgroundImage");
2419 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2420 print_timestamp_time("SetDoorBackgroundImage");
2423 print_timestamp_time("InitGadgets");
2425 print_timestamp_time("InitToons");
2427 print_timestamp_done("ReinitializeGraphics");
2430 static void ReinitializeSounds()
2432 InitSoundInfo(); /* sound properties mapping */
2433 InitElementSoundInfo(); /* element game sound mapping */
2434 InitGameModeSoundInfo(); /* game mode sound mapping */
2436 InitPlayLevelSound(); /* internal game sound settings */
2439 static void ReinitializeMusic()
2441 InitMusicInfo(); /* music properties mapping */
2442 InitGameModeMusicInfo(); /* game mode music mapping */
2445 static int get_special_property_bit(int element, int property_bit_nr)
2447 struct PropertyBitInfo
2453 static struct PropertyBitInfo pb_can_move_into_acid[] =
2455 /* the player may be able fall into acid when gravity is activated */
2460 { EL_SP_MURPHY, 0 },
2461 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2463 /* all elements that can move may be able to also move into acid */
2466 { EL_BUG_RIGHT, 1 },
2469 { EL_SPACESHIP, 2 },
2470 { EL_SPACESHIP_LEFT, 2 },
2471 { EL_SPACESHIP_RIGHT, 2 },
2472 { EL_SPACESHIP_UP, 2 },
2473 { EL_SPACESHIP_DOWN, 2 },
2474 { EL_BD_BUTTERFLY, 3 },
2475 { EL_BD_BUTTERFLY_LEFT, 3 },
2476 { EL_BD_BUTTERFLY_RIGHT, 3 },
2477 { EL_BD_BUTTERFLY_UP, 3 },
2478 { EL_BD_BUTTERFLY_DOWN, 3 },
2479 { EL_BD_FIREFLY, 4 },
2480 { EL_BD_FIREFLY_LEFT, 4 },
2481 { EL_BD_FIREFLY_RIGHT, 4 },
2482 { EL_BD_FIREFLY_UP, 4 },
2483 { EL_BD_FIREFLY_DOWN, 4 },
2485 { EL_YAMYAM_LEFT, 5 },
2486 { EL_YAMYAM_RIGHT, 5 },
2487 { EL_YAMYAM_UP, 5 },
2488 { EL_YAMYAM_DOWN, 5 },
2489 { EL_DARK_YAMYAM, 6 },
2492 { EL_PACMAN_LEFT, 8 },
2493 { EL_PACMAN_RIGHT, 8 },
2494 { EL_PACMAN_UP, 8 },
2495 { EL_PACMAN_DOWN, 8 },
2497 { EL_MOLE_LEFT, 9 },
2498 { EL_MOLE_RIGHT, 9 },
2500 { EL_MOLE_DOWN, 9 },
2504 { EL_SATELLITE, 13 },
2505 { EL_SP_SNIKSNAK, 14 },
2506 { EL_SP_ELECTRON, 15 },
2509 { EL_EMC_ANDROID, 18 },
2514 static struct PropertyBitInfo pb_dont_collide_with[] =
2516 { EL_SP_SNIKSNAK, 0 },
2517 { EL_SP_ELECTRON, 1 },
2525 struct PropertyBitInfo *pb_info;
2528 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2529 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2534 struct PropertyBitInfo *pb_info = NULL;
2537 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2538 if (pb_definition[i].bit_nr == property_bit_nr)
2539 pb_info = pb_definition[i].pb_info;
2541 if (pb_info == NULL)
2544 for (i = 0; pb_info[i].element != -1; i++)
2545 if (pb_info[i].element == element)
2546 return pb_info[i].bit_nr;
2551 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2552 boolean property_value)
2554 int bit_nr = get_special_property_bit(element, property_bit_nr);
2559 *bitfield |= (1 << bit_nr);
2561 *bitfield &= ~(1 << bit_nr);
2565 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2567 int bit_nr = get_special_property_bit(element, property_bit_nr);
2570 return ((*bitfield & (1 << bit_nr)) != 0);
2575 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2577 static int group_nr;
2578 static struct ElementGroupInfo *group;
2579 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2582 if (actual_group == NULL) /* not yet initialized */
2585 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
2587 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2588 group_element - EL_GROUP_START + 1);
2590 /* replace element which caused too deep recursion by question mark */
2591 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2596 if (recursion_depth == 0) /* initialization */
2598 group = actual_group;
2599 group_nr = GROUP_NR(group_element);
2601 group->num_elements_resolved = 0;
2602 group->choice_pos = 0;
2604 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2605 element_info[i].in_group[group_nr] = FALSE;
2608 for (i = 0; i < actual_group->num_elements; i++)
2610 int element = actual_group->element[i];
2612 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2615 if (IS_GROUP_ELEMENT(element))
2616 ResolveGroupElementExt(element, recursion_depth + 1);
2619 group->element_resolved[group->num_elements_resolved++] = element;
2620 element_info[element].in_group[group_nr] = TRUE;
2625 void ResolveGroupElement(int group_element)
2627 ResolveGroupElementExt(group_element, 0);
2630 void InitElementPropertiesStatic()
2632 static boolean clipboard_elements_initialized = FALSE;
2634 static int ep_diggable[] =
2639 EL_SP_BUGGY_BASE_ACTIVATING,
2642 EL_INVISIBLE_SAND_ACTIVE,
2645 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2646 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2651 EL_SP_BUGGY_BASE_ACTIVE,
2658 static int ep_collectible_only[] =
2680 EL_DYNABOMB_INCREASE_NUMBER,
2681 EL_DYNABOMB_INCREASE_SIZE,
2682 EL_DYNABOMB_INCREASE_POWER,
2700 /* !!! handle separately !!! */
2701 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2707 static int ep_dont_run_into[] =
2709 /* same elements as in 'ep_dont_touch' */
2715 /* same elements as in 'ep_dont_collide_with' */
2727 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2732 EL_SP_BUGGY_BASE_ACTIVE,
2739 static int ep_dont_collide_with[] =
2741 /* same elements as in 'ep_dont_touch' */
2758 static int ep_dont_touch[] =
2768 static int ep_indestructible[] =
2772 EL_ACID_POOL_TOPLEFT,
2773 EL_ACID_POOL_TOPRIGHT,
2774 EL_ACID_POOL_BOTTOMLEFT,
2775 EL_ACID_POOL_BOTTOM,
2776 EL_ACID_POOL_BOTTOMRIGHT,
2777 EL_SP_HARDWARE_GRAY,
2778 EL_SP_HARDWARE_GREEN,
2779 EL_SP_HARDWARE_BLUE,
2781 EL_SP_HARDWARE_YELLOW,
2782 EL_SP_HARDWARE_BASE_1,
2783 EL_SP_HARDWARE_BASE_2,
2784 EL_SP_HARDWARE_BASE_3,
2785 EL_SP_HARDWARE_BASE_4,
2786 EL_SP_HARDWARE_BASE_5,
2787 EL_SP_HARDWARE_BASE_6,
2788 EL_INVISIBLE_STEELWALL,
2789 EL_INVISIBLE_STEELWALL_ACTIVE,
2790 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2791 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2792 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2793 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2794 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2795 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2796 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2797 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2798 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2799 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2800 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2801 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2803 EL_LIGHT_SWITCH_ACTIVE,
2804 EL_SIGN_EXCLAMATION,
2805 EL_SIGN_RADIOACTIVITY,
2812 EL_SIGN_ENTRY_FORBIDDEN,
2813 EL_SIGN_EMERGENCY_EXIT,
2821 EL_STEEL_EXIT_CLOSED,
2823 EL_EM_STEEL_EXIT_CLOSED,
2824 EL_EM_STEEL_EXIT_OPEN,
2825 EL_DC_STEELWALL_1_LEFT,
2826 EL_DC_STEELWALL_1_RIGHT,
2827 EL_DC_STEELWALL_1_TOP,
2828 EL_DC_STEELWALL_1_BOTTOM,
2829 EL_DC_STEELWALL_1_HORIZONTAL,
2830 EL_DC_STEELWALL_1_VERTICAL,
2831 EL_DC_STEELWALL_1_TOPLEFT,
2832 EL_DC_STEELWALL_1_TOPRIGHT,
2833 EL_DC_STEELWALL_1_BOTTOMLEFT,
2834 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2835 EL_DC_STEELWALL_1_TOPLEFT_2,
2836 EL_DC_STEELWALL_1_TOPRIGHT_2,
2837 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2838 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2839 EL_DC_STEELWALL_2_LEFT,
2840 EL_DC_STEELWALL_2_RIGHT,
2841 EL_DC_STEELWALL_2_TOP,
2842 EL_DC_STEELWALL_2_BOTTOM,
2843 EL_DC_STEELWALL_2_HORIZONTAL,
2844 EL_DC_STEELWALL_2_VERTICAL,
2845 EL_DC_STEELWALL_2_MIDDLE,
2846 EL_DC_STEELWALL_2_SINGLE,
2847 EL_STEELWALL_SLIPPERY,
2861 EL_GATE_1_GRAY_ACTIVE,
2862 EL_GATE_2_GRAY_ACTIVE,
2863 EL_GATE_3_GRAY_ACTIVE,
2864 EL_GATE_4_GRAY_ACTIVE,
2873 EL_EM_GATE_1_GRAY_ACTIVE,
2874 EL_EM_GATE_2_GRAY_ACTIVE,
2875 EL_EM_GATE_3_GRAY_ACTIVE,
2876 EL_EM_GATE_4_GRAY_ACTIVE,
2885 EL_EMC_GATE_5_GRAY_ACTIVE,
2886 EL_EMC_GATE_6_GRAY_ACTIVE,
2887 EL_EMC_GATE_7_GRAY_ACTIVE,
2888 EL_EMC_GATE_8_GRAY_ACTIVE,
2890 EL_DC_GATE_WHITE_GRAY,
2891 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2892 EL_DC_GATE_FAKE_GRAY,
2894 EL_SWITCHGATE_OPENING,
2895 EL_SWITCHGATE_CLOSED,
2896 EL_SWITCHGATE_CLOSING,
2898 EL_DC_SWITCHGATE_SWITCH_UP,
2899 EL_DC_SWITCHGATE_SWITCH_DOWN,
2902 EL_TIMEGATE_OPENING,
2904 EL_TIMEGATE_CLOSING,
2906 EL_DC_TIMEGATE_SWITCH,
2907 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2912 EL_TUBE_VERTICAL_LEFT,
2913 EL_TUBE_VERTICAL_RIGHT,
2914 EL_TUBE_HORIZONTAL_UP,
2915 EL_TUBE_HORIZONTAL_DOWN,
2920 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2921 EL_EXPANDABLE_STEELWALL_VERTICAL,
2922 EL_EXPANDABLE_STEELWALL_ANY,
2927 static int ep_slippery[] =
2941 EL_ROBOT_WHEEL_ACTIVE,
2947 EL_ACID_POOL_TOPLEFT,
2948 EL_ACID_POOL_TOPRIGHT,
2958 EL_STEELWALL_SLIPPERY,
2961 EL_EMC_WALL_SLIPPERY_1,
2962 EL_EMC_WALL_SLIPPERY_2,
2963 EL_EMC_WALL_SLIPPERY_3,
2964 EL_EMC_WALL_SLIPPERY_4,
2966 EL_EMC_MAGIC_BALL_ACTIVE,
2971 static int ep_can_change[] =
2976 static int ep_can_move[] =
2978 /* same elements as in 'pb_can_move_into_acid' */
3001 static int ep_can_fall[] =
3015 EL_QUICKSAND_FAST_FULL,
3017 EL_BD_MAGIC_WALL_FULL,
3018 EL_DC_MAGIC_WALL_FULL,
3032 static int ep_can_smash_player[] =
3058 static int ep_can_smash_enemies[] =
3067 static int ep_can_smash_everything[] =
3076 static int ep_explodes_by_fire[] =
3078 /* same elements as in 'ep_explodes_impact' */
3083 /* same elements as in 'ep_explodes_smashed' */
3093 EL_EM_DYNAMITE_ACTIVE,
3094 EL_DYNABOMB_PLAYER_1_ACTIVE,
3095 EL_DYNABOMB_PLAYER_2_ACTIVE,
3096 EL_DYNABOMB_PLAYER_3_ACTIVE,
3097 EL_DYNABOMB_PLAYER_4_ACTIVE,
3098 EL_DYNABOMB_INCREASE_NUMBER,
3099 EL_DYNABOMB_INCREASE_SIZE,
3100 EL_DYNABOMB_INCREASE_POWER,
3101 EL_SP_DISK_RED_ACTIVE,
3115 static int ep_explodes_smashed[] =
3117 /* same elements as in 'ep_explodes_impact' */
3131 static int ep_explodes_impact[] =
3140 static int ep_walkable_over[] =
3144 EL_SOKOBAN_FIELD_EMPTY,
3150 EL_EM_STEEL_EXIT_OPEN,
3159 EL_GATE_1_GRAY_ACTIVE,
3160 EL_GATE_2_GRAY_ACTIVE,
3161 EL_GATE_3_GRAY_ACTIVE,
3162 EL_GATE_4_GRAY_ACTIVE,
3170 static int ep_walkable_inside[] =
3175 EL_TUBE_VERTICAL_LEFT,
3176 EL_TUBE_VERTICAL_RIGHT,
3177 EL_TUBE_HORIZONTAL_UP,
3178 EL_TUBE_HORIZONTAL_DOWN,
3187 static int ep_walkable_under[] =
3192 static int ep_passable_over[] =
3202 EL_EM_GATE_1_GRAY_ACTIVE,
3203 EL_EM_GATE_2_GRAY_ACTIVE,
3204 EL_EM_GATE_3_GRAY_ACTIVE,
3205 EL_EM_GATE_4_GRAY_ACTIVE,
3214 EL_EMC_GATE_5_GRAY_ACTIVE,
3215 EL_EMC_GATE_6_GRAY_ACTIVE,
3216 EL_EMC_GATE_7_GRAY_ACTIVE,
3217 EL_EMC_GATE_8_GRAY_ACTIVE,
3219 EL_DC_GATE_WHITE_GRAY,
3220 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3227 static int ep_passable_inside[] =
3233 EL_SP_PORT_HORIZONTAL,
3234 EL_SP_PORT_VERTICAL,
3236 EL_SP_GRAVITY_PORT_LEFT,
3237 EL_SP_GRAVITY_PORT_RIGHT,
3238 EL_SP_GRAVITY_PORT_UP,
3239 EL_SP_GRAVITY_PORT_DOWN,
3240 EL_SP_GRAVITY_ON_PORT_LEFT,
3241 EL_SP_GRAVITY_ON_PORT_RIGHT,
3242 EL_SP_GRAVITY_ON_PORT_UP,
3243 EL_SP_GRAVITY_ON_PORT_DOWN,
3244 EL_SP_GRAVITY_OFF_PORT_LEFT,
3245 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3246 EL_SP_GRAVITY_OFF_PORT_UP,
3247 EL_SP_GRAVITY_OFF_PORT_DOWN,
3252 static int ep_passable_under[] =
3257 static int ep_droppable[] =
3262 static int ep_explodes_1x1_old[] =
3267 static int ep_pushable[] =
3279 EL_SOKOBAN_FIELD_FULL,
3288 static int ep_explodes_cross_old[] =
3293 static int ep_protected[] =
3295 /* same elements as in 'ep_walkable_inside' */
3299 EL_TUBE_VERTICAL_LEFT,
3300 EL_TUBE_VERTICAL_RIGHT,
3301 EL_TUBE_HORIZONTAL_UP,
3302 EL_TUBE_HORIZONTAL_DOWN,
3308 /* same elements as in 'ep_passable_over' */
3317 EL_EM_GATE_1_GRAY_ACTIVE,
3318 EL_EM_GATE_2_GRAY_ACTIVE,
3319 EL_EM_GATE_3_GRAY_ACTIVE,
3320 EL_EM_GATE_4_GRAY_ACTIVE,
3329 EL_EMC_GATE_5_GRAY_ACTIVE,
3330 EL_EMC_GATE_6_GRAY_ACTIVE,
3331 EL_EMC_GATE_7_GRAY_ACTIVE,
3332 EL_EMC_GATE_8_GRAY_ACTIVE,
3334 EL_DC_GATE_WHITE_GRAY,
3335 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3339 /* same elements as in 'ep_passable_inside' */
3344 EL_SP_PORT_HORIZONTAL,
3345 EL_SP_PORT_VERTICAL,
3347 EL_SP_GRAVITY_PORT_LEFT,
3348 EL_SP_GRAVITY_PORT_RIGHT,
3349 EL_SP_GRAVITY_PORT_UP,
3350 EL_SP_GRAVITY_PORT_DOWN,
3351 EL_SP_GRAVITY_ON_PORT_LEFT,
3352 EL_SP_GRAVITY_ON_PORT_RIGHT,
3353 EL_SP_GRAVITY_ON_PORT_UP,
3354 EL_SP_GRAVITY_ON_PORT_DOWN,
3355 EL_SP_GRAVITY_OFF_PORT_LEFT,
3356 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3357 EL_SP_GRAVITY_OFF_PORT_UP,
3358 EL_SP_GRAVITY_OFF_PORT_DOWN,
3363 static int ep_throwable[] =
3368 static int ep_can_explode[] =
3370 /* same elements as in 'ep_explodes_impact' */
3375 /* same elements as in 'ep_explodes_smashed' */
3381 /* elements that can explode by explosion or by dragonfire */
3385 EL_EM_DYNAMITE_ACTIVE,
3386 EL_DYNABOMB_PLAYER_1_ACTIVE,
3387 EL_DYNABOMB_PLAYER_2_ACTIVE,
3388 EL_DYNABOMB_PLAYER_3_ACTIVE,
3389 EL_DYNABOMB_PLAYER_4_ACTIVE,
3390 EL_DYNABOMB_INCREASE_NUMBER,
3391 EL_DYNABOMB_INCREASE_SIZE,
3392 EL_DYNABOMB_INCREASE_POWER,
3393 EL_SP_DISK_RED_ACTIVE,
3401 /* elements that can explode only by explosion */
3407 static int ep_gravity_reachable[] =
3413 EL_INVISIBLE_SAND_ACTIVE,
3418 EL_SP_PORT_HORIZONTAL,
3419 EL_SP_PORT_VERTICAL,
3421 EL_SP_GRAVITY_PORT_LEFT,
3422 EL_SP_GRAVITY_PORT_RIGHT,
3423 EL_SP_GRAVITY_PORT_UP,
3424 EL_SP_GRAVITY_PORT_DOWN,
3425 EL_SP_GRAVITY_ON_PORT_LEFT,
3426 EL_SP_GRAVITY_ON_PORT_RIGHT,
3427 EL_SP_GRAVITY_ON_PORT_UP,
3428 EL_SP_GRAVITY_ON_PORT_DOWN,
3429 EL_SP_GRAVITY_OFF_PORT_LEFT,
3430 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3431 EL_SP_GRAVITY_OFF_PORT_UP,
3432 EL_SP_GRAVITY_OFF_PORT_DOWN,
3438 static int ep_player[] =
3445 EL_SOKOBAN_FIELD_PLAYER,
3451 static int ep_can_pass_magic_wall[] =
3465 static int ep_can_pass_dc_magic_wall[] =
3481 static int ep_switchable[] =
3485 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3486 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3487 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3488 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3489 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3490 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3491 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3492 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3493 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3494 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3495 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3496 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3497 EL_SWITCHGATE_SWITCH_UP,
3498 EL_SWITCHGATE_SWITCH_DOWN,
3499 EL_DC_SWITCHGATE_SWITCH_UP,
3500 EL_DC_SWITCHGATE_SWITCH_DOWN,
3502 EL_LIGHT_SWITCH_ACTIVE,
3504 EL_DC_TIMEGATE_SWITCH,
3505 EL_BALLOON_SWITCH_LEFT,
3506 EL_BALLOON_SWITCH_RIGHT,
3507 EL_BALLOON_SWITCH_UP,
3508 EL_BALLOON_SWITCH_DOWN,
3509 EL_BALLOON_SWITCH_ANY,
3510 EL_BALLOON_SWITCH_NONE,
3513 EL_EMC_MAGIC_BALL_SWITCH,
3514 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3519 static int ep_bd_element[] =
3553 static int ep_sp_element[] =
3555 /* should always be valid */
3558 /* standard classic Supaplex elements */
3565 EL_SP_HARDWARE_GRAY,
3573 EL_SP_GRAVITY_PORT_RIGHT,
3574 EL_SP_GRAVITY_PORT_DOWN,
3575 EL_SP_GRAVITY_PORT_LEFT,
3576 EL_SP_GRAVITY_PORT_UP,
3581 EL_SP_PORT_VERTICAL,
3582 EL_SP_PORT_HORIZONTAL,
3588 EL_SP_HARDWARE_BASE_1,
3589 EL_SP_HARDWARE_GREEN,
3590 EL_SP_HARDWARE_BLUE,
3592 EL_SP_HARDWARE_YELLOW,
3593 EL_SP_HARDWARE_BASE_2,
3594 EL_SP_HARDWARE_BASE_3,
3595 EL_SP_HARDWARE_BASE_4,
3596 EL_SP_HARDWARE_BASE_5,
3597 EL_SP_HARDWARE_BASE_6,
3601 /* additional elements that appeared in newer Supaplex levels */
3604 /* additional gravity port elements (not switching, but setting gravity) */
3605 EL_SP_GRAVITY_ON_PORT_LEFT,
3606 EL_SP_GRAVITY_ON_PORT_RIGHT,
3607 EL_SP_GRAVITY_ON_PORT_UP,
3608 EL_SP_GRAVITY_ON_PORT_DOWN,
3609 EL_SP_GRAVITY_OFF_PORT_LEFT,
3610 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3611 EL_SP_GRAVITY_OFF_PORT_UP,
3612 EL_SP_GRAVITY_OFF_PORT_DOWN,
3614 /* more than one Murphy in a level results in an inactive clone */
3617 /* runtime Supaplex elements */
3618 EL_SP_DISK_RED_ACTIVE,
3619 EL_SP_TERMINAL_ACTIVE,
3620 EL_SP_BUGGY_BASE_ACTIVATING,
3621 EL_SP_BUGGY_BASE_ACTIVE,
3628 static int ep_sb_element[] =
3633 EL_SOKOBAN_FIELD_EMPTY,
3634 EL_SOKOBAN_FIELD_FULL,
3635 EL_SOKOBAN_FIELD_PLAYER,
3640 EL_INVISIBLE_STEELWALL,
3645 static int ep_gem[] =
3657 static int ep_food_dark_yamyam[] =
3685 static int ep_food_penguin[] =
3699 static int ep_food_pig[] =
3711 static int ep_historic_wall[] =
3722 EL_GATE_1_GRAY_ACTIVE,
3723 EL_GATE_2_GRAY_ACTIVE,
3724 EL_GATE_3_GRAY_ACTIVE,
3725 EL_GATE_4_GRAY_ACTIVE,
3734 EL_EM_GATE_1_GRAY_ACTIVE,
3735 EL_EM_GATE_2_GRAY_ACTIVE,
3736 EL_EM_GATE_3_GRAY_ACTIVE,
3737 EL_EM_GATE_4_GRAY_ACTIVE,
3744 EL_EXPANDABLE_WALL_HORIZONTAL,
3745 EL_EXPANDABLE_WALL_VERTICAL,
3746 EL_EXPANDABLE_WALL_ANY,
3747 EL_EXPANDABLE_WALL_GROWING,
3748 EL_BD_EXPANDABLE_WALL,
3755 EL_SP_HARDWARE_GRAY,
3756 EL_SP_HARDWARE_GREEN,
3757 EL_SP_HARDWARE_BLUE,
3759 EL_SP_HARDWARE_YELLOW,
3760 EL_SP_HARDWARE_BASE_1,
3761 EL_SP_HARDWARE_BASE_2,
3762 EL_SP_HARDWARE_BASE_3,
3763 EL_SP_HARDWARE_BASE_4,
3764 EL_SP_HARDWARE_BASE_5,
3765 EL_SP_HARDWARE_BASE_6,
3767 EL_SP_TERMINAL_ACTIVE,
3770 EL_INVISIBLE_STEELWALL,
3771 EL_INVISIBLE_STEELWALL_ACTIVE,
3773 EL_INVISIBLE_WALL_ACTIVE,
3774 EL_STEELWALL_SLIPPERY,
3791 static int ep_historic_solid[] =
3795 EL_EXPANDABLE_WALL_HORIZONTAL,
3796 EL_EXPANDABLE_WALL_VERTICAL,
3797 EL_EXPANDABLE_WALL_ANY,
3798 EL_BD_EXPANDABLE_WALL,
3811 EL_QUICKSAND_FILLING,
3812 EL_QUICKSAND_EMPTYING,
3814 EL_MAGIC_WALL_ACTIVE,
3815 EL_MAGIC_WALL_EMPTYING,
3816 EL_MAGIC_WALL_FILLING,
3820 EL_BD_MAGIC_WALL_ACTIVE,
3821 EL_BD_MAGIC_WALL_EMPTYING,
3822 EL_BD_MAGIC_WALL_FULL,
3823 EL_BD_MAGIC_WALL_FILLING,
3824 EL_BD_MAGIC_WALL_DEAD,
3833 EL_SP_TERMINAL_ACTIVE,
3837 EL_INVISIBLE_WALL_ACTIVE,
3838 EL_SWITCHGATE_SWITCH_UP,
3839 EL_SWITCHGATE_SWITCH_DOWN,
3840 EL_DC_SWITCHGATE_SWITCH_UP,
3841 EL_DC_SWITCHGATE_SWITCH_DOWN,
3843 EL_TIMEGATE_SWITCH_ACTIVE,
3844 EL_DC_TIMEGATE_SWITCH,
3845 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3857 /* the following elements are a direct copy of "indestructible" elements,
3858 except "EL_ACID", which is "indestructible", but not "solid"! */
3863 EL_ACID_POOL_TOPLEFT,
3864 EL_ACID_POOL_TOPRIGHT,
3865 EL_ACID_POOL_BOTTOMLEFT,
3866 EL_ACID_POOL_BOTTOM,
3867 EL_ACID_POOL_BOTTOMRIGHT,
3868 EL_SP_HARDWARE_GRAY,
3869 EL_SP_HARDWARE_GREEN,
3870 EL_SP_HARDWARE_BLUE,
3872 EL_SP_HARDWARE_YELLOW,
3873 EL_SP_HARDWARE_BASE_1,
3874 EL_SP_HARDWARE_BASE_2,
3875 EL_SP_HARDWARE_BASE_3,
3876 EL_SP_HARDWARE_BASE_4,
3877 EL_SP_HARDWARE_BASE_5,
3878 EL_SP_HARDWARE_BASE_6,
3879 EL_INVISIBLE_STEELWALL,
3880 EL_INVISIBLE_STEELWALL_ACTIVE,
3881 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3882 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3883 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3884 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3885 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3886 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3887 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3888 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3889 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3890 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3891 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3892 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3894 EL_LIGHT_SWITCH_ACTIVE,
3895 EL_SIGN_EXCLAMATION,
3896 EL_SIGN_RADIOACTIVITY,
3903 EL_SIGN_ENTRY_FORBIDDEN,
3904 EL_SIGN_EMERGENCY_EXIT,
3912 EL_STEEL_EXIT_CLOSED,
3914 EL_DC_STEELWALL_1_LEFT,
3915 EL_DC_STEELWALL_1_RIGHT,
3916 EL_DC_STEELWALL_1_TOP,
3917 EL_DC_STEELWALL_1_BOTTOM,
3918 EL_DC_STEELWALL_1_HORIZONTAL,
3919 EL_DC_STEELWALL_1_VERTICAL,
3920 EL_DC_STEELWALL_1_TOPLEFT,
3921 EL_DC_STEELWALL_1_TOPRIGHT,
3922 EL_DC_STEELWALL_1_BOTTOMLEFT,
3923 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3924 EL_DC_STEELWALL_1_TOPLEFT_2,
3925 EL_DC_STEELWALL_1_TOPRIGHT_2,
3926 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3927 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3928 EL_DC_STEELWALL_2_LEFT,
3929 EL_DC_STEELWALL_2_RIGHT,
3930 EL_DC_STEELWALL_2_TOP,
3931 EL_DC_STEELWALL_2_BOTTOM,
3932 EL_DC_STEELWALL_2_HORIZONTAL,
3933 EL_DC_STEELWALL_2_VERTICAL,
3934 EL_DC_STEELWALL_2_MIDDLE,
3935 EL_DC_STEELWALL_2_SINGLE,
3936 EL_STEELWALL_SLIPPERY,
3950 EL_GATE_1_GRAY_ACTIVE,
3951 EL_GATE_2_GRAY_ACTIVE,
3952 EL_GATE_3_GRAY_ACTIVE,
3953 EL_GATE_4_GRAY_ACTIVE,
3962 EL_EM_GATE_1_GRAY_ACTIVE,
3963 EL_EM_GATE_2_GRAY_ACTIVE,
3964 EL_EM_GATE_3_GRAY_ACTIVE,
3965 EL_EM_GATE_4_GRAY_ACTIVE,
3967 EL_SWITCHGATE_OPENING,
3968 EL_SWITCHGATE_CLOSED,
3969 EL_SWITCHGATE_CLOSING,
3971 EL_TIMEGATE_OPENING,
3973 EL_TIMEGATE_CLOSING,
3977 EL_TUBE_VERTICAL_LEFT,
3978 EL_TUBE_VERTICAL_RIGHT,
3979 EL_TUBE_HORIZONTAL_UP,
3980 EL_TUBE_HORIZONTAL_DOWN,
3989 static int ep_classic_enemy[] =
4006 static int ep_belt[] =
4008 EL_CONVEYOR_BELT_1_LEFT,
4009 EL_CONVEYOR_BELT_1_MIDDLE,
4010 EL_CONVEYOR_BELT_1_RIGHT,
4011 EL_CONVEYOR_BELT_2_LEFT,
4012 EL_CONVEYOR_BELT_2_MIDDLE,
4013 EL_CONVEYOR_BELT_2_RIGHT,
4014 EL_CONVEYOR_BELT_3_LEFT,
4015 EL_CONVEYOR_BELT_3_MIDDLE,
4016 EL_CONVEYOR_BELT_3_RIGHT,
4017 EL_CONVEYOR_BELT_4_LEFT,
4018 EL_CONVEYOR_BELT_4_MIDDLE,
4019 EL_CONVEYOR_BELT_4_RIGHT,
4024 static int ep_belt_active[] =
4026 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
4027 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
4028 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
4029 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
4030 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
4031 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
4032 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
4033 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
4034 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
4035 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
4036 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
4037 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
4042 static int ep_belt_switch[] =
4044 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4045 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4046 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4047 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4048 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4049 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4050 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4051 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4052 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4053 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4054 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4055 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4060 static int ep_tube[] =
4067 EL_TUBE_HORIZONTAL_UP,
4068 EL_TUBE_HORIZONTAL_DOWN,
4070 EL_TUBE_VERTICAL_LEFT,
4071 EL_TUBE_VERTICAL_RIGHT,
4077 static int ep_acid_pool[] =
4079 EL_ACID_POOL_TOPLEFT,
4080 EL_ACID_POOL_TOPRIGHT,
4081 EL_ACID_POOL_BOTTOMLEFT,
4082 EL_ACID_POOL_BOTTOM,
4083 EL_ACID_POOL_BOTTOMRIGHT,
4088 static int ep_keygate[] =
4098 EL_GATE_1_GRAY_ACTIVE,
4099 EL_GATE_2_GRAY_ACTIVE,
4100 EL_GATE_3_GRAY_ACTIVE,
4101 EL_GATE_4_GRAY_ACTIVE,
4110 EL_EM_GATE_1_GRAY_ACTIVE,
4111 EL_EM_GATE_2_GRAY_ACTIVE,
4112 EL_EM_GATE_3_GRAY_ACTIVE,
4113 EL_EM_GATE_4_GRAY_ACTIVE,
4122 EL_EMC_GATE_5_GRAY_ACTIVE,
4123 EL_EMC_GATE_6_GRAY_ACTIVE,
4124 EL_EMC_GATE_7_GRAY_ACTIVE,
4125 EL_EMC_GATE_8_GRAY_ACTIVE,
4127 EL_DC_GATE_WHITE_GRAY,
4128 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4133 static int ep_amoeboid[] =
4145 static int ep_amoebalive[] =
4156 static int ep_has_editor_content[] =
4178 static int ep_can_turn_each_move[] =
4180 /* !!! do something with this one !!! */
4184 static int ep_can_grow[] =
4198 static int ep_active_bomb[] =
4201 EL_EM_DYNAMITE_ACTIVE,
4202 EL_DYNABOMB_PLAYER_1_ACTIVE,
4203 EL_DYNABOMB_PLAYER_2_ACTIVE,
4204 EL_DYNABOMB_PLAYER_3_ACTIVE,
4205 EL_DYNABOMB_PLAYER_4_ACTIVE,
4206 EL_SP_DISK_RED_ACTIVE,
4211 static int ep_inactive[] =
4221 EL_QUICKSAND_FAST_EMPTY,
4244 EL_GATE_1_GRAY_ACTIVE,
4245 EL_GATE_2_GRAY_ACTIVE,
4246 EL_GATE_3_GRAY_ACTIVE,
4247 EL_GATE_4_GRAY_ACTIVE,
4256 EL_EM_GATE_1_GRAY_ACTIVE,
4257 EL_EM_GATE_2_GRAY_ACTIVE,
4258 EL_EM_GATE_3_GRAY_ACTIVE,
4259 EL_EM_GATE_4_GRAY_ACTIVE,
4268 EL_EMC_GATE_5_GRAY_ACTIVE,
4269 EL_EMC_GATE_6_GRAY_ACTIVE,
4270 EL_EMC_GATE_7_GRAY_ACTIVE,
4271 EL_EMC_GATE_8_GRAY_ACTIVE,
4273 EL_DC_GATE_WHITE_GRAY,
4274 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4275 EL_DC_GATE_FAKE_GRAY,
4278 EL_INVISIBLE_STEELWALL,
4286 EL_WALL_EMERALD_YELLOW,
4287 EL_DYNABOMB_INCREASE_NUMBER,
4288 EL_DYNABOMB_INCREASE_SIZE,
4289 EL_DYNABOMB_INCREASE_POWER,
4293 EL_SOKOBAN_FIELD_EMPTY,
4294 EL_SOKOBAN_FIELD_FULL,
4295 EL_WALL_EMERALD_RED,
4296 EL_WALL_EMERALD_PURPLE,
4297 EL_ACID_POOL_TOPLEFT,
4298 EL_ACID_POOL_TOPRIGHT,
4299 EL_ACID_POOL_BOTTOMLEFT,
4300 EL_ACID_POOL_BOTTOM,
4301 EL_ACID_POOL_BOTTOMRIGHT,
4305 EL_BD_MAGIC_WALL_DEAD,
4307 EL_DC_MAGIC_WALL_DEAD,
4308 EL_AMOEBA_TO_DIAMOND,
4316 EL_SP_GRAVITY_PORT_RIGHT,
4317 EL_SP_GRAVITY_PORT_DOWN,
4318 EL_SP_GRAVITY_PORT_LEFT,
4319 EL_SP_GRAVITY_PORT_UP,
4320 EL_SP_PORT_HORIZONTAL,
4321 EL_SP_PORT_VERTICAL,
4332 EL_SP_HARDWARE_GRAY,
4333 EL_SP_HARDWARE_GREEN,
4334 EL_SP_HARDWARE_BLUE,
4336 EL_SP_HARDWARE_YELLOW,
4337 EL_SP_HARDWARE_BASE_1,
4338 EL_SP_HARDWARE_BASE_2,
4339 EL_SP_HARDWARE_BASE_3,
4340 EL_SP_HARDWARE_BASE_4,
4341 EL_SP_HARDWARE_BASE_5,
4342 EL_SP_HARDWARE_BASE_6,
4343 EL_SP_GRAVITY_ON_PORT_LEFT,
4344 EL_SP_GRAVITY_ON_PORT_RIGHT,
4345 EL_SP_GRAVITY_ON_PORT_UP,
4346 EL_SP_GRAVITY_ON_PORT_DOWN,
4347 EL_SP_GRAVITY_OFF_PORT_LEFT,
4348 EL_SP_GRAVITY_OFF_PORT_RIGHT,
4349 EL_SP_GRAVITY_OFF_PORT_UP,
4350 EL_SP_GRAVITY_OFF_PORT_DOWN,
4351 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4352 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4353 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4354 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4355 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4356 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4357 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4358 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4359 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4360 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4361 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4362 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4363 EL_SIGN_EXCLAMATION,
4364 EL_SIGN_RADIOACTIVITY,
4371 EL_SIGN_ENTRY_FORBIDDEN,
4372 EL_SIGN_EMERGENCY_EXIT,
4380 EL_DC_STEELWALL_1_LEFT,
4381 EL_DC_STEELWALL_1_RIGHT,
4382 EL_DC_STEELWALL_1_TOP,
4383 EL_DC_STEELWALL_1_BOTTOM,
4384 EL_DC_STEELWALL_1_HORIZONTAL,
4385 EL_DC_STEELWALL_1_VERTICAL,
4386 EL_DC_STEELWALL_1_TOPLEFT,
4387 EL_DC_STEELWALL_1_TOPRIGHT,
4388 EL_DC_STEELWALL_1_BOTTOMLEFT,
4389 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4390 EL_DC_STEELWALL_1_TOPLEFT_2,
4391 EL_DC_STEELWALL_1_TOPRIGHT_2,
4392 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4393 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4394 EL_DC_STEELWALL_2_LEFT,
4395 EL_DC_STEELWALL_2_RIGHT,
4396 EL_DC_STEELWALL_2_TOP,
4397 EL_DC_STEELWALL_2_BOTTOM,
4398 EL_DC_STEELWALL_2_HORIZONTAL,
4399 EL_DC_STEELWALL_2_VERTICAL,
4400 EL_DC_STEELWALL_2_MIDDLE,
4401 EL_DC_STEELWALL_2_SINGLE,
4402 EL_STEELWALL_SLIPPERY,
4407 EL_EMC_WALL_SLIPPERY_1,
4408 EL_EMC_WALL_SLIPPERY_2,
4409 EL_EMC_WALL_SLIPPERY_3,
4410 EL_EMC_WALL_SLIPPERY_4,
4431 static int ep_em_slippery_wall[] =
4436 static int ep_gfx_crumbled[] =
4447 static int ep_editor_cascade_active[] =
4449 EL_INTERNAL_CASCADE_BD_ACTIVE,
4450 EL_INTERNAL_CASCADE_EM_ACTIVE,
4451 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4452 EL_INTERNAL_CASCADE_RND_ACTIVE,
4453 EL_INTERNAL_CASCADE_SB_ACTIVE,
4454 EL_INTERNAL_CASCADE_SP_ACTIVE,
4455 EL_INTERNAL_CASCADE_DC_ACTIVE,
4456 EL_INTERNAL_CASCADE_DX_ACTIVE,
4457 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4458 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4459 EL_INTERNAL_CASCADE_CE_ACTIVE,
4460 EL_INTERNAL_CASCADE_GE_ACTIVE,
4461 EL_INTERNAL_CASCADE_REF_ACTIVE,
4462 EL_INTERNAL_CASCADE_USER_ACTIVE,
4463 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4468 static int ep_editor_cascade_inactive[] =
4470 EL_INTERNAL_CASCADE_BD,
4471 EL_INTERNAL_CASCADE_EM,
4472 EL_INTERNAL_CASCADE_EMC,
4473 EL_INTERNAL_CASCADE_RND,
4474 EL_INTERNAL_CASCADE_SB,
4475 EL_INTERNAL_CASCADE_SP,
4476 EL_INTERNAL_CASCADE_DC,
4477 EL_INTERNAL_CASCADE_DX,
4478 EL_INTERNAL_CASCADE_CHARS,
4479 EL_INTERNAL_CASCADE_STEEL_CHARS,
4480 EL_INTERNAL_CASCADE_CE,
4481 EL_INTERNAL_CASCADE_GE,
4482 EL_INTERNAL_CASCADE_REF,
4483 EL_INTERNAL_CASCADE_USER,
4484 EL_INTERNAL_CASCADE_DYNAMIC,
4489 static int ep_obsolete[] =
4493 EL_EM_KEY_1_FILE_OBSOLETE,
4494 EL_EM_KEY_2_FILE_OBSOLETE,
4495 EL_EM_KEY_3_FILE_OBSOLETE,
4496 EL_EM_KEY_4_FILE_OBSOLETE,
4497 EL_ENVELOPE_OBSOLETE,
4506 } element_properties[] =
4508 { ep_diggable, EP_DIGGABLE },
4509 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4510 { ep_dont_run_into, EP_DONT_RUN_INTO },
4511 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4512 { ep_dont_touch, EP_DONT_TOUCH },
4513 { ep_indestructible, EP_INDESTRUCTIBLE },
4514 { ep_slippery, EP_SLIPPERY },
4515 { ep_can_change, EP_CAN_CHANGE },
4516 { ep_can_move, EP_CAN_MOVE },
4517 { ep_can_fall, EP_CAN_FALL },
4518 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4519 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4520 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4521 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4522 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4523 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4524 { ep_walkable_over, EP_WALKABLE_OVER },
4525 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4526 { ep_walkable_under, EP_WALKABLE_UNDER },
4527 { ep_passable_over, EP_PASSABLE_OVER },
4528 { ep_passable_inside, EP_PASSABLE_INSIDE },
4529 { ep_passable_under, EP_PASSABLE_UNDER },
4530 { ep_droppable, EP_DROPPABLE },
4531 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4532 { ep_pushable, EP_PUSHABLE },
4533 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4534 { ep_protected, EP_PROTECTED },
4535 { ep_throwable, EP_THROWABLE },
4536 { ep_can_explode, EP_CAN_EXPLODE },
4537 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4539 { ep_player, EP_PLAYER },
4540 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4541 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4542 { ep_switchable, EP_SWITCHABLE },
4543 { ep_bd_element, EP_BD_ELEMENT },
4544 { ep_sp_element, EP_SP_ELEMENT },
4545 { ep_sb_element, EP_SB_ELEMENT },
4547 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4548 { ep_food_penguin, EP_FOOD_PENGUIN },
4549 { ep_food_pig, EP_FOOD_PIG },
4550 { ep_historic_wall, EP_HISTORIC_WALL },
4551 { ep_historic_solid, EP_HISTORIC_SOLID },
4552 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4553 { ep_belt, EP_BELT },
4554 { ep_belt_active, EP_BELT_ACTIVE },
4555 { ep_belt_switch, EP_BELT_SWITCH },
4556 { ep_tube, EP_TUBE },
4557 { ep_acid_pool, EP_ACID_POOL },
4558 { ep_keygate, EP_KEYGATE },
4559 { ep_amoeboid, EP_AMOEBOID },
4560 { ep_amoebalive, EP_AMOEBALIVE },
4561 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4562 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4563 { ep_can_grow, EP_CAN_GROW },
4564 { ep_active_bomb, EP_ACTIVE_BOMB },
4565 { ep_inactive, EP_INACTIVE },
4567 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4569 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4571 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4572 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4574 { ep_obsolete, EP_OBSOLETE },
4581 /* always start with reliable default values (element has no properties) */
4582 /* (but never initialize clipboard elements after the very first time) */
4583 /* (to be able to use clipboard elements between several levels) */
4584 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4585 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4586 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4587 SET_PROPERTY(i, j, FALSE);
4589 /* set all base element properties from above array definitions */
4590 for (i = 0; element_properties[i].elements != NULL; i++)
4591 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4592 SET_PROPERTY((element_properties[i].elements)[j],
4593 element_properties[i].property, TRUE);
4595 /* copy properties to some elements that are only stored in level file */
4596 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4597 for (j = 0; copy_properties[j][0] != -1; j++)
4598 if (HAS_PROPERTY(copy_properties[j][0], i))
4599 for (k = 1; k <= 4; k++)
4600 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4602 /* set static element properties that are not listed in array definitions */
4603 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4604 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4606 clipboard_elements_initialized = TRUE;
4609 void InitElementPropertiesEngine(int engine_version)
4611 static int no_wall_properties[] =
4614 EP_COLLECTIBLE_ONLY,
4616 EP_DONT_COLLIDE_WITH,
4619 EP_CAN_SMASH_PLAYER,
4620 EP_CAN_SMASH_ENEMIES,
4621 EP_CAN_SMASH_EVERYTHING,
4626 EP_FOOD_DARK_YAMYAM,
4642 /* important: after initialization in InitElementPropertiesStatic(), the
4643 elements are not again initialized to a default value; therefore all
4644 changes have to make sure that they leave the element with a defined
4645 property (which means that conditional property changes must be set to
4646 a reliable default value before) */
4648 /* resolve group elements */
4649 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4650 ResolveGroupElement(EL_GROUP_START + i);
4652 /* set all special, combined or engine dependent element properties */
4653 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4655 /* do not change (already initialized) clipboard elements here */
4656 if (IS_CLIPBOARD_ELEMENT(i))
4659 /* ---------- INACTIVE ------------------------------------------------- */
4660 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4661 i <= EL_CHAR_END) ||
4662 (i >= EL_STEEL_CHAR_START &&
4663 i <= EL_STEEL_CHAR_END)));
4665 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4666 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4667 IS_WALKABLE_INSIDE(i) ||
4668 IS_WALKABLE_UNDER(i)));
4670 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4671 IS_PASSABLE_INSIDE(i) ||
4672 IS_PASSABLE_UNDER(i)));
4674 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4675 IS_PASSABLE_OVER(i)));
4677 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4678 IS_PASSABLE_INSIDE(i)));
4680 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4681 IS_PASSABLE_UNDER(i)));
4683 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4686 /* ---------- COLLECTIBLE ---------------------------------------------- */
4687 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4691 /* ---------- SNAPPABLE ------------------------------------------------ */
4692 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4693 IS_COLLECTIBLE(i) ||
4697 /* ---------- WALL ----------------------------------------------------- */
4698 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4700 for (j = 0; no_wall_properties[j] != -1; j++)
4701 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4702 i >= EL_FIRST_RUNTIME_UNREAL)
4703 SET_PROPERTY(i, EP_WALL, FALSE);
4705 if (IS_HISTORIC_WALL(i))
4706 SET_PROPERTY(i, EP_WALL, TRUE);
4708 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4709 if (engine_version < VERSION_IDENT(2,2,0,0))
4710 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4712 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4714 !IS_COLLECTIBLE(i)));
4716 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4717 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4718 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4720 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4721 IS_INDESTRUCTIBLE(i)));
4723 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4725 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4726 else if (engine_version < VERSION_IDENT(2,2,0,0))
4727 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4729 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4733 if (IS_CUSTOM_ELEMENT(i))
4735 /* these are additional properties which are initially false when set */
4737 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4739 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4740 if (DONT_COLLIDE_WITH(i))
4741 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4743 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4744 if (CAN_SMASH_EVERYTHING(i))
4745 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4746 if (CAN_SMASH_ENEMIES(i))
4747 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4750 /* ---------- CAN_SMASH ------------------------------------------------ */
4751 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4752 CAN_SMASH_ENEMIES(i) ||
4753 CAN_SMASH_EVERYTHING(i)));
4755 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4756 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4757 EXPLODES_BY_FIRE(i)));
4759 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4760 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4761 EXPLODES_SMASHED(i)));
4763 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4764 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4765 EXPLODES_IMPACT(i)));
4767 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4768 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4770 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4771 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4772 i == EL_BLACK_ORB));
4774 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4775 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4777 IS_CUSTOM_ELEMENT(i)));
4779 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4780 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4781 i == EL_SP_ELECTRON));
4783 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4784 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4785 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4786 getMoveIntoAcidProperty(&level, i));
4788 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4789 if (MAYBE_DONT_COLLIDE_WITH(i))
4790 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4791 getDontCollideWithProperty(&level, i));
4793 /* ---------- SP_PORT -------------------------------------------------- */
4794 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4795 IS_PASSABLE_INSIDE(i)));
4797 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4798 for (j = 0; j < level.num_android_clone_elements; j++)
4799 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4801 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4803 /* ---------- CAN_CHANGE ----------------------------------------------- */
4804 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4805 for (j = 0; j < element_info[i].num_change_pages; j++)
4806 if (element_info[i].change_page[j].can_change)
4807 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4809 /* ---------- HAS_ACTION ----------------------------------------------- */
4810 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4811 for (j = 0; j < element_info[i].num_change_pages; j++)
4812 if (element_info[i].change_page[j].has_action)
4813 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4815 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4816 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4819 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4821 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4822 element_info[i].crumbled[ACTION_DEFAULT] !=
4823 element_info[i].graphic[ACTION_DEFAULT]);
4825 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
4826 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4827 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
4830 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4831 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4832 IS_EDITOR_CASCADE_INACTIVE(i)));
4835 /* dynamically adjust element properties according to game engine version */
4837 static int ep_em_slippery_wall[] =
4842 EL_EXPANDABLE_WALL_HORIZONTAL,
4843 EL_EXPANDABLE_WALL_VERTICAL,
4844 EL_EXPANDABLE_WALL_ANY,
4845 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4846 EL_EXPANDABLE_STEELWALL_VERTICAL,
4847 EL_EXPANDABLE_STEELWALL_ANY,
4848 EL_EXPANDABLE_STEELWALL_GROWING,
4852 /* special EM style gems behaviour */
4853 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4854 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4855 level.em_slippery_gems);
4857 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4858 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4859 (level.em_slippery_gems &&
4860 engine_version > VERSION_IDENT(2,0,1,0)));
4863 /* this is needed because some graphics depend on element properties */
4864 if (game_status == GAME_MODE_PLAYING)
4865 InitElementGraphicInfo();
4868 void InitElementPropertiesAfterLoading(int engine_version)
4872 /* set some other uninitialized values of custom elements in older levels */
4873 if (engine_version < VERSION_IDENT(3,1,0,0))
4875 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4877 int element = EL_CUSTOM_START + i;
4879 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4881 element_info[element].explosion_delay = 17;
4882 element_info[element].ignition_delay = 8;
4887 static void InitGlobal()
4892 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4894 /* check if element_name_info entry defined for each element in "main.h" */
4895 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4896 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4898 element_info[i].token_name = element_name_info[i].token_name;
4899 element_info[i].class_name = element_name_info[i].class_name;
4900 element_info[i].editor_description= element_name_info[i].editor_description;
4903 printf("%04d: %s\n", i, element_name_info[i].token_name);
4907 /* create hash from image config list */
4908 image_config_hash = newSetupFileHash();
4909 for (i = 0; image_config[i].token != NULL; i++)
4910 setHashEntry(image_config_hash,
4911 image_config[i].token,
4912 image_config[i].value);
4914 /* create hash from element token list */
4915 element_token_hash = newSetupFileHash();
4916 for (i = 0; element_name_info[i].token_name != NULL; i++)
4917 setHashEntry(element_token_hash,
4918 element_name_info[i].token_name,
4921 /* create hash from graphic token list */
4922 graphic_token_hash = newSetupFileHash();
4923 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4924 if (strSuffix(image_config[i].value, ".pcx") ||
4925 strSuffix(image_config[i].value, ".wav") ||
4926 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4927 setHashEntry(graphic_token_hash,
4928 image_config[i].token,
4929 int2str(graphic++, 0));
4931 /* create hash from font token list */
4932 font_token_hash = newSetupFileHash();
4933 for (i = 0; font_info[i].token_name != NULL; i++)
4934 setHashEntry(font_token_hash,
4935 font_info[i].token_name,
4938 /* always start with reliable default values (all elements) */
4939 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4940 ActiveElement[i] = i;
4942 /* now add all entries that have an active state (active elements) */
4943 for (i = 0; element_with_active_state[i].element != -1; i++)
4945 int element = element_with_active_state[i].element;
4946 int element_active = element_with_active_state[i].element_active;
4948 ActiveElement[element] = element_active;
4951 /* always start with reliable default values (all buttons) */
4952 for (i = 0; i < NUM_IMAGE_FILES; i++)
4953 ActiveButton[i] = i;
4955 /* now add all entries that have an active state (active buttons) */
4956 for (i = 0; button_with_active_state[i].button != -1; i++)
4958 int button = button_with_active_state[i].button;
4959 int button_active = button_with_active_state[i].button_active;
4961 ActiveButton[button] = button_active;
4964 /* always start with reliable default values (all fonts) */
4965 for (i = 0; i < NUM_FONTS; i++)
4968 /* now add all entries that have an active state (active fonts) */
4969 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4971 int font = font_with_active_state[i].font_nr;
4972 int font_active = font_with_active_state[i].font_nr_active;
4974 ActiveFont[font] = font_active;
4977 global.autoplay_leveldir = NULL;
4978 global.convert_leveldir = NULL;
4979 global.create_images_dir = NULL;
4981 global.frames_per_second = 0;
4982 global.fps_slowdown = FALSE;
4983 global.fps_slowdown_factor = 1;
4985 global.border_status = GAME_MODE_MAIN;
4987 global.fading_status = GAME_MODE_MAIN;
4988 global.fading_type = TYPE_ENTER_MENU;
4992 void Execute_Command(char *command)
4996 if (strEqual(command, "print graphicsinfo.conf"))
4998 printf("# You can configure additional/alternative image files here.\n");
4999 printf("# (The entries below are default and therefore commented out.)\n");
5001 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
5003 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5006 for (i = 0; image_config[i].token != NULL; i++)
5007 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
5008 image_config[i].value));
5012 else if (strEqual(command, "print soundsinfo.conf"))
5014 printf("# You can configure additional/alternative sound files here.\n");
5015 printf("# (The entries below are default and therefore commented out.)\n");
5017 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
5019 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5022 for (i = 0; sound_config[i].token != NULL; i++)
5023 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
5024 sound_config[i].value));
5028 else if (strEqual(command, "print musicinfo.conf"))
5030 printf("# You can configure additional/alternative music files here.\n");
5031 printf("# (The entries below are default and therefore commented out.)\n");
5033 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
5035 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5038 for (i = 0; music_config[i].token != NULL; i++)
5039 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
5040 music_config[i].value));
5044 else if (strEqual(command, "print editorsetup.conf"))
5046 printf("# You can configure your personal editor element list here.\n");
5047 printf("# (The entries below are default and therefore commented out.)\n");
5050 /* this is needed to be able to check element list for cascade elements */
5051 InitElementPropertiesStatic();
5052 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5054 PrintEditorElementList();
5058 else if (strEqual(command, "print helpanim.conf"))
5060 printf("# You can configure different element help animations here.\n");
5061 printf("# (The entries below are default and therefore commented out.)\n");
5064 for (i = 0; helpanim_config[i].token != NULL; i++)
5066 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
5067 helpanim_config[i].value));
5069 if (strEqual(helpanim_config[i].token, "end"))
5075 else if (strEqual(command, "print helptext.conf"))
5077 printf("# You can configure different element help text here.\n");
5078 printf("# (The entries below are default and therefore commented out.)\n");
5081 for (i = 0; helptext_config[i].token != NULL; i++)
5082 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
5083 helptext_config[i].value));
5087 else if (strncmp(command, "dump level ", 11) == 0)
5089 char *filename = &command[11];
5091 if (!fileExists(filename))
5092 Error(ERR_EXIT, "cannot open file '%s'", filename);
5094 LoadLevelFromFilename(&level, filename);
5099 else if (strncmp(command, "dump tape ", 10) == 0)
5101 char *filename = &command[10];
5103 if (!fileExists(filename))
5104 Error(ERR_EXIT, "cannot open file '%s'", filename);
5106 LoadTapeFromFilename(filename);
5111 else if (strncmp(command, "autoplay ", 9) == 0)
5113 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
5115 while (*str_ptr != '\0') /* continue parsing string */
5117 /* cut leading whitespace from string, replace it by string terminator */
5118 while (*str_ptr == ' ' || *str_ptr == '\t')
5121 if (*str_ptr == '\0') /* end of string reached */
5124 if (global.autoplay_leveldir == NULL) /* read level set string */
5126 global.autoplay_leveldir = str_ptr;
5127 global.autoplay_all = TRUE; /* default: play all tapes */
5129 for (i = 0; i < MAX_TAPES_PER_SET; i++)
5130 global.autoplay_level[i] = FALSE;
5132 else /* read level number string */
5134 int level_nr = atoi(str_ptr); /* get level_nr value */
5136 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5137 global.autoplay_level[level_nr] = TRUE;
5139 global.autoplay_all = FALSE;
5142 /* advance string pointer to the next whitespace (or end of string) */
5143 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5147 else if (strncmp(command, "convert ", 8) == 0)
5149 char *str_copy = getStringCopy(&command[8]);
5150 char *str_ptr = strchr(str_copy, ' ');
5152 global.convert_leveldir = str_copy;
5153 global.convert_level_nr = -1;
5155 if (str_ptr != NULL) /* level number follows */
5157 *str_ptr++ = '\0'; /* terminate leveldir string */
5158 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
5161 else if (strncmp(command, "create images ", 14) == 0)
5163 #if defined(TARGET_SDL)
5164 global.create_images_dir = getStringCopy(&command[14]);
5166 if (access(global.create_images_dir, W_OK) != 0)
5167 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
5168 global.create_images_dir);
5170 Error(ERR_EXIT, "command only available for SDL target");
5175 #if defined(TARGET_SDL)
5176 else if (strEqual(command, "SDL_ListModes"))
5181 SDL_Init(SDL_INIT_VIDEO);
5183 /* get available fullscreen/hardware modes */
5184 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
5186 /* check if there are any modes available */
5189 printf("No modes available!\n");
5194 /* check if our resolution is restricted */
5195 if (modes == (SDL_Rect **)-1)
5197 printf("All resolutions available.\n");
5201 printf("Available Modes:\n");
5203 for(i = 0; modes[i]; i++)
5204 printf(" %d x %d\n", modes[i]->w, modes[i]->h);
5214 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
5218 static void InitSetup()
5220 LoadSetup(); /* global setup info */
5222 /* set some options from setup file */
5224 if (setup.options.verbose)
5225 options.verbose = TRUE;
5228 static void InitGameInfo()
5230 game.restart_level = FALSE;
5233 static void InitPlayerInfo()
5237 /* choose default local player */
5238 local_player = &stored_player[0];
5240 for (i = 0; i < MAX_PLAYERS; i++)
5241 stored_player[i].connected = FALSE;
5243 local_player->connected = TRUE;
5246 static void InitArtworkInfo()
5251 static char *get_string_in_brackets(char *string)
5253 char *string_in_brackets = checked_malloc(strlen(string) + 3);
5255 sprintf(string_in_brackets, "[%s]", string);
5257 return string_in_brackets;
5260 static char *get_level_id_suffix(int id_nr)
5262 char *id_suffix = checked_malloc(1 + 3 + 1);
5264 if (id_nr < 0 || id_nr > 999)
5267 sprintf(id_suffix, ".%03d", id_nr);
5273 static char *get_element_class_token(int element)
5275 char *element_class_name = element_info[element].class_name;
5276 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
5278 sprintf(element_class_token, "[%s]", element_class_name);
5280 return element_class_token;
5283 static char *get_action_class_token(int action)
5285 char *action_class_name = &element_action_info[action].suffix[1];
5286 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
5288 sprintf(action_class_token, "[%s]", action_class_name);
5290 return action_class_token;
5294 static void InitArtworkConfig()
5296 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
5297 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
5298 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
5299 static char *action_id_suffix[NUM_ACTIONS + 1];
5300 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5301 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5302 static char *level_id_suffix[MAX_LEVELS + 1];
5303 static char *dummy[1] = { NULL };
5304 static char *ignore_generic_tokens[] =
5310 static char **ignore_image_tokens;
5311 static char **ignore_sound_tokens;
5312 static char **ignore_music_tokens;
5313 int num_ignore_generic_tokens;
5314 int num_ignore_image_tokens;
5315 int num_ignore_sound_tokens;
5316 int num_ignore_music_tokens;
5319 /* dynamically determine list of generic tokens to be ignored */
5320 num_ignore_generic_tokens = 0;
5321 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5322 num_ignore_generic_tokens++;
5324 /* dynamically determine list of image tokens to be ignored */
5325 num_ignore_image_tokens = num_ignore_generic_tokens;
5326 for (i = 0; image_config_vars[i].token != NULL; i++)
5327 num_ignore_image_tokens++;
5328 ignore_image_tokens =
5329 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5330 for (i = 0; i < num_ignore_generic_tokens; i++)
5331 ignore_image_tokens[i] = ignore_generic_tokens[i];
5332 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5333 ignore_image_tokens[num_ignore_generic_tokens + i] =
5334 image_config_vars[i].token;
5335 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5337 /* dynamically determine list of sound tokens to be ignored */
5338 num_ignore_sound_tokens = num_ignore_generic_tokens;
5339 ignore_sound_tokens =
5340 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5341 for (i = 0; i < num_ignore_generic_tokens; i++)
5342 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5343 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5345 /* dynamically determine list of music tokens to be ignored */
5346 num_ignore_music_tokens = num_ignore_generic_tokens;
5347 ignore_music_tokens =
5348 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5349 for (i = 0; i < num_ignore_generic_tokens; i++)
5350 ignore_music_tokens[i] = ignore_generic_tokens[i];
5351 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5353 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5354 image_id_prefix[i] = element_info[i].token_name;
5355 for (i = 0; i < NUM_FONTS; i++)
5356 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5357 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
5359 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5360 sound_id_prefix[i] = element_info[i].token_name;
5361 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5362 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5363 get_string_in_brackets(element_info[i].class_name);
5364 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
5366 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5367 music_id_prefix[i] = music_prefix_info[i].prefix;
5368 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
5370 for (i = 0; i < NUM_ACTIONS; i++)
5371 action_id_suffix[i] = element_action_info[i].suffix;
5372 action_id_suffix[NUM_ACTIONS] = NULL;
5374 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5375 direction_id_suffix[i] = element_direction_info[i].suffix;
5376 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5378 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5379 special_id_suffix[i] = special_suffix_info[i].suffix;
5380 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5382 for (i = 0; i < MAX_LEVELS; i++)
5383 level_id_suffix[i] = get_level_id_suffix(i);
5384 level_id_suffix[MAX_LEVELS] = NULL;
5386 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5387 image_id_prefix, action_id_suffix, direction_id_suffix,
5388 special_id_suffix, ignore_image_tokens);
5389 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5390 sound_id_prefix, action_id_suffix, dummy,
5391 special_id_suffix, ignore_sound_tokens);
5392 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5393 music_id_prefix, special_id_suffix, level_id_suffix,
5394 dummy, ignore_music_tokens);
5397 static void InitMixer()
5406 struct GraphicInfo *graphic_info_last = graphic_info;
5407 char *filename_font_initial = NULL;
5408 char *filename_anim_initial = NULL;
5409 Bitmap *bitmap_font_initial = NULL;
5413 /* determine settings for initial font (for displaying startup messages) */
5414 for (i = 0; image_config[i].token != NULL; i++)
5416 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5418 char font_token[128];
5421 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5422 len_font_token = strlen(font_token);
5424 if (strEqual(image_config[i].token, font_token))
5425 filename_font_initial = image_config[i].value;
5426 else if (strlen(image_config[i].token) > len_font_token &&
5427 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5429 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5430 font_initial[j].src_x = atoi(image_config[i].value);
5431 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5432 font_initial[j].src_y = atoi(image_config[i].value);
5433 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5434 font_initial[j].width = atoi(image_config[i].value);
5435 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5436 font_initial[j].height = atoi(image_config[i].value);
5441 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5443 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5444 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5447 if (filename_font_initial == NULL) /* should not happen */
5448 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5450 /* create additional image buffers for double-buffering and cross-fading */
5451 bitmap_db_cross = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5452 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
5453 bitmap_db_panel = CreateBitmap(DXSIZE, DYSIZE, DEFAULT_DEPTH);
5454 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
5455 bitmap_db_toons = CreateBitmap(FULL_SXSIZE, FULL_SYSIZE, DEFAULT_DEPTH);
5457 /* initialize screen properties */
5458 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5459 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5461 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5462 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5463 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5464 InitGfxCustomArtworkInfo();
5466 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5468 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5469 font_initial[j].bitmap = bitmap_font_initial;
5471 InitFontGraphicInfo();
5473 font_height = getFontHeight(FC_RED);
5476 DrawInitText(getWindowTitleString(), 20, FC_YELLOW);
5478 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
5480 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
5481 DrawInitText(PROGRAM_WEBSITE_STRING, WIN_YSIZE - 20 - font_height, FC_RED);
5483 DrawInitText("Loading graphics", 120, FC_GREEN);
5487 /* initialize busy animation with default values */
5488 int parameter[NUM_GFX_ARGS];
5489 for (i = 0; i < NUM_GFX_ARGS; i++)
5490 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5491 image_config_suffix[i].token,
5492 image_config_suffix[i].type);
5494 for (i = 0; i < NUM_GFX_ARGS; i++)
5495 printf("::: '%s' => %d\n", image_config_suffix[i].token, parameter[i]);
5499 /* determine settings for busy animation (when displaying startup messages) */
5500 for (i = 0; image_config[i].token != NULL; i++)
5502 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5503 int len_anim_token = strlen(anim_token);
5505 if (strEqual(image_config[i].token, anim_token))
5506 filename_anim_initial = image_config[i].value;
5507 else if (strlen(image_config[i].token) > len_anim_token &&
5508 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5511 for (j = 0; image_config_suffix[j].token != NULL; j++)
5513 if (strEqual(&image_config[i].token[len_anim_token],
5514 image_config_suffix[j].token))
5516 get_graphic_parameter_value(image_config[i].value,
5517 image_config_suffix[j].token,
5518 image_config_suffix[j].type);
5521 if (strEqual(&image_config[i].token[len_anim_token], ".x"))
5522 anim_initial.src_x = atoi(image_config[i].value);
5523 else if (strEqual(&image_config[i].token[len_anim_token], ".y"))
5524 anim_initial.src_y = atoi(image_config[i].value);
5525 else if (strEqual(&image_config[i].token[len_anim_token], ".width"))
5526 anim_initial.width = atoi(image_config[i].value);
5527 else if (strEqual(&image_config[i].token[len_anim_token], ".height"))
5528 anim_initial.height = atoi(image_config[i].value);
5529 else if (strEqual(&image_config[i].token[len_anim_token], ".frames"))
5530 anim_initial.anim_frames = atoi(image_config[i].value);
5531 else if (strEqual(&image_config[i].token[len_anim_token],
5532 ".frames_per_line"))
5533 anim_initial.anim_frames_per_line = atoi(image_config[i].value);
5534 else if (strEqual(&image_config[i].token[len_anim_token], ".delay"))
5535 anim_initial.anim_delay = atoi(image_config[i].value);
5540 #if defined(CREATE_SPECIAL_EDITION_RND_JUE)
5541 filename_anim_initial = "loading.pcx";
5543 parameter[GFX_ARG_X] = 0;
5544 parameter[GFX_ARG_Y] = 0;
5545 parameter[GFX_ARG_WIDTH] = 128;
5546 parameter[GFX_ARG_HEIGHT] = 40;
5547 parameter[GFX_ARG_FRAMES] = 32;
5548 parameter[GFX_ARG_DELAY] = 4;
5549 parameter[GFX_ARG_FRAMES_PER_LINE] = ARG_UNDEFINED_VALUE;
5552 if (filename_anim_initial == NULL) /* should not happen */
5553 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5555 anim_initial.bitmap = LoadCustomImage(filename_anim_initial);
5557 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
5559 set_graphic_parameters_ext(0, parameter, anim_initial.bitmap);
5562 printf("::: INIT_GFX: anim_frames_per_line == %d [%d / %d] [%d, %d]\n",
5563 graphic_info[0].anim_frames_per_line,
5564 get_scaled_graphic_width(0),
5565 graphic_info[0].width,
5566 getOriginalImageWidthFromImageID(0),
5567 graphic_info[0].scale_up_factor);
5570 graphic_info = graphic_info_last;
5572 init.busy.width = anim_initial.width;
5573 init.busy.height = anim_initial.height;
5575 InitMenuDesignSettings_Static();
5576 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5580 void RedrawBackground()
5582 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
5583 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
5585 redraw_mask = REDRAW_ALL;
5588 void InitGfxBackground()
5592 fieldbuffer = bitmap_db_field;
5593 SetDrawtoField(DRAW_BACKBUFFER);
5596 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5600 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
5601 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
5604 for (x = 0; x < MAX_BUF_XSIZE; x++)
5605 for (y = 0; y < MAX_BUF_YSIZE; y++)
5608 redraw_mask = REDRAW_ALL;
5611 static void InitLevelInfo()
5613 LoadLevelInfo(); /* global level info */
5614 LoadLevelSetup_LastSeries(); /* last played series info */
5615 LoadLevelSetup_SeriesInfo(); /* last played level info */
5618 static void InitLevelArtworkInfo()
5620 LoadLevelArtworkInfo();
5623 static void InitImages()
5625 print_timestamp_init("InitImages");
5628 printf("::: leveldir_current->identifier == '%s'\n",
5629 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5630 printf("::: leveldir_current->graphics_path == '%s'\n",
5631 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5632 printf("::: leveldir_current->graphics_set == '%s'\n",
5633 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5634 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5635 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5638 setLevelArtworkDir(artwork.gfx_first);
5641 printf("::: leveldir_current->identifier == '%s'\n",
5642 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5643 printf("::: leveldir_current->graphics_path == '%s'\n",
5644 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5645 printf("::: leveldir_current->graphics_set == '%s'\n",
5646 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5647 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5648 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5652 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5653 leveldir_current->identifier,
5654 artwork.gfx_current_identifier,
5655 artwork.gfx_current->identifier,
5656 leveldir_current->graphics_set,
5657 leveldir_current->graphics_path);
5660 UPDATE_BUSY_STATE();
5662 ReloadCustomImages();
5663 print_timestamp_time("ReloadCustomImages");
5665 UPDATE_BUSY_STATE();
5667 LoadCustomElementDescriptions();
5668 print_timestamp_time("LoadCustomElementDescriptions");
5670 UPDATE_BUSY_STATE();
5672 LoadMenuDesignSettings();
5673 print_timestamp_time("LoadMenuDesignSettings");
5675 UPDATE_BUSY_STATE();
5677 ReinitializeGraphics();
5678 print_timestamp_time("ReinitializeGraphics");
5680 UPDATE_BUSY_STATE();
5682 print_timestamp_done("InitImages");
5685 static void InitSound(char *identifier)
5687 print_timestamp_init("InitSound");
5689 if (identifier == NULL)
5690 identifier = artwork.snd_current->identifier;
5692 /* set artwork path to send it to the sound server process */
5693 setLevelArtworkDir(artwork.snd_first);
5695 InitReloadCustomSounds(identifier);
5696 print_timestamp_time("InitReloadCustomSounds");
5698 ReinitializeSounds();
5699 print_timestamp_time("ReinitializeSounds");
5701 print_timestamp_done("InitSound");
5704 static void InitMusic(char *identifier)
5706 print_timestamp_init("InitMusic");
5708 if (identifier == NULL)
5709 identifier = artwork.mus_current->identifier;
5711 /* set artwork path to send it to the sound server process */
5712 setLevelArtworkDir(artwork.mus_first);
5714 InitReloadCustomMusic(identifier);
5715 print_timestamp_time("InitReloadCustomMusic");
5717 ReinitializeMusic();
5718 print_timestamp_time("ReinitializeMusic");
5720 print_timestamp_done("InitMusic");
5723 void InitNetworkServer()
5725 #if defined(NETWORK_AVALIABLE)
5729 if (!options.network)
5732 #if defined(NETWORK_AVALIABLE)
5733 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5735 if (!ConnectToServer(options.server_host, options.server_port))
5736 Error(ERR_EXIT, "cannot connect to network game server");
5738 SendToServer_PlayerName(setup.player_name);
5739 SendToServer_ProtocolVersion();
5742 SendToServer_NrWanted(nr_wanted);
5746 static boolean CheckArtworkConfigForCustomElements(char *filename)
5748 SetupFileHash *setup_file_hash;
5749 boolean redefined_ce_found = FALSE;
5751 /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */
5753 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5755 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5757 char *token = HASH_ITERATION_TOKEN(itr);
5759 if (strPrefix(token, "custom_"))
5761 redefined_ce_found = TRUE;
5766 END_HASH_ITERATION(setup_file_hash, itr)
5768 freeSetupFileHash(setup_file_hash);
5771 return redefined_ce_found;
5774 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5776 char *filename_base, *filename_local;
5777 boolean redefined_ce_found = FALSE;
5779 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5782 printf("::: leveldir_current->identifier == '%s'\n",
5783 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5784 printf("::: leveldir_current->graphics_path == '%s'\n",
5785 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5786 printf("::: leveldir_current->graphics_set == '%s'\n",
5787 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5788 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5789 leveldir_current == NULL ? "[NULL]" :
5790 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5793 /* first look for special artwork configured in level series config */
5794 filename_base = getCustomArtworkLevelConfigFilename(type);
5797 printf("::: filename_base == '%s'\n", filename_base);
5800 if (fileExists(filename_base))
5801 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5803 filename_local = getCustomArtworkConfigFilename(type);
5806 printf("::: filename_local == '%s'\n", filename_local);
5809 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5810 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5813 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5816 return redefined_ce_found;
5819 static void InitOverrideArtwork()
5821 boolean redefined_ce_found = FALSE;
5823 /* to check if this level set redefines any CEs, do not use overriding */
5824 gfx.override_level_graphics = FALSE;
5825 gfx.override_level_sounds = FALSE;
5826 gfx.override_level_music = FALSE;
5828 /* now check if this level set has definitions for custom elements */
5829 if (setup.override_level_graphics == AUTO ||
5830 setup.override_level_sounds == AUTO ||
5831 setup.override_level_music == AUTO)
5832 redefined_ce_found =
5833 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5834 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5835 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5838 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5841 if (redefined_ce_found)
5843 /* this level set has CE definitions: change "AUTO" to "FALSE" */
5844 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5845 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
5846 gfx.override_level_music = (setup.override_level_music == TRUE);
5850 /* this level set has no CE definitions: change "AUTO" to "TRUE" */
5851 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5852 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
5853 gfx.override_level_music = (setup.override_level_music != FALSE);
5857 printf("::: => %d, %d, %d\n",
5858 gfx.override_level_graphics,
5859 gfx.override_level_sounds,
5860 gfx.override_level_music);
5864 static char *getNewArtworkIdentifier(int type)
5866 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5867 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5868 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5869 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5870 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5872 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5874 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
5876 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5877 char *leveldir_identifier = leveldir_current->identifier;
5879 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
5880 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5882 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
5884 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5885 char *artwork_current_identifier;
5886 char *artwork_new_identifier = NULL; /* default: nothing has changed */
5888 /* leveldir_current may be invalid (level group, parent link) */
5889 if (!validLevelSeries(leveldir_current))
5892 /* 1st step: determine artwork set to be activated in descending order:
5893 --------------------------------------------------------------------
5894 1. setup artwork (when configured to override everything else)
5895 2. artwork set configured in "levelinfo.conf" of current level set
5896 (artwork in level directory will have priority when loading later)
5897 3. artwork in level directory (stored in artwork sub-directory)
5898 4. setup artwork (currently configured in setup menu) */
5900 if (setup_override_artwork)
5901 artwork_current_identifier = setup_artwork_set;
5902 else if (leveldir_artwork_set != NULL)
5903 artwork_current_identifier = leveldir_artwork_set;
5904 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5905 artwork_current_identifier = leveldir_identifier;
5907 artwork_current_identifier = setup_artwork_set;
5910 /* 2nd step: check if it is really needed to reload artwork set
5911 ------------------------------------------------------------ */
5914 if (type == ARTWORK_TYPE_GRAPHICS)
5915 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
5916 artwork_new_identifier,
5917 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5918 artwork_current_identifier,
5919 leveldir_current->graphics_set,
5920 leveldir_current->identifier);
5923 /* ---------- reload if level set and also artwork set has changed ------- */
5924 if (leveldir_current_identifier[type] != leveldir_identifier &&
5925 (last_has_level_artwork_set[type] || has_level_artwork_set))
5926 artwork_new_identifier = artwork_current_identifier;
5928 leveldir_current_identifier[type] = leveldir_identifier;
5929 last_has_level_artwork_set[type] = has_level_artwork_set;
5932 if (type == ARTWORK_TYPE_GRAPHICS)
5933 printf("::: 1: '%s'\n", artwork_new_identifier);
5936 /* ---------- reload if "override artwork" setting has changed ----------- */
5937 if (last_override_level_artwork[type] != setup_override_artwork)
5938 artwork_new_identifier = artwork_current_identifier;
5940 last_override_level_artwork[type] = setup_override_artwork;
5943 if (type == ARTWORK_TYPE_GRAPHICS)
5944 printf("::: 2: '%s'\n", artwork_new_identifier);
5947 /* ---------- reload if current artwork identifier has changed ----------- */
5948 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5949 artwork_current_identifier))
5950 artwork_new_identifier = artwork_current_identifier;
5952 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5955 if (type == ARTWORK_TYPE_GRAPHICS)
5956 printf("::: 3: '%s'\n", artwork_new_identifier);
5959 /* ---------- do not reload directly after starting ---------------------- */
5960 if (!initialized[type])
5961 artwork_new_identifier = NULL;
5963 initialized[type] = TRUE;
5966 if (type == ARTWORK_TYPE_GRAPHICS)
5967 printf("::: 4: '%s'\n", artwork_new_identifier);
5971 if (type == ARTWORK_TYPE_GRAPHICS)
5972 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
5973 artwork.gfx_current_identifier, artwork_current_identifier,
5974 artwork.gfx_current->identifier, leveldir_current->graphics_set,
5975 artwork_new_identifier);
5978 return artwork_new_identifier;
5981 void ReloadCustomArtwork(int force_reload)
5983 int last_game_status = game_status; /* save current game status */
5984 char *gfx_new_identifier;
5985 char *snd_new_identifier;
5986 char *mus_new_identifier;
5987 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5988 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5989 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5990 boolean reload_needed;
5992 InitOverrideArtwork();
5994 force_reload_gfx |= AdjustGraphicsForEMC();
5996 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5997 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5998 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
6000 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
6001 snd_new_identifier != NULL || force_reload_snd ||
6002 mus_new_identifier != NULL || force_reload_mus);
6007 print_timestamp_init("ReloadCustomArtwork");
6009 game_status = GAME_MODE_LOADING;
6011 FadeOut(REDRAW_ALL);
6014 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6016 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
6018 print_timestamp_time("ClearRectangle");
6021 printf("::: fading in ... %d\n", fading.fade_mode);
6025 printf("::: done\n");
6028 if (gfx_new_identifier != NULL || force_reload_gfx)
6031 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
6032 artwork.gfx_current_identifier,
6034 artwork.gfx_current->identifier,
6035 leveldir_current->graphics_set);
6039 print_timestamp_time("InitImages");
6042 if (snd_new_identifier != NULL || force_reload_snd)
6044 InitSound(snd_new_identifier);
6045 print_timestamp_time("InitSound");
6048 if (mus_new_identifier != NULL || force_reload_mus)
6050 InitMusic(mus_new_identifier);
6051 print_timestamp_time("InitMusic");
6054 game_status = last_game_status; /* restore current game status */
6057 printf("::: ----------------DELAY 1 ...\n");
6062 printf("::: FadeOut @ ReloadCustomArtwork ...\n");
6064 FadeOut(REDRAW_ALL);
6066 printf("::: FadeOut @ ReloadCustomArtwork done\n");
6071 /* force redraw of (open or closed) door graphics */
6072 SetDoorState(DOOR_OPEN_ALL);
6073 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
6078 FadeSetEnterScreen();
6079 FadeSkipNextFadeOut();
6080 // FadeSetDisabled();
6085 fading = fading_none;
6090 redraw_mask = REDRAW_ALL;
6093 print_timestamp_done("ReloadCustomArtwork");
6096 void KeyboardAutoRepeatOffUnlessAutoplay()
6098 if (global.autoplay_leveldir == NULL)
6099 KeyboardAutoRepeatOff();
6103 /* ========================================================================= */
6105 /* ========================================================================= */
6109 print_timestamp_init("OpenAll");
6111 game_status = GAME_MODE_LOADING;
6113 InitGlobal(); /* initialize some global variables */
6115 if (options.execute_command)
6116 Execute_Command(options.execute_command);
6118 if (options.serveronly)
6120 #if defined(PLATFORM_UNIX)
6121 NetworkServer(options.server_port, options.serveronly);
6123 Error(ERR_WARN, "networking only supported in Unix version");
6126 exit(0); /* never reached, server loops forever */
6133 InitArtworkInfo(); /* needed before loading gfx, sound & music */
6134 InitArtworkConfig(); /* needed before forking sound child process */
6139 InitRND(NEW_RANDOMIZE);
6140 InitSimpleRandom(NEW_RANDOMIZE);
6144 print_timestamp_time("[pre-video]");
6147 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
6149 InitEventFilter(FilterMouseMotionEvents);
6151 InitElementPropertiesStatic();
6152 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
6154 print_timestamp_time("[post-video]");
6158 print_timestamp_time("InitGfx");
6161 print_timestamp_time("InitLevelInfo");
6163 InitLevelArtworkInfo();
6164 print_timestamp_time("InitLevelArtworkInfo");
6166 InitOverrideArtwork(); /* needs to know current level directory */
6167 print_timestamp_time("InitOverrideArtwork");
6169 InitImages(); /* needs to know current level directory */
6170 print_timestamp_time("InitImages");
6172 InitSound(NULL); /* needs to know current level directory */
6173 print_timestamp_time("InitSound");
6175 InitMusic(NULL); /* needs to know current level directory */
6176 print_timestamp_time("InitMusic");
6178 InitGfxBackground();
6184 if (global.autoplay_leveldir)
6189 else if (global.convert_leveldir)
6194 else if (global.create_images_dir)
6196 CreateLevelSketchImages();
6200 game_status = GAME_MODE_MAIN;
6203 FadeSetEnterScreen();
6204 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
6205 FadeSkipNextFadeOut();
6206 // FadeSetDisabled();
6208 fading = fading_none;
6211 print_timestamp_time("[post-artwork]");
6213 print_timestamp_done("OpenAll");
6217 InitNetworkServer();
6220 void CloseAllAndExit(int exit_value)
6225 CloseAudio(); /* called after freeing sounds (needed for SDL) */
6233 #if defined(TARGET_SDL)
6234 if (network_server) /* terminate network server */
6235 SDL_KillThread(server_thread);
6238 CloseVideoDisplay();
6239 ClosePlatformDependentStuff();
6241 if (exit_value != 0)
6242 NotifyUserAboutErrorFile();