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;
4980 global.frames_per_second = 0;
4981 global.fps_slowdown = FALSE;
4982 global.fps_slowdown_factor = 1;
4984 global.border_status = GAME_MODE_MAIN;
4986 global.fading_status = GAME_MODE_MAIN;
4987 global.fading_type = TYPE_ENTER_MENU;
4991 void Execute_Command(char *command)
4995 if (strEqual(command, "print graphicsinfo.conf"))
4997 printf("# You can configure additional/alternative image files here.\n");
4998 printf("# (The entries below are default and therefore commented out.)\n");
5000 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
5002 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5005 for (i = 0; image_config[i].token != NULL; i++)
5006 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
5007 image_config[i].value));
5011 else if (strEqual(command, "print soundsinfo.conf"))
5013 printf("# You can configure additional/alternative sound files here.\n");
5014 printf("# (The entries below are default and therefore commented out.)\n");
5016 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
5018 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5021 for (i = 0; sound_config[i].token != NULL; i++)
5022 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
5023 sound_config[i].value));
5027 else if (strEqual(command, "print musicinfo.conf"))
5029 printf("# You can configure additional/alternative music files here.\n");
5030 printf("# (The entries below are default and therefore commented out.)\n");
5032 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
5034 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5037 for (i = 0; music_config[i].token != NULL; i++)
5038 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
5039 music_config[i].value));
5043 else if (strEqual(command, "print editorsetup.conf"))
5045 printf("# You can configure your personal editor element list here.\n");
5046 printf("# (The entries below are default and therefore commented out.)\n");
5049 /* this is needed to be able to check element list for cascade elements */
5050 InitElementPropertiesStatic();
5051 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5053 PrintEditorElementList();
5057 else if (strEqual(command, "print helpanim.conf"))
5059 printf("# You can configure different element help animations here.\n");
5060 printf("# (The entries below are default and therefore commented out.)\n");
5063 for (i = 0; helpanim_config[i].token != NULL; i++)
5065 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
5066 helpanim_config[i].value));
5068 if (strEqual(helpanim_config[i].token, "end"))
5074 else if (strEqual(command, "print helptext.conf"))
5076 printf("# You can configure different element help text here.\n");
5077 printf("# (The entries below are default and therefore commented out.)\n");
5080 for (i = 0; helptext_config[i].token != NULL; i++)
5081 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
5082 helptext_config[i].value));
5086 else if (strncmp(command, "dump level ", 11) == 0)
5088 char *filename = &command[11];
5090 if (!fileExists(filename))
5091 Error(ERR_EXIT, "cannot open file '%s'", filename);
5093 LoadLevelFromFilename(&level, filename);
5098 else if (strncmp(command, "dump tape ", 10) == 0)
5100 char *filename = &command[10];
5102 if (!fileExists(filename))
5103 Error(ERR_EXIT, "cannot open file '%s'", filename);
5105 LoadTapeFromFilename(filename);
5110 else if (strncmp(command, "autoplay ", 9) == 0)
5112 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
5114 while (*str_ptr != '\0') /* continue parsing string */
5116 /* cut leading whitespace from string, replace it by string terminator */
5117 while (*str_ptr == ' ' || *str_ptr == '\t')
5120 if (*str_ptr == '\0') /* end of string reached */
5123 if (global.autoplay_leveldir == NULL) /* read level set string */
5125 global.autoplay_leveldir = str_ptr;
5126 global.autoplay_all = TRUE; /* default: play all tapes */
5128 for (i = 0; i < MAX_TAPES_PER_SET; i++)
5129 global.autoplay_level[i] = FALSE;
5131 else /* read level number string */
5133 int level_nr = atoi(str_ptr); /* get level_nr value */
5135 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5136 global.autoplay_level[level_nr] = TRUE;
5138 global.autoplay_all = FALSE;
5141 /* advance string pointer to the next whitespace (or end of string) */
5142 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5146 else if (strncmp(command, "convert ", 8) == 0)
5148 char *str_copy = getStringCopy(&command[8]);
5149 char *str_ptr = strchr(str_copy, ' ');
5151 global.convert_leveldir = str_copy;
5152 global.convert_level_nr = -1;
5154 if (str_ptr != NULL) /* level number follows */
5156 *str_ptr++ = '\0'; /* terminate leveldir string */
5157 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
5162 #if defined(TARGET_SDL)
5163 else if (strEqual(command, "SDL_ListModes"))
5168 SDL_Init(SDL_INIT_VIDEO);
5170 /* get available fullscreen/hardware modes */
5171 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
5173 /* check if there are any modes available */
5176 printf("No modes available!\n");
5181 /* check if our resolution is restricted */
5182 if (modes == (SDL_Rect **)-1)
5184 printf("All resolutions available.\n");
5188 printf("Available Modes:\n");
5190 for(i = 0; modes[i]; i++)
5191 printf(" %d x %d\n", modes[i]->w, modes[i]->h);
5201 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
5205 static void InitSetup()
5207 LoadSetup(); /* global setup info */
5209 /* set some options from setup file */
5211 if (setup.options.verbose)
5212 options.verbose = TRUE;
5215 static void InitGameInfo()
5217 game.restart_level = FALSE;
5220 static void InitPlayerInfo()
5224 /* choose default local player */
5225 local_player = &stored_player[0];
5227 for (i = 0; i < MAX_PLAYERS; i++)
5228 stored_player[i].connected = FALSE;
5230 local_player->connected = TRUE;
5233 static void InitArtworkInfo()
5238 static char *get_string_in_brackets(char *string)
5240 char *string_in_brackets = checked_malloc(strlen(string) + 3);
5242 sprintf(string_in_brackets, "[%s]", string);
5244 return string_in_brackets;
5247 static char *get_level_id_suffix(int id_nr)
5249 char *id_suffix = checked_malloc(1 + 3 + 1);
5251 if (id_nr < 0 || id_nr > 999)
5254 sprintf(id_suffix, ".%03d", id_nr);
5260 static char *get_element_class_token(int element)
5262 char *element_class_name = element_info[element].class_name;
5263 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
5265 sprintf(element_class_token, "[%s]", element_class_name);
5267 return element_class_token;
5270 static char *get_action_class_token(int action)
5272 char *action_class_name = &element_action_info[action].suffix[1];
5273 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
5275 sprintf(action_class_token, "[%s]", action_class_name);
5277 return action_class_token;
5281 static void InitArtworkConfig()
5283 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
5284 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
5285 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
5286 static char *action_id_suffix[NUM_ACTIONS + 1];
5287 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5288 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5289 static char *level_id_suffix[MAX_LEVELS + 1];
5290 static char *dummy[1] = { NULL };
5291 static char *ignore_generic_tokens[] =
5297 static char **ignore_image_tokens;
5298 static char **ignore_sound_tokens;
5299 static char **ignore_music_tokens;
5300 int num_ignore_generic_tokens;
5301 int num_ignore_image_tokens;
5302 int num_ignore_sound_tokens;
5303 int num_ignore_music_tokens;
5306 /* dynamically determine list of generic tokens to be ignored */
5307 num_ignore_generic_tokens = 0;
5308 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5309 num_ignore_generic_tokens++;
5311 /* dynamically determine list of image tokens to be ignored */
5312 num_ignore_image_tokens = num_ignore_generic_tokens;
5313 for (i = 0; image_config_vars[i].token != NULL; i++)
5314 num_ignore_image_tokens++;
5315 ignore_image_tokens =
5316 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5317 for (i = 0; i < num_ignore_generic_tokens; i++)
5318 ignore_image_tokens[i] = ignore_generic_tokens[i];
5319 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5320 ignore_image_tokens[num_ignore_generic_tokens + i] =
5321 image_config_vars[i].token;
5322 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5324 /* dynamically determine list of sound tokens to be ignored */
5325 num_ignore_sound_tokens = num_ignore_generic_tokens;
5326 ignore_sound_tokens =
5327 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5328 for (i = 0; i < num_ignore_generic_tokens; i++)
5329 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5330 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5332 /* dynamically determine list of music tokens to be ignored */
5333 num_ignore_music_tokens = num_ignore_generic_tokens;
5334 ignore_music_tokens =
5335 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5336 for (i = 0; i < num_ignore_generic_tokens; i++)
5337 ignore_music_tokens[i] = ignore_generic_tokens[i];
5338 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5340 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5341 image_id_prefix[i] = element_info[i].token_name;
5342 for (i = 0; i < NUM_FONTS; i++)
5343 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5344 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
5346 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5347 sound_id_prefix[i] = element_info[i].token_name;
5348 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5349 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5350 get_string_in_brackets(element_info[i].class_name);
5351 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
5353 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5354 music_id_prefix[i] = music_prefix_info[i].prefix;
5355 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
5357 for (i = 0; i < NUM_ACTIONS; i++)
5358 action_id_suffix[i] = element_action_info[i].suffix;
5359 action_id_suffix[NUM_ACTIONS] = NULL;
5361 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5362 direction_id_suffix[i] = element_direction_info[i].suffix;
5363 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5365 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5366 special_id_suffix[i] = special_suffix_info[i].suffix;
5367 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5369 for (i = 0; i < MAX_LEVELS; i++)
5370 level_id_suffix[i] = get_level_id_suffix(i);
5371 level_id_suffix[MAX_LEVELS] = NULL;
5373 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5374 image_id_prefix, action_id_suffix, direction_id_suffix,
5375 special_id_suffix, ignore_image_tokens);
5376 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5377 sound_id_prefix, action_id_suffix, dummy,
5378 special_id_suffix, ignore_sound_tokens);
5379 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5380 music_id_prefix, special_id_suffix, level_id_suffix,
5381 dummy, ignore_music_tokens);
5384 static void InitMixer()
5393 struct GraphicInfo *graphic_info_last = graphic_info;
5394 char *filename_font_initial = NULL;
5395 char *filename_anim_initial = NULL;
5396 Bitmap *bitmap_font_initial = NULL;
5400 /* determine settings for initial font (for displaying startup messages) */
5401 for (i = 0; image_config[i].token != NULL; i++)
5403 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5405 char font_token[128];
5408 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5409 len_font_token = strlen(font_token);
5411 if (strEqual(image_config[i].token, font_token))
5412 filename_font_initial = image_config[i].value;
5413 else if (strlen(image_config[i].token) > len_font_token &&
5414 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5416 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5417 font_initial[j].src_x = atoi(image_config[i].value);
5418 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5419 font_initial[j].src_y = atoi(image_config[i].value);
5420 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5421 font_initial[j].width = atoi(image_config[i].value);
5422 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5423 font_initial[j].height = atoi(image_config[i].value);
5428 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5430 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5431 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5434 if (filename_font_initial == NULL) /* should not happen */
5435 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5437 /* create additional image buffers for double-buffering and cross-fading */
5438 bitmap_db_cross = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5439 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
5440 bitmap_db_panel = CreateBitmap(DXSIZE, DYSIZE, DEFAULT_DEPTH);
5441 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
5442 bitmap_db_toons = CreateBitmap(FULL_SXSIZE, FULL_SYSIZE, DEFAULT_DEPTH);
5444 /* initialize screen properties */
5445 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5446 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5448 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5449 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5450 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5451 InitGfxCustomArtworkInfo();
5453 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5455 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5456 font_initial[j].bitmap = bitmap_font_initial;
5458 InitFontGraphicInfo();
5460 font_height = getFontHeight(FC_RED);
5463 DrawInitText(getWindowTitleString(), 20, FC_YELLOW);
5465 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
5467 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
5468 DrawInitText(PROGRAM_WEBSITE_STRING, WIN_YSIZE - 20 - font_height, FC_RED);
5470 DrawInitText("Loading graphics", 120, FC_GREEN);
5474 /* initialize busy animation with default values */
5475 int parameter[NUM_GFX_ARGS];
5476 for (i = 0; i < NUM_GFX_ARGS; i++)
5477 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5478 image_config_suffix[i].token,
5479 image_config_suffix[i].type);
5481 for (i = 0; i < NUM_GFX_ARGS; i++)
5482 printf("::: '%s' => %d\n", image_config_suffix[i].token, parameter[i]);
5486 /* determine settings for busy animation (when displaying startup messages) */
5487 for (i = 0; image_config[i].token != NULL; i++)
5489 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5490 int len_anim_token = strlen(anim_token);
5492 if (strEqual(image_config[i].token, anim_token))
5493 filename_anim_initial = image_config[i].value;
5494 else if (strlen(image_config[i].token) > len_anim_token &&
5495 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5498 for (j = 0; image_config_suffix[j].token != NULL; j++)
5500 if (strEqual(&image_config[i].token[len_anim_token],
5501 image_config_suffix[j].token))
5503 get_graphic_parameter_value(image_config[i].value,
5504 image_config_suffix[j].token,
5505 image_config_suffix[j].type);
5508 if (strEqual(&image_config[i].token[len_anim_token], ".x"))
5509 anim_initial.src_x = atoi(image_config[i].value);
5510 else if (strEqual(&image_config[i].token[len_anim_token], ".y"))
5511 anim_initial.src_y = atoi(image_config[i].value);
5512 else if (strEqual(&image_config[i].token[len_anim_token], ".width"))
5513 anim_initial.width = atoi(image_config[i].value);
5514 else if (strEqual(&image_config[i].token[len_anim_token], ".height"))
5515 anim_initial.height = atoi(image_config[i].value);
5516 else if (strEqual(&image_config[i].token[len_anim_token], ".frames"))
5517 anim_initial.anim_frames = atoi(image_config[i].value);
5518 else if (strEqual(&image_config[i].token[len_anim_token],
5519 ".frames_per_line"))
5520 anim_initial.anim_frames_per_line = atoi(image_config[i].value);
5521 else if (strEqual(&image_config[i].token[len_anim_token], ".delay"))
5522 anim_initial.anim_delay = atoi(image_config[i].value);
5527 #if defined(CREATE_SPECIAL_EDITION_RND_JUE)
5528 filename_anim_initial = "loading.pcx";
5530 parameter[GFX_ARG_X] = 0;
5531 parameter[GFX_ARG_Y] = 0;
5532 parameter[GFX_ARG_WIDTH] = 128;
5533 parameter[GFX_ARG_HEIGHT] = 40;
5534 parameter[GFX_ARG_FRAMES] = 32;
5535 parameter[GFX_ARG_DELAY] = 4;
5536 parameter[GFX_ARG_FRAMES_PER_LINE] = ARG_UNDEFINED_VALUE;
5539 if (filename_anim_initial == NULL) /* should not happen */
5540 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5542 anim_initial.bitmap = LoadCustomImage(filename_anim_initial);
5544 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
5546 set_graphic_parameters_ext(0, parameter, anim_initial.bitmap);
5549 printf("::: INIT_GFX: anim_frames_per_line == %d [%d / %d] [%d, %d]\n",
5550 graphic_info[0].anim_frames_per_line,
5551 get_scaled_graphic_width(0),
5552 graphic_info[0].width,
5553 getOriginalImageWidthFromImageID(0),
5554 graphic_info[0].scale_up_factor);
5557 graphic_info = graphic_info_last;
5559 init.busy.width = anim_initial.width;
5560 init.busy.height = anim_initial.height;
5562 InitMenuDesignSettings_Static();
5563 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5567 void RedrawBackground()
5569 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
5570 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
5572 redraw_mask = REDRAW_ALL;
5575 void InitGfxBackground()
5579 fieldbuffer = bitmap_db_field;
5580 SetDrawtoField(DRAW_BACKBUFFER);
5583 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5587 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
5588 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
5591 for (x = 0; x < MAX_BUF_XSIZE; x++)
5592 for (y = 0; y < MAX_BUF_YSIZE; y++)
5595 redraw_mask = REDRAW_ALL;
5598 static void InitLevelInfo()
5600 LoadLevelInfo(); /* global level info */
5601 LoadLevelSetup_LastSeries(); /* last played series info */
5602 LoadLevelSetup_SeriesInfo(); /* last played level info */
5605 static void InitLevelArtworkInfo()
5607 LoadLevelArtworkInfo();
5610 static void InitImages()
5612 print_timestamp_init("InitImages");
5615 printf("::: leveldir_current->identifier == '%s'\n",
5616 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5617 printf("::: leveldir_current->graphics_path == '%s'\n",
5618 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5619 printf("::: leveldir_current->graphics_set == '%s'\n",
5620 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5621 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5622 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5625 setLevelArtworkDir(artwork.gfx_first);
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));
5639 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5640 leveldir_current->identifier,
5641 artwork.gfx_current_identifier,
5642 artwork.gfx_current->identifier,
5643 leveldir_current->graphics_set,
5644 leveldir_current->graphics_path);
5647 UPDATE_BUSY_STATE();
5649 ReloadCustomImages();
5650 print_timestamp_time("ReloadCustomImages");
5652 UPDATE_BUSY_STATE();
5654 LoadCustomElementDescriptions();
5655 print_timestamp_time("LoadCustomElementDescriptions");
5657 UPDATE_BUSY_STATE();
5659 LoadMenuDesignSettings();
5660 print_timestamp_time("LoadMenuDesignSettings");
5662 UPDATE_BUSY_STATE();
5664 ReinitializeGraphics();
5665 print_timestamp_time("ReinitializeGraphics");
5667 UPDATE_BUSY_STATE();
5669 print_timestamp_done("InitImages");
5672 static void InitSound(char *identifier)
5674 print_timestamp_init("InitSound");
5676 if (identifier == NULL)
5677 identifier = artwork.snd_current->identifier;
5679 /* set artwork path to send it to the sound server process */
5680 setLevelArtworkDir(artwork.snd_first);
5682 InitReloadCustomSounds(identifier);
5683 print_timestamp_time("InitReloadCustomSounds");
5685 ReinitializeSounds();
5686 print_timestamp_time("ReinitializeSounds");
5688 print_timestamp_done("InitSound");
5691 static void InitMusic(char *identifier)
5693 print_timestamp_init("InitMusic");
5695 if (identifier == NULL)
5696 identifier = artwork.mus_current->identifier;
5698 /* set artwork path to send it to the sound server process */
5699 setLevelArtworkDir(artwork.mus_first);
5701 InitReloadCustomMusic(identifier);
5702 print_timestamp_time("InitReloadCustomMusic");
5704 ReinitializeMusic();
5705 print_timestamp_time("ReinitializeMusic");
5707 print_timestamp_done("InitMusic");
5710 void InitNetworkServer()
5712 #if defined(NETWORK_AVALIABLE)
5716 if (!options.network)
5719 #if defined(NETWORK_AVALIABLE)
5720 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5722 if (!ConnectToServer(options.server_host, options.server_port))
5723 Error(ERR_EXIT, "cannot connect to network game server");
5725 SendToServer_PlayerName(setup.player_name);
5726 SendToServer_ProtocolVersion();
5729 SendToServer_NrWanted(nr_wanted);
5733 static boolean CheckArtworkConfigForCustomElements(char *filename)
5735 SetupFileHash *setup_file_hash;
5736 boolean redefined_ce_found = FALSE;
5738 /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */
5740 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5742 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5744 char *token = HASH_ITERATION_TOKEN(itr);
5746 if (strPrefix(token, "custom_"))
5748 redefined_ce_found = TRUE;
5753 END_HASH_ITERATION(setup_file_hash, itr)
5755 freeSetupFileHash(setup_file_hash);
5758 return redefined_ce_found;
5761 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5763 char *filename_base, *filename_local;
5764 boolean redefined_ce_found = FALSE;
5766 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5769 printf("::: leveldir_current->identifier == '%s'\n",
5770 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5771 printf("::: leveldir_current->graphics_path == '%s'\n",
5772 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5773 printf("::: leveldir_current->graphics_set == '%s'\n",
5774 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5775 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5776 leveldir_current == NULL ? "[NULL]" :
5777 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5780 /* first look for special artwork configured in level series config */
5781 filename_base = getCustomArtworkLevelConfigFilename(type);
5784 printf("::: filename_base == '%s'\n", filename_base);
5787 if (fileExists(filename_base))
5788 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5790 filename_local = getCustomArtworkConfigFilename(type);
5793 printf("::: filename_local == '%s'\n", filename_local);
5796 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5797 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5800 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5803 return redefined_ce_found;
5806 static void InitOverrideArtwork()
5808 boolean redefined_ce_found = FALSE;
5810 /* to check if this level set redefines any CEs, do not use overriding */
5811 gfx.override_level_graphics = FALSE;
5812 gfx.override_level_sounds = FALSE;
5813 gfx.override_level_music = FALSE;
5815 /* now check if this level set has definitions for custom elements */
5816 if (setup.override_level_graphics == AUTO ||
5817 setup.override_level_sounds == AUTO ||
5818 setup.override_level_music == AUTO)
5819 redefined_ce_found =
5820 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5821 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5822 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5825 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5828 if (redefined_ce_found)
5830 /* this level set has CE definitions: change "AUTO" to "FALSE" */
5831 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5832 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
5833 gfx.override_level_music = (setup.override_level_music == TRUE);
5837 /* this level set has no CE definitions: change "AUTO" to "TRUE" */
5838 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5839 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
5840 gfx.override_level_music = (setup.override_level_music != FALSE);
5844 printf("::: => %d, %d, %d\n",
5845 gfx.override_level_graphics,
5846 gfx.override_level_sounds,
5847 gfx.override_level_music);
5851 static char *getNewArtworkIdentifier(int type)
5853 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5854 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5855 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5856 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5857 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5859 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5861 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
5863 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5864 char *leveldir_identifier = leveldir_current->identifier;
5866 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
5867 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5869 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
5871 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5872 char *artwork_current_identifier;
5873 char *artwork_new_identifier = NULL; /* default: nothing has changed */
5875 /* leveldir_current may be invalid (level group, parent link) */
5876 if (!validLevelSeries(leveldir_current))
5879 /* 1st step: determine artwork set to be activated in descending order:
5880 --------------------------------------------------------------------
5881 1. setup artwork (when configured to override everything else)
5882 2. artwork set configured in "levelinfo.conf" of current level set
5883 (artwork in level directory will have priority when loading later)
5884 3. artwork in level directory (stored in artwork sub-directory)
5885 4. setup artwork (currently configured in setup menu) */
5887 if (setup_override_artwork)
5888 artwork_current_identifier = setup_artwork_set;
5889 else if (leveldir_artwork_set != NULL)
5890 artwork_current_identifier = leveldir_artwork_set;
5891 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5892 artwork_current_identifier = leveldir_identifier;
5894 artwork_current_identifier = setup_artwork_set;
5897 /* 2nd step: check if it is really needed to reload artwork set
5898 ------------------------------------------------------------ */
5901 if (type == ARTWORK_TYPE_GRAPHICS)
5902 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
5903 artwork_new_identifier,
5904 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5905 artwork_current_identifier,
5906 leveldir_current->graphics_set,
5907 leveldir_current->identifier);
5910 /* ---------- reload if level set and also artwork set has changed ------- */
5911 if (leveldir_current_identifier[type] != leveldir_identifier &&
5912 (last_has_level_artwork_set[type] || has_level_artwork_set))
5913 artwork_new_identifier = artwork_current_identifier;
5915 leveldir_current_identifier[type] = leveldir_identifier;
5916 last_has_level_artwork_set[type] = has_level_artwork_set;
5919 if (type == ARTWORK_TYPE_GRAPHICS)
5920 printf("::: 1: '%s'\n", artwork_new_identifier);
5923 /* ---------- reload if "override artwork" setting has changed ----------- */
5924 if (last_override_level_artwork[type] != setup_override_artwork)
5925 artwork_new_identifier = artwork_current_identifier;
5927 last_override_level_artwork[type] = setup_override_artwork;
5930 if (type == ARTWORK_TYPE_GRAPHICS)
5931 printf("::: 2: '%s'\n", artwork_new_identifier);
5934 /* ---------- reload if current artwork identifier has changed ----------- */
5935 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5936 artwork_current_identifier))
5937 artwork_new_identifier = artwork_current_identifier;
5939 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5942 if (type == ARTWORK_TYPE_GRAPHICS)
5943 printf("::: 3: '%s'\n", artwork_new_identifier);
5946 /* ---------- do not reload directly after starting ---------------------- */
5947 if (!initialized[type])
5948 artwork_new_identifier = NULL;
5950 initialized[type] = TRUE;
5953 if (type == ARTWORK_TYPE_GRAPHICS)
5954 printf("::: 4: '%s'\n", artwork_new_identifier);
5958 if (type == ARTWORK_TYPE_GRAPHICS)
5959 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
5960 artwork.gfx_current_identifier, artwork_current_identifier,
5961 artwork.gfx_current->identifier, leveldir_current->graphics_set,
5962 artwork_new_identifier);
5965 return artwork_new_identifier;
5968 void ReloadCustomArtwork(int force_reload)
5970 int last_game_status = game_status; /* save current game status */
5971 char *gfx_new_identifier;
5972 char *snd_new_identifier;
5973 char *mus_new_identifier;
5974 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5975 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5976 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5977 boolean reload_needed;
5979 InitOverrideArtwork();
5981 force_reload_gfx |= AdjustGraphicsForEMC();
5983 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5984 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5985 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5987 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
5988 snd_new_identifier != NULL || force_reload_snd ||
5989 mus_new_identifier != NULL || force_reload_mus);
5994 print_timestamp_init("ReloadCustomArtwork");
5996 game_status = GAME_MODE_LOADING;
5998 FadeOut(REDRAW_ALL);
6001 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6003 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
6005 print_timestamp_time("ClearRectangle");
6008 printf("::: fading in ... %d\n", fading.fade_mode);
6012 printf("::: done\n");
6015 if (gfx_new_identifier != NULL || force_reload_gfx)
6018 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
6019 artwork.gfx_current_identifier,
6021 artwork.gfx_current->identifier,
6022 leveldir_current->graphics_set);
6026 print_timestamp_time("InitImages");
6029 if (snd_new_identifier != NULL || force_reload_snd)
6031 InitSound(snd_new_identifier);
6032 print_timestamp_time("InitSound");
6035 if (mus_new_identifier != NULL || force_reload_mus)
6037 InitMusic(mus_new_identifier);
6038 print_timestamp_time("InitMusic");
6041 game_status = last_game_status; /* restore current game status */
6044 printf("::: ----------------DELAY 1 ...\n");
6049 printf("::: FadeOut @ ReloadCustomArtwork ...\n");
6051 FadeOut(REDRAW_ALL);
6053 printf("::: FadeOut @ ReloadCustomArtwork done\n");
6058 /* force redraw of (open or closed) door graphics */
6059 SetDoorState(DOOR_OPEN_ALL);
6060 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
6065 FadeSetEnterScreen();
6066 FadeSkipNextFadeOut();
6067 // FadeSetDisabled();
6072 fading = fading_none;
6077 redraw_mask = REDRAW_ALL;
6080 print_timestamp_done("ReloadCustomArtwork");
6083 void KeyboardAutoRepeatOffUnlessAutoplay()
6085 if (global.autoplay_leveldir == NULL)
6086 KeyboardAutoRepeatOff();
6090 /* ========================================================================= */
6092 /* ========================================================================= */
6096 print_timestamp_init("OpenAll");
6098 game_status = GAME_MODE_LOADING;
6100 InitGlobal(); /* initialize some global variables */
6102 if (options.execute_command)
6103 Execute_Command(options.execute_command);
6105 if (options.serveronly)
6107 #if defined(PLATFORM_UNIX)
6108 NetworkServer(options.server_port, options.serveronly);
6110 Error(ERR_WARN, "networking only supported in Unix version");
6113 exit(0); /* never reached, server loops forever */
6120 InitArtworkInfo(); /* needed before loading gfx, sound & music */
6121 InitArtworkConfig(); /* needed before forking sound child process */
6126 InitRND(NEW_RANDOMIZE);
6127 InitSimpleRandom(NEW_RANDOMIZE);
6131 print_timestamp_time("[pre-video]");
6134 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
6136 InitEventFilter(FilterMouseMotionEvents);
6138 InitElementPropertiesStatic();
6139 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
6141 print_timestamp_time("[post-video]");
6145 print_timestamp_time("InitGfx");
6148 print_timestamp_time("InitLevelInfo");
6150 InitLevelArtworkInfo();
6151 print_timestamp_time("InitLevelArtworkInfo");
6153 InitOverrideArtwork(); /* needs to know current level directory */
6154 print_timestamp_time("InitOverrideArtwork");
6156 InitImages(); /* needs to know current level directory */
6157 print_timestamp_time("InitImages");
6159 InitSound(NULL); /* needs to know current level directory */
6160 print_timestamp_time("InitSound");
6162 InitMusic(NULL); /* needs to know current level directory */
6163 print_timestamp_time("InitMusic");
6165 InitGfxBackground();
6171 if (global.autoplay_leveldir)
6176 else if (global.convert_leveldir)
6182 game_status = GAME_MODE_MAIN;
6185 FadeSetEnterScreen();
6186 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
6187 FadeSkipNextFadeOut();
6188 // FadeSetDisabled();
6190 fading = fading_none;
6193 print_timestamp_time("[post-artwork]");
6195 print_timestamp_done("OpenAll");
6199 InitNetworkServer();
6202 void CloseAllAndExit(int exit_value)
6207 CloseAudio(); /* called after freeing sounds (needed for SDL) */
6215 #if defined(TARGET_SDL)
6216 if (network_server) /* terminate network server */
6217 SDL_KillThread(server_thread);
6220 CloseVideoDisplay();
6221 ClosePlatformDependentStuff();
6223 if (exit_value != 0)
6224 NotifyUserAboutErrorFile();