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;
189 x = ALIGNED_TEXT_XPOS(&init_last.busy);
190 y = ALIGNED_TEXT_YPOS(&init_last.busy);
192 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
196 static boolean done = FALSE;
199 printf("::: %d, %d, %d, %d => %d, %d [%d, %d] [%d, %d]\n",
200 init.busy.x, init.busy.y,
201 init.busy.align, init.busy.valign,
203 graphic_info[graphic].width,
204 graphic_info[graphic].height,
205 sync_frame, anim_initial.anim_delay);
211 if (sync_frame % anim_initial.anim_delay == 0)
216 int width = graphic_info[graphic].width;
217 int height = graphic_info[graphic].height;
218 int frame = getGraphicAnimationFrame(graphic, sync_frame);
220 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
221 BlitBitmap(src_bitmap, window, src_x, src_y, width, height, x, y);
223 /* !!! this can only draw TILEX/TILEY size animations !!! */
224 DrawGraphicAnimationExt(window, x, y, graphic, sync_frame, NO_MASKING);
228 graphic_info = graphic_info_last;
235 FreeLevelEditorGadgets();
244 static boolean gadgets_initialized = FALSE;
246 if (gadgets_initialized)
249 CreateLevelEditorGadgets();
253 CreateScreenGadgets();
255 InitGadgetsSoundCallback(PlaySoundActivating, PlaySoundSelecting);
257 gadgets_initialized = TRUE;
260 inline void InitElementSmallImagesScaledUp(int graphic)
263 struct FileInfo *fi = getImageListEntryFromImageID(graphic);
265 printf("::: '%s' -> '%s'\n", fi->token, fi->filename);
268 CreateImageWithSmallImages(graphic, graphic_info[graphic].scale_up_factor);
271 void InitElementSmallImages()
273 static int special_graphics[] =
275 IMG_EDITOR_ELEMENT_BORDER,
276 IMG_EDITOR_ELEMENT_BORDER_INPUT,
277 IMG_EDITOR_CASCADE_LIST,
278 IMG_EDITOR_CASCADE_LIST_ACTIVE,
281 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
282 int num_property_mappings = getImageListPropertyMappingSize();
285 /* initialize normal images from static configuration */
286 for (i = 0; element_to_graphic[i].element > -1; i++)
287 InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
289 /* initialize special images from static configuration */
290 for (i = 0; element_to_special_graphic[i].element > -1; i++)
291 InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
293 /* initialize images from dynamic configuration (may be elements or other) */
294 for (i = 0; i < num_property_mappings; i++)
295 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
297 /* initialize special images from above list (non-element images) */
298 for (i = 0; special_graphics[i] > -1; i++)
299 InitElementSmallImagesScaledUp(special_graphics[i]);
302 void InitScaledImages()
306 /* scale normal images from static configuration, if not already scaled */
307 for (i = 0; i < NUM_IMAGE_FILES; i++)
308 ScaleImage(i, graphic_info[i].scale_up_factor);
312 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
313 void SetBitmaps_EM(Bitmap **em_bitmap)
315 em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
316 em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].bitmap;
321 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
322 void SetBitmaps_SP(Bitmap **sp_bitmap)
324 *sp_bitmap = graphic_info[IMG_SP_OBJECTS].bitmap;
328 static int getFontBitmapID(int font_nr)
332 /* (special case: do not use special font for GAME_MODE_LOADING) */
333 if (game_status >= GAME_MODE_TITLE_INITIAL &&
334 game_status <= GAME_MODE_PSEUDO_PREVIEW)
335 special = game_status;
336 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
337 special = GFX_SPECIAL_ARG_MAIN;
339 else if (game_status == GAME_MODE_PLAYING)
340 special = GFX_SPECIAL_ARG_DOOR;
347 font_info[font_nr].token_name,
348 special_suffix_info[special].suffix);
353 return font_info[font_nr].special_bitmap_id[special];
358 static int getFontFromToken(char *token)
361 char *value = getHashEntry(font_token_hash, token);
368 /* !!! OPTIMIZE THIS BY USING HASH !!! */
369 for (i = 0; i < NUM_FONTS; i++)
370 if (strEqual(token, font_info[i].token_name))
374 /* if font not found, use reliable default value */
375 return FONT_INITIAL_1;
378 void InitFontGraphicInfo()
380 static struct FontBitmapInfo *font_bitmap_info = NULL;
381 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
382 int num_property_mappings = getImageListPropertyMappingSize();
383 int num_font_bitmaps = NUM_FONTS;
386 if (graphic_info == NULL) /* still at startup phase */
388 InitFontInfo(font_initial, NUM_INITIAL_FONTS,
389 getFontBitmapID, getFontFromToken);
394 /* ---------- initialize font graphic definitions ---------- */
396 /* always start with reliable default values (normal font graphics) */
397 for (i = 0; i < NUM_FONTS; i++)
398 font_info[i].graphic = IMG_FONT_INITIAL_1;
400 /* initialize normal font/graphic mapping from static configuration */
401 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
403 int font_nr = font_to_graphic[i].font_nr;
404 int special = font_to_graphic[i].special;
405 int graphic = font_to_graphic[i].graphic;
410 font_info[font_nr].graphic = graphic;
413 /* always start with reliable default values (special font graphics) */
414 for (i = 0; i < NUM_FONTS; i++)
416 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
418 font_info[i].special_graphic[j] = font_info[i].graphic;
419 font_info[i].special_bitmap_id[j] = i;
423 /* initialize special font/graphic mapping from static configuration */
424 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
426 int font_nr = font_to_graphic[i].font_nr;
427 int special = font_to_graphic[i].special;
428 int graphic = font_to_graphic[i].graphic;
429 int base_graphic = font2baseimg(font_nr);
431 if (IS_SPECIAL_GFX_ARG(special))
433 boolean base_redefined =
434 getImageListEntryFromImageID(base_graphic)->redefined;
435 boolean special_redefined =
436 getImageListEntryFromImageID(graphic)->redefined;
437 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
439 /* if the base font ("font.title_1", for example) has been redefined,
440 but not the special font ("font.title_1.LEVELS", for example), do not
441 use an existing (in this case considered obsolete) special font
442 anymore, but use the automatically determined default font */
443 /* special case: cloned special fonts must be explicitly redefined,
444 but are not automatically redefined by redefining base font */
445 if (base_redefined && !special_redefined && !special_cloned)
448 font_info[font_nr].special_graphic[special] = graphic;
449 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
454 /* initialize special font/graphic mapping from dynamic configuration */
455 for (i = 0; i < num_property_mappings; i++)
457 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
458 int special = property_mapping[i].ext3_index;
459 int graphic = property_mapping[i].artwork_index;
464 if (IS_SPECIAL_GFX_ARG(special))
466 font_info[font_nr].special_graphic[special] = graphic;
467 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
472 /* correct special font/graphic mapping for cloned fonts for downwards
473 compatibility of PREVIEW fonts -- this is only needed for implicit
474 redefinition of special font by redefined base font, and only if other
475 fonts are cloned from this special font (like in the "Zelda" level set) */
476 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
478 int font_nr = font_to_graphic[i].font_nr;
479 int special = font_to_graphic[i].special;
480 int graphic = font_to_graphic[i].graphic;
482 if (IS_SPECIAL_GFX_ARG(special))
484 boolean special_redefined =
485 getImageListEntryFromImageID(graphic)->redefined;
486 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
488 if (special_cloned && !special_redefined)
492 for (j = 0; font_to_graphic[j].font_nr > -1; j++)
494 int font_nr2 = font_to_graphic[j].font_nr;
495 int special2 = font_to_graphic[j].special;
496 int graphic2 = font_to_graphic[j].graphic;
498 if (IS_SPECIAL_GFX_ARG(special2) &&
499 graphic2 == graphic_info[graphic].clone_from)
501 font_info[font_nr].special_graphic[special] =
502 font_info[font_nr2].special_graphic[special2];
503 font_info[font_nr].special_bitmap_id[special] =
504 font_info[font_nr2].special_bitmap_id[special2];
511 /* reset non-redefined ".active" font graphics if normal font is redefined */
512 /* (this different treatment is needed because normal and active fonts are
513 independently defined ("active" is not a property of font definitions!) */
514 for (i = 0; i < NUM_FONTS; i++)
516 int font_nr_base = i;
517 int font_nr_active = FONT_ACTIVE(font_nr_base);
519 /* check only those fonts with exist as normal and ".active" variant */
520 if (font_nr_base != font_nr_active)
522 int base_graphic = font_info[font_nr_base].graphic;
523 int active_graphic = font_info[font_nr_active].graphic;
524 boolean base_redefined =
525 getImageListEntryFromImageID(base_graphic)->redefined;
526 boolean active_redefined =
527 getImageListEntryFromImageID(active_graphic)->redefined;
529 /* if the base font ("font.menu_1", for example) has been redefined,
530 but not the active font ("font.menu_1.active", for example), do not
531 use an existing (in this case considered obsolete) active font
532 anymore, but use the automatically determined default font */
533 if (base_redefined && !active_redefined)
534 font_info[font_nr_active].graphic = base_graphic;
536 /* now also check each "special" font (which may be the same as above) */
537 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
539 int base_graphic = font_info[font_nr_base].special_graphic[j];
540 int active_graphic = font_info[font_nr_active].special_graphic[j];
541 boolean base_redefined =
542 getImageListEntryFromImageID(base_graphic)->redefined;
543 boolean active_redefined =
544 getImageListEntryFromImageID(active_graphic)->redefined;
546 /* same as above, but check special graphic definitions, for example:
547 redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN" */
548 if (base_redefined && !active_redefined)
550 font_info[font_nr_active].special_graphic[j] =
551 font_info[font_nr_base].special_graphic[j];
552 font_info[font_nr_active].special_bitmap_id[j] =
553 font_info[font_nr_base].special_bitmap_id[j];
559 /* ---------- initialize font bitmap array ---------- */
561 if (font_bitmap_info != NULL)
562 FreeFontInfo(font_bitmap_info);
565 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
567 /* ---------- initialize font bitmap definitions ---------- */
569 for (i = 0; i < NUM_FONTS; i++)
571 if (i < NUM_INITIAL_FONTS)
573 font_bitmap_info[i] = font_initial[i];
577 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
579 int font_bitmap_id = font_info[i].special_bitmap_id[j];
580 int graphic = font_info[i].special_graphic[j];
582 /* set 'graphic_info' for font entries, if uninitialized (guessed) */
583 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
585 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
586 graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
589 /* copy font relevant information from graphics information */
590 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
591 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
592 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
593 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
594 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
596 font_bitmap_info[font_bitmap_id].draw_xoffset =
597 graphic_info[graphic].draw_xoffset;
598 font_bitmap_info[font_bitmap_id].draw_yoffset =
599 graphic_info[graphic].draw_yoffset;
601 font_bitmap_info[font_bitmap_id].num_chars =
602 graphic_info[graphic].anim_frames;
603 font_bitmap_info[font_bitmap_id].num_chars_per_line =
604 graphic_info[graphic].anim_frames_per_line;
608 InitFontInfo(font_bitmap_info, num_font_bitmaps,
609 getFontBitmapID, getFontFromToken);
612 void InitElementGraphicInfo()
614 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
615 int num_property_mappings = getImageListPropertyMappingSize();
618 if (graphic_info == NULL) /* still at startup phase */
621 /* set values to -1 to identify later as "uninitialized" values */
622 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
624 for (act = 0; act < NUM_ACTIONS; act++)
626 element_info[i].graphic[act] = -1;
627 element_info[i].crumbled[act] = -1;
629 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
631 element_info[i].direction_graphic[act][dir] = -1;
632 element_info[i].direction_crumbled[act][dir] = -1;
639 /* initialize normal element/graphic mapping from static configuration */
640 for (i = 0; element_to_graphic[i].element > -1; i++)
642 int element = element_to_graphic[i].element;
643 int action = element_to_graphic[i].action;
644 int direction = element_to_graphic[i].direction;
645 boolean crumbled = element_to_graphic[i].crumbled;
646 int graphic = element_to_graphic[i].graphic;
647 int base_graphic = el2baseimg(element);
649 if (graphic_info[graphic].bitmap == NULL)
652 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
655 boolean base_redefined =
656 getImageListEntryFromImageID(base_graphic)->redefined;
657 boolean act_dir_redefined =
658 getImageListEntryFromImageID(graphic)->redefined;
660 /* if the base graphic ("emerald", for example) has been redefined,
661 but not the action graphic ("emerald.falling", for example), do not
662 use an existing (in this case considered obsolete) action graphic
663 anymore, but use the automatically determined default graphic */
664 if (base_redefined && !act_dir_redefined)
669 action = ACTION_DEFAULT;
674 element_info[element].direction_crumbled[action][direction] = graphic;
676 element_info[element].crumbled[action] = graphic;
681 element_info[element].direction_graphic[action][direction] = graphic;
683 element_info[element].graphic[action] = graphic;
687 /* initialize normal element/graphic mapping from dynamic configuration */
688 for (i = 0; i < num_property_mappings; i++)
690 int element = property_mapping[i].base_index;
691 int action = property_mapping[i].ext1_index;
692 int direction = property_mapping[i].ext2_index;
693 int special = property_mapping[i].ext3_index;
694 int graphic = property_mapping[i].artwork_index;
695 boolean crumbled = FALSE;
698 if ((element == EL_EM_DYNAMITE ||
699 element == EL_EM_DYNAMITE_ACTIVE) &&
700 action == ACTION_ACTIVE &&
701 (special == GFX_SPECIAL_ARG_EDITOR ||
702 special == GFX_SPECIAL_ARG_PANEL))
703 printf("::: DYNAMIC: %d, %d, %d -> %d\n",
704 element, action, special, graphic);
707 if (special == GFX_SPECIAL_ARG_CRUMBLED)
713 if (graphic_info[graphic].bitmap == NULL)
716 if (element >= MAX_NUM_ELEMENTS || special != -1)
720 action = ACTION_DEFAULT;
725 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
726 element_info[element].direction_crumbled[action][dir] = -1;
729 element_info[element].direction_crumbled[action][direction] = graphic;
731 element_info[element].crumbled[action] = graphic;
736 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
737 element_info[element].direction_graphic[action][dir] = -1;
740 element_info[element].direction_graphic[action][direction] = graphic;
742 element_info[element].graphic[action] = graphic;
746 /* now copy all graphics that are defined to be cloned from other graphics */
747 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
749 int graphic = element_info[i].graphic[ACTION_DEFAULT];
750 int crumbled_like, diggable_like;
755 crumbled_like = graphic_info[graphic].crumbled_like;
756 diggable_like = graphic_info[graphic].diggable_like;
758 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
760 for (act = 0; act < NUM_ACTIONS; act++)
761 element_info[i].crumbled[act] =
762 element_info[crumbled_like].crumbled[act];
763 for (act = 0; act < NUM_ACTIONS; act++)
764 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
765 element_info[i].direction_crumbled[act][dir] =
766 element_info[crumbled_like].direction_crumbled[act][dir];
769 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
771 element_info[i].graphic[ACTION_DIGGING] =
772 element_info[diggable_like].graphic[ACTION_DIGGING];
773 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
774 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
775 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
780 /* set hardcoded definitions for some runtime elements without graphic */
781 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
785 /* set hardcoded definitions for some internal elements without graphic */
786 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
788 if (IS_EDITOR_CASCADE_INACTIVE(i))
789 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
790 else if (IS_EDITOR_CASCADE_ACTIVE(i))
791 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
795 /* now set all undefined/invalid graphics to -1 to set to default after it */
796 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
798 for (act = 0; act < NUM_ACTIONS; act++)
802 graphic = element_info[i].graphic[act];
803 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
804 element_info[i].graphic[act] = -1;
806 graphic = element_info[i].crumbled[act];
807 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
808 element_info[i].crumbled[act] = -1;
810 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
812 graphic = element_info[i].direction_graphic[act][dir];
813 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
814 element_info[i].direction_graphic[act][dir] = -1;
816 graphic = element_info[i].direction_crumbled[act][dir];
817 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
818 element_info[i].direction_crumbled[act][dir] = -1;
825 /* adjust graphics with 2nd tile for movement according to direction
826 (do this before correcting '-1' values to minimize calculations) */
827 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
829 for (act = 0; act < NUM_ACTIONS; act++)
831 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
833 int graphic = element_info[i].direction_graphic[act][dir];
834 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
836 if (act == ACTION_FALLING) /* special case */
837 graphic = element_info[i].graphic[act];
840 graphic_info[graphic].double_movement &&
841 graphic_info[graphic].swap_double_tiles != 0)
843 struct GraphicInfo *g = &graphic_info[graphic];
844 int src_x_front = g->src_x;
845 int src_y_front = g->src_y;
846 int src_x_back = g->src_x + g->offset2_x;
847 int src_y_back = g->src_y + g->offset2_y;
848 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
850 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
851 src_y_front < src_y_back);
852 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
853 boolean swap_movement_tiles_autodetected =
854 (!frames_are_ordered_diagonally &&
855 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
856 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
857 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
858 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
861 /* swap frontside and backside graphic tile coordinates, if needed */
862 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
864 /* get current (wrong) backside tile coordinates */
865 getGraphicSourceExt(graphic, 0, &dummy, &src_x_back, &src_y_back,
868 /* set frontside tile coordinates to backside tile coordinates */
869 g->src_x = src_x_back;
870 g->src_y = src_y_back;
872 /* invert tile offset to point to new backside tile coordinates */
876 /* do not swap front and backside tiles again after correction */
877 g->swap_double_tiles = 0;
886 /* now set all '-1' values to element specific default values */
887 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
889 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
890 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
891 int default_direction_graphic[NUM_DIRECTIONS_FULL];
892 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
894 if (default_graphic == -1)
895 default_graphic = IMG_UNKNOWN;
897 if (default_crumbled == -1)
898 default_crumbled = default_graphic;
900 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
901 if (default_crumbled == -1)
902 default_crumbled = IMG_EMPTY;
905 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
907 default_direction_graphic[dir] =
908 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
909 default_direction_crumbled[dir] =
910 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
912 if (default_direction_graphic[dir] == -1)
913 default_direction_graphic[dir] = default_graphic;
915 if (default_direction_crumbled[dir] == -1)
916 default_direction_crumbled[dir] = default_direction_graphic[dir];
918 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
919 if (default_direction_crumbled[dir] == -1)
920 default_direction_crumbled[dir] = default_crumbled;
924 for (act = 0; act < NUM_ACTIONS; act++)
926 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
927 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
928 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
929 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
930 act == ACTION_TURNING_FROM_RIGHT ||
931 act == ACTION_TURNING_FROM_UP ||
932 act == ACTION_TURNING_FROM_DOWN);
934 /* generic default action graphic (defined by "[default]" directive) */
935 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
936 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
937 int default_remove_graphic = IMG_EMPTY;
939 if (act_remove && default_action_graphic != -1)
940 default_remove_graphic = default_action_graphic;
942 /* look for special default action graphic (classic game specific) */
943 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
944 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
945 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
946 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
947 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
948 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
950 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
951 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
952 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
953 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
954 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
955 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
958 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
959 /* !!! make this better !!! */
960 if (i == EL_EMPTY_SPACE)
962 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
963 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
967 if (default_action_graphic == -1)
968 default_action_graphic = default_graphic;
970 if (default_action_crumbled == -1)
971 default_action_crumbled = default_action_graphic;
973 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
974 if (default_action_crumbled == -1)
975 default_action_crumbled = default_crumbled;
978 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
980 /* use action graphic as the default direction graphic, if undefined */
981 int default_action_direction_graphic = element_info[i].graphic[act];
982 int default_action_direction_crumbled = element_info[i].crumbled[act];
984 /* no graphic for current action -- use default direction graphic */
985 if (default_action_direction_graphic == -1)
986 default_action_direction_graphic =
987 (act_remove ? default_remove_graphic :
989 element_info[i].direction_graphic[ACTION_TURNING][dir] :
990 default_action_graphic != default_graphic ?
991 default_action_graphic :
992 default_direction_graphic[dir]);
994 if (element_info[i].direction_graphic[act][dir] == -1)
995 element_info[i].direction_graphic[act][dir] =
996 default_action_direction_graphic;
999 if (default_action_direction_crumbled == -1)
1000 default_action_direction_crumbled =
1001 element_info[i].direction_graphic[act][dir];
1003 if (default_action_direction_crumbled == -1)
1004 default_action_direction_crumbled =
1005 (act_remove ? default_remove_graphic :
1007 element_info[i].direction_crumbled[ACTION_TURNING][dir] :
1008 default_action_crumbled != default_crumbled ?
1009 default_action_crumbled :
1010 default_direction_crumbled[dir]);
1013 if (element_info[i].direction_crumbled[act][dir] == -1)
1014 element_info[i].direction_crumbled[act][dir] =
1015 default_action_direction_crumbled;
1018 /* no graphic for this specific action -- use default action graphic */
1019 if (element_info[i].graphic[act] == -1)
1020 element_info[i].graphic[act] =
1021 (act_remove ? default_remove_graphic :
1022 act_turning ? element_info[i].graphic[ACTION_TURNING] :
1023 default_action_graphic);
1025 if (element_info[i].crumbled[act] == -1)
1026 element_info[i].crumbled[act] = element_info[i].graphic[act];
1028 if (element_info[i].crumbled[act] == -1)
1029 element_info[i].crumbled[act] =
1030 (act_remove ? default_remove_graphic :
1031 act_turning ? element_info[i].crumbled[ACTION_TURNING] :
1032 default_action_crumbled);
1037 UPDATE_BUSY_STATE();
1040 /* !!! THIS ALSO CLEARS SPECIAL FLAGS (AND IS NOT NEEDED ANYWAY) !!! */
1041 /* set animation mode to "none" for each graphic with only 1 frame */
1042 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1044 for (act = 0; act < NUM_ACTIONS; act++)
1046 int graphic = element_info[i].graphic[act];
1047 int crumbled = element_info[i].crumbled[act];
1049 if (graphic_info[graphic].anim_frames == 1)
1050 graphic_info[graphic].anim_mode = ANIM_NONE;
1051 if (graphic_info[crumbled].anim_frames == 1)
1052 graphic_info[crumbled].anim_mode = ANIM_NONE;
1054 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1056 graphic = element_info[i].direction_graphic[act][dir];
1057 crumbled = element_info[i].direction_crumbled[act][dir];
1059 if (graphic_info[graphic].anim_frames == 1)
1060 graphic_info[graphic].anim_mode = ANIM_NONE;
1061 if (graphic_info[crumbled].anim_frames == 1)
1062 graphic_info[crumbled].anim_mode = ANIM_NONE;
1070 if (options.verbose)
1072 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1073 if (element_info[i].graphic[ACTION_DEFAULT] == IMG_UNKNOWN &&
1075 Error(ERR_INFO, "warning: no graphic for element '%s' (%d)",
1076 element_info[i].token_name, i);
1082 void InitElementSpecialGraphicInfo()
1084 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
1085 int num_property_mappings = getImageListPropertyMappingSize();
1088 /* always start with reliable default values */
1089 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1090 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1091 element_info[i].special_graphic[j] =
1092 element_info[i].graphic[ACTION_DEFAULT];
1094 /* initialize special element/graphic mapping from static configuration */
1095 for (i = 0; element_to_special_graphic[i].element > -1; i++)
1097 int element = element_to_special_graphic[i].element;
1098 int special = element_to_special_graphic[i].special;
1099 int graphic = element_to_special_graphic[i].graphic;
1100 int base_graphic = el2baseimg(element);
1101 boolean base_redefined =
1102 getImageListEntryFromImageID(base_graphic)->redefined;
1103 boolean special_redefined =
1104 getImageListEntryFromImageID(graphic)->redefined;
1107 if ((element == EL_EM_DYNAMITE ||
1108 element == EL_EM_DYNAMITE_ACTIVE) &&
1109 (special == GFX_SPECIAL_ARG_EDITOR ||
1110 special == GFX_SPECIAL_ARG_PANEL))
1111 printf("::: SPECIAL STATIC: %d, %d -> %d\n",
1112 element, special, graphic);
1115 /* if the base graphic ("emerald", for example) has been redefined,
1116 but not the special graphic ("emerald.EDITOR", for example), do not
1117 use an existing (in this case considered obsolete) special graphic
1118 anymore, but use the automatically created (down-scaled) graphic */
1119 if (base_redefined && !special_redefined)
1122 element_info[element].special_graphic[special] = graphic;
1125 /* initialize special element/graphic mapping from dynamic configuration */
1126 for (i = 0; i < num_property_mappings; i++)
1128 int element = property_mapping[i].base_index;
1129 int action = property_mapping[i].ext1_index;
1130 int direction = property_mapping[i].ext2_index;
1131 int special = property_mapping[i].ext3_index;
1132 int graphic = property_mapping[i].artwork_index;
1135 if ((element == EL_EM_DYNAMITE ||
1136 element == EL_EM_DYNAMITE_ACTIVE ||
1137 element == EL_CONVEYOR_BELT_1_MIDDLE ||
1138 element == EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE) &&
1139 (special == GFX_SPECIAL_ARG_EDITOR ||
1140 special == GFX_SPECIAL_ARG_PANEL))
1141 printf("::: SPECIAL DYNAMIC: %d, %d -> %d [%d]\n",
1142 element, special, graphic, property_mapping[i].ext1_index);
1146 if (element == EL_CONVEYOR_BELT_1_MIDDLE &&
1147 action == ACTION_ACTIVE)
1149 element = EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE;
1155 if (element == EL_MAGIC_WALL &&
1156 action == ACTION_ACTIVE)
1158 element = EL_MAGIC_WALL_ACTIVE;
1164 /* for action ".active", replace element with active element, if exists */
1165 if (action == ACTION_ACTIVE && element != ELEMENT_ACTIVE(element))
1167 element = ELEMENT_ACTIVE(element);
1172 if (element >= MAX_NUM_ELEMENTS)
1175 /* do not change special graphic if action or direction was specified */
1176 if (action != -1 || direction != -1)
1179 if (IS_SPECIAL_GFX_ARG(special))
1180 element_info[element].special_graphic[special] = graphic;
1183 /* now set all undefined/invalid graphics to default */
1184 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1185 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1186 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
1187 element_info[i].special_graphic[j] =
1188 element_info[i].graphic[ACTION_DEFAULT];
1191 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
1193 if (type != TYPE_ELEMENT && type != TYPE_GRAPHIC)
1194 return get_parameter_value(value_raw, suffix, type);
1196 if (strEqual(value_raw, ARG_UNDEFINED))
1197 return ARG_UNDEFINED_VALUE;
1200 if (type == TYPE_ELEMENT)
1202 char *value = getHashEntry(element_token_hash, value_raw);
1204 return (value != NULL ? atoi(value) : EL_UNDEFINED);
1206 else if (type == TYPE_GRAPHIC)
1208 char *value = getHashEntry(graphic_token_hash, value_raw);
1210 return (value != NULL ? atoi(value) : IMG_UNDEFINED);
1218 /* !!! THIS IS BUGGY !!! NOT SURE IF YOU GET ELEMENT ID OR GRAPHIC ID !!! */
1219 /* !!! (possible reason why ".clone_from" with elements doesn't work) !!! */
1221 /* !!! OPTIMIZE THIS BY USING HASH !!! */
1222 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1223 if (strEqual(element_info[i].token_name, value_raw))
1226 /* !!! OPTIMIZE THIS BY USING HASH !!! */
1227 for (i = 0; image_config[i].token != NULL; i++)
1229 int len_config_value = strlen(image_config[i].value);
1231 if (!strEqual(&image_config[i].value[len_config_value - 4], ".pcx") &&
1232 !strEqual(&image_config[i].value[len_config_value - 4], ".wav") &&
1233 !strEqual(image_config[i].value, UNDEFINED_FILENAME))
1236 if (strEqual(image_config[i].token, value_raw))
1246 static int get_scaled_graphic_width(int graphic)
1248 int original_width = getOriginalImageWidthFromImageID(graphic);
1249 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1251 return original_width * scale_up_factor;
1254 static int get_scaled_graphic_height(int graphic)
1256 int original_height = getOriginalImageHeightFromImageID(graphic);
1257 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1259 return original_height * scale_up_factor;
1262 static void set_graphic_parameters_ext(int graphic, int *parameter,
1265 struct GraphicInfo *g = &graphic_info[graphic];
1266 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1267 int anim_frames_per_line = 1;
1269 /* always start with reliable default values */
1270 g->src_image_width = 0;
1271 g->src_image_height = 0;
1274 g->width = TILEX; /* default for element graphics */
1275 g->height = TILEY; /* default for element graphics */
1276 g->offset_x = 0; /* one or both of these values ... */
1277 g->offset_y = 0; /* ... will be corrected later */
1278 g->offset2_x = 0; /* one or both of these values ... */
1279 g->offset2_y = 0; /* ... will be corrected later */
1280 g->swap_double_tiles = -1; /* auto-detect tile swapping */
1281 g->crumbled_like = -1; /* do not use clone element */
1282 g->diggable_like = -1; /* do not use clone element */
1283 g->border_size = TILEX / 8; /* "CRUMBLED" border size */
1284 g->scale_up_factor = 1; /* default: no scaling up */
1285 g->clone_from = -1; /* do not use clone graphic */
1286 g->anim_delay_fixed = 0;
1287 g->anim_delay_random = 0;
1288 g->post_delay_fixed = 0;
1289 g->post_delay_random = 0;
1290 g->fade_mode = FADE_MODE_DEFAULT;
1294 g->align = ALIGN_CENTER; /* default for title screens */
1295 g->valign = VALIGN_MIDDLE; /* default for title screens */
1296 g->sort_priority = 0; /* default for title screens */
1298 g->style = STYLE_DEFAULT;
1300 g->bitmap = src_bitmap;
1303 /* optional zoom factor for scaling up the image to a larger size */
1304 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1305 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1306 if (g->scale_up_factor < 1)
1307 g->scale_up_factor = 1; /* no scaling */
1311 if (g->use_image_size)
1313 /* set new default bitmap size (with scaling, but without small images) */
1314 g->width = get_scaled_graphic_width(graphic);
1315 g->height = get_scaled_graphic_height(graphic);
1319 /* optional x and y tile position of animation frame sequence */
1320 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1321 g->src_x = parameter[GFX_ARG_XPOS] * TILEX;
1322 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1323 g->src_y = parameter[GFX_ARG_YPOS] * TILEY;
1325 /* optional x and y pixel position of animation frame sequence */
1326 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1327 g->src_x = parameter[GFX_ARG_X];
1328 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1329 g->src_y = parameter[GFX_ARG_Y];
1331 /* optional width and height of each animation frame */
1332 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1333 g->width = parameter[GFX_ARG_WIDTH];
1334 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1335 g->height = parameter[GFX_ARG_HEIGHT];
1338 /* optional zoom factor for scaling up the image to a larger size */
1339 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1340 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1341 if (g->scale_up_factor < 1)
1342 g->scale_up_factor = 1; /* no scaling */
1347 /* get final bitmap size (with scaling, but without small images) */
1348 int src_image_width = get_scaled_graphic_width(graphic);
1349 int src_image_height = get_scaled_graphic_height(graphic);
1351 if (src_image_width == 0 || src_image_height == 0)
1353 /* only happens when loaded outside artwork system (like "global.busy") */
1354 src_image_width = src_bitmap->width;
1355 src_image_height = src_bitmap->height;
1358 anim_frames_per_row = src_image_width / g->width;
1359 anim_frames_per_col = src_image_height / g->height;
1361 g->src_image_width = src_image_width;
1362 g->src_image_height = src_image_height;
1365 /* correct x or y offset dependent of vertical or horizontal frame order */
1366 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1368 g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1369 parameter[GFX_ARG_OFFSET] : g->height);
1370 anim_frames_per_line = anim_frames_per_col;
1372 else /* frames are ordered horizontally */
1374 g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1375 parameter[GFX_ARG_OFFSET] : g->width);
1376 anim_frames_per_line = anim_frames_per_row;
1379 /* optionally, the x and y offset of frames can be specified directly */
1380 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1381 g->offset_x = parameter[GFX_ARG_XOFFSET];
1382 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1383 g->offset_y = parameter[GFX_ARG_YOFFSET];
1385 /* optionally, moving animations may have separate start and end graphics */
1386 g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1388 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1389 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1391 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1392 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1393 g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1394 parameter[GFX_ARG_2ND_OFFSET] : g->height);
1395 else /* frames are ordered horizontally */
1396 g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1397 parameter[GFX_ARG_2ND_OFFSET] : g->width);
1399 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1400 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1401 g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1402 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1403 g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1405 /* optionally, the second movement tile can be specified as start tile */
1406 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1407 g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1409 /* automatically determine correct number of frames, if not defined */
1410 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1411 g->anim_frames = parameter[GFX_ARG_FRAMES];
1412 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1413 g->anim_frames = anim_frames_per_row;
1414 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1415 g->anim_frames = anim_frames_per_col;
1419 if (g->anim_frames == 0) /* frames must be at least 1 */
1422 g->anim_frames_per_line =
1423 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1424 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1426 g->anim_delay = parameter[GFX_ARG_DELAY];
1427 if (g->anim_delay == 0) /* delay must be at least 1 */
1430 g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1432 if (g->anim_frames == 1)
1433 g->anim_mode = ANIM_NONE;
1436 /* automatically determine correct start frame, if not defined */
1437 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1438 g->anim_start_frame = 0;
1439 else if (g->anim_mode & ANIM_REVERSE)
1440 g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1442 g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1444 /* animation synchronized with global frame counter, not move position */
1445 g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1447 /* optional element for cloning crumble graphics */
1448 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1449 g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1451 /* optional element for cloning digging graphics */
1452 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1453 g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1455 /* optional border size for "crumbling" diggable graphics */
1456 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1457 g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1459 /* this is only used for player "boring" and "sleeping" actions */
1460 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1461 g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1462 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1463 g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1464 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1465 g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1466 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1467 g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1469 /* this is only used for toon animations */
1470 g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1471 g->step_delay = parameter[GFX_ARG_STEP_DELAY];
1473 /* this is only used for drawing font characters */
1474 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1475 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1477 /* this is only used for drawing envelope graphics */
1478 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1480 /* optional graphic for cloning all graphics settings */
1481 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1482 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1484 /* optional settings for drawing title screens and title messages */
1485 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1486 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1487 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1488 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1489 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1490 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1491 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1492 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1493 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1494 g->align = parameter[GFX_ARG_ALIGN];
1495 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1496 g->valign = parameter[GFX_ARG_VALIGN];
1497 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1498 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1500 if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
1501 g->class = parameter[GFX_ARG_CLASS];
1502 if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
1503 g->style = parameter[GFX_ARG_STYLE];
1506 static void set_graphic_parameters(int graphic)
1509 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1510 char **parameter_raw = image->parameter;
1511 Bitmap *src_bitmap = getBitmapFromImageID(graphic);
1512 int parameter[NUM_GFX_ARGS];
1515 /* if fallback to default artwork is done, also use the default parameters */
1516 if (image->fallback_to_default)
1517 parameter_raw = image->default_parameter;
1519 /* get integer values from string parameters */
1520 for (i = 0; i < NUM_GFX_ARGS; i++)
1521 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1522 image_config_suffix[i].token,
1523 image_config_suffix[i].type);
1525 set_graphic_parameters_ext(graphic, parameter, src_bitmap);
1529 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1530 char **parameter_raw = image->parameter;
1531 Bitmap *src_bitmap = getBitmapFromImageID(graphic);
1532 int parameter[NUM_GFX_ARGS];
1533 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1534 int anim_frames_per_line = 1;
1537 /* if fallback to default artwork is done, also use the default parameters */
1538 if (image->fallback_to_default)
1539 parameter_raw = image->default_parameter;
1541 /* get integer values from string parameters */
1542 for (i = 0; i < NUM_GFX_ARGS; i++)
1543 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1544 image_config_suffix[i].token,
1545 image_config_suffix[i].type);
1547 graphic_info[graphic].bitmap = src_bitmap;
1549 /* always start with reliable default values */
1550 graphic_info[graphic].src_image_width = 0;
1551 graphic_info[graphic].src_image_height = 0;
1552 graphic_info[graphic].src_x = 0;
1553 graphic_info[graphic].src_y = 0;
1554 graphic_info[graphic].width = TILEX; /* default for element graphics */
1555 graphic_info[graphic].height = TILEY; /* default for element graphics */
1556 graphic_info[graphic].offset_x = 0; /* one or both of these values ... */
1557 graphic_info[graphic].offset_y = 0; /* ... will be corrected later */
1558 graphic_info[graphic].offset2_x = 0; /* one or both of these values ... */
1559 graphic_info[graphic].offset2_y = 0; /* ... will be corrected later */
1560 graphic_info[graphic].swap_double_tiles = -1; /* auto-detect tile swapping */
1561 graphic_info[graphic].crumbled_like = -1; /* do not use clone element */
1562 graphic_info[graphic].diggable_like = -1; /* do not use clone element */
1563 graphic_info[graphic].border_size = TILEX / 8; /* "CRUMBLED" border size */
1564 graphic_info[graphic].scale_up_factor = 1; /* default: no scaling up */
1565 graphic_info[graphic].clone_from = -1; /* do not use clone graphic */
1566 graphic_info[graphic].anim_delay_fixed = 0;
1567 graphic_info[graphic].anim_delay_random = 0;
1568 graphic_info[graphic].post_delay_fixed = 0;
1569 graphic_info[graphic].post_delay_random = 0;
1570 graphic_info[graphic].fade_mode = FADE_MODE_DEFAULT;
1571 graphic_info[graphic].fade_delay = -1;
1572 graphic_info[graphic].post_delay = -1;
1573 graphic_info[graphic].auto_delay = -1;
1574 graphic_info[graphic].align = ALIGN_CENTER; /* default for title screens */
1575 graphic_info[graphic].valign = VALIGN_MIDDLE; /* default for title screens */
1576 graphic_info[graphic].sort_priority = 0; /* default for title screens */
1579 /* optional zoom factor for scaling up the image to a larger size */
1580 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1581 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1582 if (graphic_info[graphic].scale_up_factor < 1)
1583 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
1587 if (graphic_info[graphic].use_image_size)
1589 /* set new default bitmap size (with scaling, but without small images) */
1590 graphic_info[graphic].width = get_scaled_graphic_width(graphic);
1591 graphic_info[graphic].height = get_scaled_graphic_height(graphic);
1595 /* optional x and y tile position of animation frame sequence */
1596 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1597 graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
1598 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1599 graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
1601 /* optional x and y pixel position of animation frame sequence */
1602 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1603 graphic_info[graphic].src_x = parameter[GFX_ARG_X];
1604 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1605 graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
1607 /* optional width and height of each animation frame */
1608 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1609 graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
1610 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1611 graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
1614 /* optional zoom factor for scaling up the image to a larger size */
1615 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1616 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1617 if (graphic_info[graphic].scale_up_factor < 1)
1618 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
1623 /* get final bitmap size (with scaling, but without small images) */
1624 int src_image_width = get_scaled_graphic_width(graphic);
1625 int src_image_height = get_scaled_graphic_height(graphic);
1627 anim_frames_per_row = src_image_width / graphic_info[graphic].width;
1628 anim_frames_per_col = src_image_height / graphic_info[graphic].height;
1630 graphic_info[graphic].src_image_width = src_image_width;
1631 graphic_info[graphic].src_image_height = src_image_height;
1634 /* correct x or y offset dependent of vertical or horizontal frame order */
1635 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1637 graphic_info[graphic].offset_y =
1638 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1639 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
1640 anim_frames_per_line = anim_frames_per_col;
1642 else /* frames are ordered horizontally */
1644 graphic_info[graphic].offset_x =
1645 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1646 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
1647 anim_frames_per_line = anim_frames_per_row;
1650 /* optionally, the x and y offset of frames can be specified directly */
1651 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1652 graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
1653 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1654 graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
1656 /* optionally, moving animations may have separate start and end graphics */
1657 graphic_info[graphic].double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1659 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1660 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1662 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1663 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1664 graphic_info[graphic].offset2_y =
1665 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1666 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].height);
1667 else /* frames are ordered horizontally */
1668 graphic_info[graphic].offset2_x =
1669 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1670 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].width);
1672 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1673 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1674 graphic_info[graphic].offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1675 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1676 graphic_info[graphic].offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1678 /* optionally, the second movement tile can be specified as start tile */
1679 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1680 graphic_info[graphic].swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1682 /* automatically determine correct number of frames, if not defined */
1683 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1684 graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
1685 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1686 graphic_info[graphic].anim_frames = anim_frames_per_row;
1687 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1688 graphic_info[graphic].anim_frames = anim_frames_per_col;
1690 graphic_info[graphic].anim_frames = 1;
1692 if (graphic_info[graphic].anim_frames == 0) /* frames must be at least 1 */
1693 graphic_info[graphic].anim_frames = 1;
1695 graphic_info[graphic].anim_frames_per_line =
1696 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1697 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1699 graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
1700 if (graphic_info[graphic].anim_delay == 0) /* delay must be at least 1 */
1701 graphic_info[graphic].anim_delay = 1;
1703 graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
1705 if (graphic_info[graphic].anim_frames == 1)
1706 graphic_info[graphic].anim_mode = ANIM_NONE;
1709 /* automatically determine correct start frame, if not defined */
1710 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1711 graphic_info[graphic].anim_start_frame = 0;
1712 else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
1713 graphic_info[graphic].anim_start_frame =
1714 graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1716 graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
1718 /* animation synchronized with global frame counter, not move position */
1719 graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1721 /* optional element for cloning crumble graphics */
1722 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1723 graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1725 /* optional element for cloning digging graphics */
1726 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1727 graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1729 /* optional border size for "crumbling" diggable graphics */
1730 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1731 graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
1733 /* this is only used for player "boring" and "sleeping" actions */
1734 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1735 graphic_info[graphic].anim_delay_fixed =
1736 parameter[GFX_ARG_ANIM_DELAY_FIXED];
1737 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1738 graphic_info[graphic].anim_delay_random =
1739 parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1740 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1741 graphic_info[graphic].post_delay_fixed =
1742 parameter[GFX_ARG_POST_DELAY_FIXED];
1743 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1744 graphic_info[graphic].post_delay_random =
1745 parameter[GFX_ARG_POST_DELAY_RANDOM];
1747 /* this is only used for toon animations */
1748 graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
1749 graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY];
1751 /* this is only used for drawing font characters */
1752 graphic_info[graphic].draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1753 graphic_info[graphic].draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1755 /* this is only used for drawing envelope graphics */
1756 graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1758 /* optional graphic for cloning all graphics settings */
1759 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1760 graphic_info[graphic].clone_from = parameter[GFX_ARG_CLONE_FROM];
1762 /* optional settings for drawing title screens and title messages */
1763 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1764 graphic_info[graphic].fade_mode = parameter[GFX_ARG_FADE_MODE];
1765 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1766 graphic_info[graphic].fade_delay = parameter[GFX_ARG_FADE_DELAY];
1767 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1768 graphic_info[graphic].post_delay = parameter[GFX_ARG_POST_DELAY];
1769 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1770 graphic_info[graphic].auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1771 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1772 graphic_info[graphic].align = parameter[GFX_ARG_ALIGN];
1773 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1774 graphic_info[graphic].valign = parameter[GFX_ARG_VALIGN];
1775 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1776 graphic_info[graphic].sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1779 UPDATE_BUSY_STATE();
1782 static void set_cloned_graphic_parameters(int graphic)
1784 int fallback_graphic = IMG_CHAR_EXCLAM;
1785 int max_num_images = getImageListSize();
1786 int clone_graphic = graphic_info[graphic].clone_from;
1787 int num_references_followed = 1;
1789 while (graphic_info[clone_graphic].clone_from != -1 &&
1790 num_references_followed < max_num_images)
1792 clone_graphic = graphic_info[clone_graphic].clone_from;
1794 num_references_followed++;
1797 if (num_references_followed >= max_num_images)
1799 Error(ERR_INFO_LINE, "-");
1800 Error(ERR_INFO, "warning: error found in config file:");
1801 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1802 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1803 Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1804 Error(ERR_INFO, "custom graphic rejected for this element/action");
1806 if (graphic == fallback_graphic)
1807 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1809 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1810 Error(ERR_INFO_LINE, "-");
1812 graphic_info[graphic] = graphic_info[fallback_graphic];
1816 graphic_info[graphic] = graphic_info[clone_graphic];
1817 graphic_info[graphic].clone_from = clone_graphic;
1821 static void InitGraphicInfo()
1823 int fallback_graphic = IMG_CHAR_EXCLAM;
1824 int num_images = getImageListSize();
1827 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1828 static boolean clipmasks_initialized = FALSE;
1830 XGCValues clip_gc_values;
1831 unsigned long clip_gc_valuemask;
1832 GC copy_clipmask_gc = None;
1835 /* use image size as default values for width and height for these images */
1836 static int full_size_graphics[] =
1841 IMG_BACKGROUND_ENVELOPE_1,
1842 IMG_BACKGROUND_ENVELOPE_2,
1843 IMG_BACKGROUND_ENVELOPE_3,
1844 IMG_BACKGROUND_ENVELOPE_4,
1847 IMG_BACKGROUND_TITLE_INITIAL,
1848 IMG_BACKGROUND_TITLE,
1849 IMG_BACKGROUND_MAIN,
1850 IMG_BACKGROUND_LEVELS,
1851 IMG_BACKGROUND_SCORES,
1852 IMG_BACKGROUND_EDITOR,
1853 IMG_BACKGROUND_INFO,
1854 IMG_BACKGROUND_INFO_ELEMENTS,
1855 IMG_BACKGROUND_INFO_MUSIC,
1856 IMG_BACKGROUND_INFO_CREDITS,
1857 IMG_BACKGROUND_INFO_PROGRAM,
1858 IMG_BACKGROUND_INFO_LEVELSET,
1859 IMG_BACKGROUND_SETUP,
1860 IMG_BACKGROUND_DOOR,
1862 IMG_TITLESCREEN_INITIAL_1,
1863 IMG_TITLESCREEN_INITIAL_2,
1864 IMG_TITLESCREEN_INITIAL_3,
1865 IMG_TITLESCREEN_INITIAL_4,
1866 IMG_TITLESCREEN_INITIAL_5,
1876 checked_free(graphic_info);
1878 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1881 /* initialize "use_image_size" flag with default value */
1882 for (i = 0; i < num_images; i++)
1883 graphic_info[i].use_image_size = FALSE;
1885 /* initialize "use_image_size" flag from static configuration above */
1886 for (i = 0; full_size_graphics[i] != -1; i++)
1887 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1890 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1891 if (clipmasks_initialized)
1893 for (i = 0; i < num_images; i++)
1895 if (graphic_info[i].clip_mask)
1896 XFreePixmap(display, graphic_info[i].clip_mask);
1897 if (graphic_info[i].clip_gc)
1898 XFreeGC(display, graphic_info[i].clip_gc);
1900 graphic_info[i].clip_mask = None;
1901 graphic_info[i].clip_gc = None;
1906 /* first set all graphic paramaters ... */
1907 for (i = 0; i < num_images; i++)
1908 set_graphic_parameters(i);
1910 /* ... then copy these parameters for cloned graphics */
1911 for (i = 0; i < num_images; i++)
1912 if (graphic_info[i].clone_from != -1)
1913 set_cloned_graphic_parameters(i);
1915 for (i = 0; i < num_images; i++)
1920 int first_frame, last_frame;
1921 int src_bitmap_width, src_bitmap_height;
1923 /* now check if no animation frames are outside of the loaded image */
1925 if (graphic_info[i].bitmap == NULL)
1926 continue; /* skip check for optional images that are undefined */
1928 /* get image size (this can differ from the standard element tile size!) */
1929 width = graphic_info[i].width;
1930 height = graphic_info[i].height;
1932 /* get final bitmap size (with scaling, but without small images) */
1933 src_bitmap_width = graphic_info[i].src_image_width;
1934 src_bitmap_height = graphic_info[i].src_image_height;
1936 /* check if first animation frame is inside specified bitmap */
1939 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1942 /* this avoids calculating wrong start position for out-of-bounds frame */
1943 src_x = graphic_info[i].src_x;
1944 src_y = graphic_info[i].src_y;
1947 if (src_x < 0 || src_y < 0 ||
1948 src_x + width > src_bitmap_width ||
1949 src_y + height > src_bitmap_height)
1951 Error(ERR_INFO_LINE, "-");
1952 Error(ERR_INFO, "warning: error found in config file:");
1953 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1954 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1955 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1957 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1958 src_x, src_y, src_bitmap_width, src_bitmap_height);
1959 Error(ERR_INFO, "custom graphic rejected for this element/action");
1961 if (i == fallback_graphic)
1962 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1964 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1965 Error(ERR_INFO_LINE, "-");
1967 graphic_info[i] = graphic_info[fallback_graphic];
1970 /* check if last animation frame is inside specified bitmap */
1972 last_frame = graphic_info[i].anim_frames - 1;
1973 getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1975 if (src_x < 0 || src_y < 0 ||
1976 src_x + width > src_bitmap_width ||
1977 src_y + height > src_bitmap_height)
1979 Error(ERR_INFO_LINE, "-");
1980 Error(ERR_INFO, "warning: error found in config file:");
1981 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1982 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1983 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1985 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1986 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1987 Error(ERR_INFO, "custom graphic rejected for this element/action");
1989 if (i == fallback_graphic)
1990 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1992 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1993 Error(ERR_INFO_LINE, "-");
1995 graphic_info[i] = graphic_info[fallback_graphic];
1998 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1999 /* currently we only need a tile clip mask from the first frame */
2000 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
2002 if (copy_clipmask_gc == None)
2004 clip_gc_values.graphics_exposures = False;
2005 clip_gc_valuemask = GCGraphicsExposures;
2006 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
2007 clip_gc_valuemask, &clip_gc_values);
2010 graphic_info[i].clip_mask =
2011 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
2013 src_pixmap = src_bitmap->clip_mask;
2014 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
2015 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
2017 clip_gc_values.graphics_exposures = False;
2018 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
2019 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
2021 graphic_info[i].clip_gc =
2022 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
2026 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
2027 if (copy_clipmask_gc)
2028 XFreeGC(display, copy_clipmask_gc);
2030 clipmasks_initialized = TRUE;
2034 static void InitElementSoundInfo()
2036 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
2037 int num_property_mappings = getSoundListPropertyMappingSize();
2040 /* set values to -1 to identify later as "uninitialized" values */
2041 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2042 for (act = 0; act < NUM_ACTIONS; act++)
2043 element_info[i].sound[act] = -1;
2045 /* initialize element/sound mapping from static configuration */
2046 for (i = 0; element_to_sound[i].element > -1; i++)
2048 int element = element_to_sound[i].element;
2049 int action = element_to_sound[i].action;
2050 int sound = element_to_sound[i].sound;
2051 boolean is_class = element_to_sound[i].is_class;
2054 action = ACTION_DEFAULT;
2057 element_info[element].sound[action] = sound;
2059 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2060 if (strEqual(element_info[j].class_name,
2061 element_info[element].class_name))
2062 element_info[j].sound[action] = sound;
2065 /* initialize element class/sound mapping from dynamic configuration */
2066 for (i = 0; i < num_property_mappings; i++)
2068 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
2069 int action = property_mapping[i].ext1_index;
2070 int sound = property_mapping[i].artwork_index;
2072 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
2076 action = ACTION_DEFAULT;
2078 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2079 if (strEqual(element_info[j].class_name,
2080 element_info[element_class].class_name))
2081 element_info[j].sound[action] = sound;
2084 /* initialize element/sound mapping from dynamic configuration */
2085 for (i = 0; i < num_property_mappings; i++)
2087 int element = property_mapping[i].base_index;
2088 int action = property_mapping[i].ext1_index;
2089 int sound = property_mapping[i].artwork_index;
2091 if (element >= MAX_NUM_ELEMENTS)
2095 action = ACTION_DEFAULT;
2097 element_info[element].sound[action] = sound;
2100 /* now set all '-1' values to element specific default values */
2101 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2103 for (act = 0; act < NUM_ACTIONS; act++)
2105 /* generic default action sound (defined by "[default]" directive) */
2106 int default_action_sound = element_info[EL_DEFAULT].sound[act];
2108 /* look for special default action sound (classic game specific) */
2109 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
2110 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
2111 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
2112 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
2113 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
2114 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
2116 /* !!! there's no such thing as a "default action sound" !!! */
2118 /* look for element specific default sound (independent from action) */
2119 if (element_info[i].sound[ACTION_DEFAULT] != -1)
2120 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
2124 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
2125 /* !!! make this better !!! */
2126 if (i == EL_EMPTY_SPACE)
2127 default_action_sound = element_info[EL_DEFAULT].sound[act];
2130 /* no sound for this specific action -- use default action sound */
2131 if (element_info[i].sound[act] == -1)
2132 element_info[i].sound[act] = default_action_sound;
2136 /* copy sound settings to some elements that are only stored in level file
2137 in native R'n'D levels, but are used by game engine in native EM levels */
2138 for (i = 0; copy_properties[i][0] != -1; i++)
2139 for (j = 1; j <= 4; j++)
2140 for (act = 0; act < NUM_ACTIONS; act++)
2141 element_info[copy_properties[i][j]].sound[act] =
2142 element_info[copy_properties[i][0]].sound[act];
2145 static void InitGameModeSoundInfo()
2149 /* set values to -1 to identify later as "uninitialized" values */
2150 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2153 /* initialize gamemode/sound mapping from static configuration */
2154 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
2156 int gamemode = gamemode_to_sound[i].gamemode;
2157 int sound = gamemode_to_sound[i].sound;
2160 gamemode = GAME_MODE_DEFAULT;
2162 menu.sound[gamemode] = sound;
2165 /* now set all '-1' values to levelset specific default values */
2166 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2167 if (menu.sound[i] == -1)
2168 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
2171 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2172 if (menu.sound[i] != -1)
2173 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
2177 static void set_sound_parameters(int sound, char **parameter_raw)
2179 int parameter[NUM_SND_ARGS];
2182 /* get integer values from string parameters */
2183 for (i = 0; i < NUM_SND_ARGS; i++)
2185 get_parameter_value(parameter_raw[i],
2186 sound_config_suffix[i].token,
2187 sound_config_suffix[i].type);
2189 /* explicit loop mode setting in configuration overrides default value */
2190 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2191 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
2193 /* sound volume to change the original volume when loading the sound file */
2194 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
2196 /* sound priority to give certain sounds a higher or lower priority */
2197 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
2200 static void InitSoundInfo()
2202 int *sound_effect_properties;
2203 int num_sounds = getSoundListSize();
2206 checked_free(sound_info);
2208 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
2209 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
2211 /* initialize sound effect for all elements to "no sound" */
2212 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2213 for (j = 0; j < NUM_ACTIONS; j++)
2214 element_info[i].sound[j] = SND_UNDEFINED;
2216 for (i = 0; i < num_sounds; i++)
2218 struct FileInfo *sound = getSoundListEntry(i);
2219 int len_effect_text = strlen(sound->token);
2221 sound_effect_properties[i] = ACTION_OTHER;
2222 sound_info[i].loop = FALSE; /* default: play sound only once */
2225 printf("::: sound %d: '%s'\n", i, sound->token);
2228 /* determine all loop sounds and identify certain sound classes */
2230 for (j = 0; element_action_info[j].suffix; j++)
2232 int len_action_text = strlen(element_action_info[j].suffix);
2234 if (len_action_text < len_effect_text &&
2235 strEqual(&sound->token[len_effect_text - len_action_text],
2236 element_action_info[j].suffix))
2238 sound_effect_properties[i] = element_action_info[j].value;
2239 sound_info[i].loop = element_action_info[j].is_loop_sound;
2245 /* associate elements and some selected sound actions */
2247 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2249 if (element_info[j].class_name)
2251 int len_class_text = strlen(element_info[j].class_name);
2253 if (len_class_text + 1 < len_effect_text &&
2254 strncmp(sound->token,
2255 element_info[j].class_name, len_class_text) == 0 &&
2256 sound->token[len_class_text] == '.')
2258 int sound_action_value = sound_effect_properties[i];
2260 element_info[j].sound[sound_action_value] = i;
2265 set_sound_parameters(i, sound->parameter);
2268 free(sound_effect_properties);
2271 static void InitGameModeMusicInfo()
2273 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
2274 int num_property_mappings = getMusicListPropertyMappingSize();
2275 int default_levelset_music = -1;
2278 /* set values to -1 to identify later as "uninitialized" values */
2279 for (i = 0; i < MAX_LEVELS; i++)
2280 levelset.music[i] = -1;
2281 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2284 /* initialize gamemode/music mapping from static configuration */
2285 for (i = 0; gamemode_to_music[i].music > -1; i++)
2287 int gamemode = gamemode_to_music[i].gamemode;
2288 int music = gamemode_to_music[i].music;
2291 printf("::: gamemode == %d, music == %d\n", gamemode, music);
2295 gamemode = GAME_MODE_DEFAULT;
2297 menu.music[gamemode] = music;
2300 /* initialize gamemode/music mapping from dynamic configuration */
2301 for (i = 0; i < num_property_mappings; i++)
2303 int prefix = property_mapping[i].base_index;
2304 int gamemode = property_mapping[i].ext1_index;
2305 int level = property_mapping[i].ext2_index;
2306 int music = property_mapping[i].artwork_index;
2309 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
2310 prefix, gamemode, level, music);
2313 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
2317 gamemode = GAME_MODE_DEFAULT;
2319 /* level specific music only allowed for in-game music */
2320 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
2321 gamemode = GAME_MODE_PLAYING;
2326 default_levelset_music = music;
2329 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
2330 levelset.music[level] = music;
2331 if (gamemode != GAME_MODE_PLAYING)
2332 menu.music[gamemode] = music;
2335 /* now set all '-1' values to menu specific default values */
2336 /* (undefined values of "levelset.music[]" might stay at "-1" to
2337 allow dynamic selection of music files from music directory!) */
2338 for (i = 0; i < MAX_LEVELS; i++)
2339 if (levelset.music[i] == -1)
2340 levelset.music[i] = default_levelset_music;
2341 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2342 if (menu.music[i] == -1)
2343 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
2346 for (i = 0; i < MAX_LEVELS; i++)
2347 if (levelset.music[i] != -1)
2348 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
2349 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2350 if (menu.music[i] != -1)
2351 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
2355 static void set_music_parameters(int music, char **parameter_raw)
2357 int parameter[NUM_MUS_ARGS];
2360 /* get integer values from string parameters */
2361 for (i = 0; i < NUM_MUS_ARGS; i++)
2363 get_parameter_value(parameter_raw[i],
2364 music_config_suffix[i].token,
2365 music_config_suffix[i].type);
2367 /* explicit loop mode setting in configuration overrides default value */
2368 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2369 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
2372 static void InitMusicInfo()
2374 int num_music = getMusicListSize();
2377 checked_free(music_info);
2379 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
2381 for (i = 0; i < num_music; i++)
2383 struct FileInfo *music = getMusicListEntry(i);
2384 int len_music_text = strlen(music->token);
2386 music_info[i].loop = TRUE; /* default: play music in loop mode */
2388 /* determine all loop music */
2390 for (j = 0; music_prefix_info[j].prefix; j++)
2392 int len_prefix_text = strlen(music_prefix_info[j].prefix);
2394 if (len_prefix_text < len_music_text &&
2395 strncmp(music->token,
2396 music_prefix_info[j].prefix, len_prefix_text) == 0)
2398 music_info[i].loop = music_prefix_info[j].is_loop_music;
2404 set_music_parameters(i, music->parameter);
2408 static void ReinitializeGraphics()
2410 print_timestamp_init("ReinitializeGraphics");
2412 InitGraphicInfo(); /* graphic properties mapping */
2413 print_timestamp_time("InitGraphicInfo");
2414 InitElementGraphicInfo(); /* element game graphic mapping */
2415 print_timestamp_time("InitElementGraphicInfo");
2416 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
2417 print_timestamp_time("InitElementSpecialGraphicInfo");
2419 InitElementSmallImages(); /* scale elements to all needed sizes */
2420 print_timestamp_time("InitElementSmallImages");
2421 InitScaledImages(); /* scale all other images, if needed */
2422 print_timestamp_time("InitScaledImages");
2423 InitFontGraphicInfo(); /* initialize text drawing functions */
2424 print_timestamp_time("InitFontGraphicInfo");
2426 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
2427 print_timestamp_time("InitGraphicInfo_EM");
2429 SetMainBackgroundImage(IMG_BACKGROUND);
2430 print_timestamp_time("SetMainBackgroundImage");
2431 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2432 print_timestamp_time("SetDoorBackgroundImage");
2435 print_timestamp_time("InitGadgets");
2437 print_timestamp_time("InitToons");
2439 print_timestamp_done("ReinitializeGraphics");
2442 static void ReinitializeSounds()
2444 InitSoundInfo(); /* sound properties mapping */
2445 InitElementSoundInfo(); /* element game sound mapping */
2446 InitGameModeSoundInfo(); /* game mode sound mapping */
2448 InitPlayLevelSound(); /* internal game sound settings */
2451 static void ReinitializeMusic()
2453 InitMusicInfo(); /* music properties mapping */
2454 InitGameModeMusicInfo(); /* game mode music mapping */
2457 static int get_special_property_bit(int element, int property_bit_nr)
2459 struct PropertyBitInfo
2465 static struct PropertyBitInfo pb_can_move_into_acid[] =
2467 /* the player may be able fall into acid when gravity is activated */
2472 { EL_SP_MURPHY, 0 },
2473 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2475 /* all elements that can move may be able to also move into acid */
2478 { EL_BUG_RIGHT, 1 },
2481 { EL_SPACESHIP, 2 },
2482 { EL_SPACESHIP_LEFT, 2 },
2483 { EL_SPACESHIP_RIGHT, 2 },
2484 { EL_SPACESHIP_UP, 2 },
2485 { EL_SPACESHIP_DOWN, 2 },
2486 { EL_BD_BUTTERFLY, 3 },
2487 { EL_BD_BUTTERFLY_LEFT, 3 },
2488 { EL_BD_BUTTERFLY_RIGHT, 3 },
2489 { EL_BD_BUTTERFLY_UP, 3 },
2490 { EL_BD_BUTTERFLY_DOWN, 3 },
2491 { EL_BD_FIREFLY, 4 },
2492 { EL_BD_FIREFLY_LEFT, 4 },
2493 { EL_BD_FIREFLY_RIGHT, 4 },
2494 { EL_BD_FIREFLY_UP, 4 },
2495 { EL_BD_FIREFLY_DOWN, 4 },
2497 { EL_YAMYAM_LEFT, 5 },
2498 { EL_YAMYAM_RIGHT, 5 },
2499 { EL_YAMYAM_UP, 5 },
2500 { EL_YAMYAM_DOWN, 5 },
2501 { EL_DARK_YAMYAM, 6 },
2504 { EL_PACMAN_LEFT, 8 },
2505 { EL_PACMAN_RIGHT, 8 },
2506 { EL_PACMAN_UP, 8 },
2507 { EL_PACMAN_DOWN, 8 },
2509 { EL_MOLE_LEFT, 9 },
2510 { EL_MOLE_RIGHT, 9 },
2512 { EL_MOLE_DOWN, 9 },
2516 { EL_SATELLITE, 13 },
2517 { EL_SP_SNIKSNAK, 14 },
2518 { EL_SP_ELECTRON, 15 },
2521 { EL_EMC_ANDROID, 18 },
2526 static struct PropertyBitInfo pb_dont_collide_with[] =
2528 { EL_SP_SNIKSNAK, 0 },
2529 { EL_SP_ELECTRON, 1 },
2537 struct PropertyBitInfo *pb_info;
2540 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2541 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2546 struct PropertyBitInfo *pb_info = NULL;
2549 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2550 if (pb_definition[i].bit_nr == property_bit_nr)
2551 pb_info = pb_definition[i].pb_info;
2553 if (pb_info == NULL)
2556 for (i = 0; pb_info[i].element != -1; i++)
2557 if (pb_info[i].element == element)
2558 return pb_info[i].bit_nr;
2563 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2564 boolean property_value)
2566 int bit_nr = get_special_property_bit(element, property_bit_nr);
2571 *bitfield |= (1 << bit_nr);
2573 *bitfield &= ~(1 << bit_nr);
2577 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2579 int bit_nr = get_special_property_bit(element, property_bit_nr);
2582 return ((*bitfield & (1 << bit_nr)) != 0);
2587 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2589 static int group_nr;
2590 static struct ElementGroupInfo *group;
2591 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2594 if (actual_group == NULL) /* not yet initialized */
2597 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
2599 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2600 group_element - EL_GROUP_START + 1);
2602 /* replace element which caused too deep recursion by question mark */
2603 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2608 if (recursion_depth == 0) /* initialization */
2610 group = actual_group;
2611 group_nr = GROUP_NR(group_element);
2613 group->num_elements_resolved = 0;
2614 group->choice_pos = 0;
2616 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2617 element_info[i].in_group[group_nr] = FALSE;
2620 for (i = 0; i < actual_group->num_elements; i++)
2622 int element = actual_group->element[i];
2624 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2627 if (IS_GROUP_ELEMENT(element))
2628 ResolveGroupElementExt(element, recursion_depth + 1);
2631 group->element_resolved[group->num_elements_resolved++] = element;
2632 element_info[element].in_group[group_nr] = TRUE;
2637 void ResolveGroupElement(int group_element)
2639 ResolveGroupElementExt(group_element, 0);
2642 void InitElementPropertiesStatic()
2644 static boolean clipboard_elements_initialized = FALSE;
2646 static int ep_diggable[] =
2651 EL_SP_BUGGY_BASE_ACTIVATING,
2654 EL_INVISIBLE_SAND_ACTIVE,
2657 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2658 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2663 EL_SP_BUGGY_BASE_ACTIVE,
2670 static int ep_collectible_only[] =
2692 EL_DYNABOMB_INCREASE_NUMBER,
2693 EL_DYNABOMB_INCREASE_SIZE,
2694 EL_DYNABOMB_INCREASE_POWER,
2712 /* !!! handle separately !!! */
2713 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2719 static int ep_dont_run_into[] =
2721 /* same elements as in 'ep_dont_touch' */
2727 /* same elements as in 'ep_dont_collide_with' */
2739 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2744 EL_SP_BUGGY_BASE_ACTIVE,
2751 static int ep_dont_collide_with[] =
2753 /* same elements as in 'ep_dont_touch' */
2770 static int ep_dont_touch[] =
2780 static int ep_indestructible[] =
2784 EL_ACID_POOL_TOPLEFT,
2785 EL_ACID_POOL_TOPRIGHT,
2786 EL_ACID_POOL_BOTTOMLEFT,
2787 EL_ACID_POOL_BOTTOM,
2788 EL_ACID_POOL_BOTTOMRIGHT,
2789 EL_SP_HARDWARE_GRAY,
2790 EL_SP_HARDWARE_GREEN,
2791 EL_SP_HARDWARE_BLUE,
2793 EL_SP_HARDWARE_YELLOW,
2794 EL_SP_HARDWARE_BASE_1,
2795 EL_SP_HARDWARE_BASE_2,
2796 EL_SP_HARDWARE_BASE_3,
2797 EL_SP_HARDWARE_BASE_4,
2798 EL_SP_HARDWARE_BASE_5,
2799 EL_SP_HARDWARE_BASE_6,
2800 EL_INVISIBLE_STEELWALL,
2801 EL_INVISIBLE_STEELWALL_ACTIVE,
2802 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2803 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2804 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2805 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2806 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2807 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2808 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2809 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2810 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2811 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2812 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2813 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2815 EL_LIGHT_SWITCH_ACTIVE,
2816 EL_SIGN_EXCLAMATION,
2817 EL_SIGN_RADIOACTIVITY,
2824 EL_SIGN_ENTRY_FORBIDDEN,
2825 EL_SIGN_EMERGENCY_EXIT,
2833 EL_STEEL_EXIT_CLOSED,
2835 EL_STEEL_EXIT_OPENING,
2836 EL_STEEL_EXIT_CLOSING,
2837 EL_EM_STEEL_EXIT_CLOSED,
2838 EL_EM_STEEL_EXIT_OPEN,
2839 EL_EM_STEEL_EXIT_OPENING,
2840 EL_EM_STEEL_EXIT_CLOSING,
2841 EL_DC_STEELWALL_1_LEFT,
2842 EL_DC_STEELWALL_1_RIGHT,
2843 EL_DC_STEELWALL_1_TOP,
2844 EL_DC_STEELWALL_1_BOTTOM,
2845 EL_DC_STEELWALL_1_HORIZONTAL,
2846 EL_DC_STEELWALL_1_VERTICAL,
2847 EL_DC_STEELWALL_1_TOPLEFT,
2848 EL_DC_STEELWALL_1_TOPRIGHT,
2849 EL_DC_STEELWALL_1_BOTTOMLEFT,
2850 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2851 EL_DC_STEELWALL_1_TOPLEFT_2,
2852 EL_DC_STEELWALL_1_TOPRIGHT_2,
2853 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2854 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2855 EL_DC_STEELWALL_2_LEFT,
2856 EL_DC_STEELWALL_2_RIGHT,
2857 EL_DC_STEELWALL_2_TOP,
2858 EL_DC_STEELWALL_2_BOTTOM,
2859 EL_DC_STEELWALL_2_HORIZONTAL,
2860 EL_DC_STEELWALL_2_VERTICAL,
2861 EL_DC_STEELWALL_2_MIDDLE,
2862 EL_DC_STEELWALL_2_SINGLE,
2863 EL_STEELWALL_SLIPPERY,
2877 EL_GATE_1_GRAY_ACTIVE,
2878 EL_GATE_2_GRAY_ACTIVE,
2879 EL_GATE_3_GRAY_ACTIVE,
2880 EL_GATE_4_GRAY_ACTIVE,
2889 EL_EM_GATE_1_GRAY_ACTIVE,
2890 EL_EM_GATE_2_GRAY_ACTIVE,
2891 EL_EM_GATE_3_GRAY_ACTIVE,
2892 EL_EM_GATE_4_GRAY_ACTIVE,
2901 EL_EMC_GATE_5_GRAY_ACTIVE,
2902 EL_EMC_GATE_6_GRAY_ACTIVE,
2903 EL_EMC_GATE_7_GRAY_ACTIVE,
2904 EL_EMC_GATE_8_GRAY_ACTIVE,
2906 EL_DC_GATE_WHITE_GRAY,
2907 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2908 EL_DC_GATE_FAKE_GRAY,
2910 EL_SWITCHGATE_OPENING,
2911 EL_SWITCHGATE_CLOSED,
2912 EL_SWITCHGATE_CLOSING,
2914 EL_DC_SWITCHGATE_SWITCH_UP,
2915 EL_DC_SWITCHGATE_SWITCH_DOWN,
2918 EL_TIMEGATE_OPENING,
2920 EL_TIMEGATE_CLOSING,
2922 EL_DC_TIMEGATE_SWITCH,
2923 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2928 EL_TUBE_VERTICAL_LEFT,
2929 EL_TUBE_VERTICAL_RIGHT,
2930 EL_TUBE_HORIZONTAL_UP,
2931 EL_TUBE_HORIZONTAL_DOWN,
2936 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2937 EL_EXPANDABLE_STEELWALL_VERTICAL,
2938 EL_EXPANDABLE_STEELWALL_ANY,
2943 static int ep_slippery[] =
2957 EL_ROBOT_WHEEL_ACTIVE,
2963 EL_ACID_POOL_TOPLEFT,
2964 EL_ACID_POOL_TOPRIGHT,
2974 EL_STEELWALL_SLIPPERY,
2977 EL_EMC_WALL_SLIPPERY_1,
2978 EL_EMC_WALL_SLIPPERY_2,
2979 EL_EMC_WALL_SLIPPERY_3,
2980 EL_EMC_WALL_SLIPPERY_4,
2982 EL_EMC_MAGIC_BALL_ACTIVE,
2987 static int ep_can_change[] =
2992 static int ep_can_move[] =
2994 /* same elements as in 'pb_can_move_into_acid' */
3017 static int ep_can_fall[] =
3031 EL_QUICKSAND_FAST_FULL,
3033 EL_BD_MAGIC_WALL_FULL,
3034 EL_DC_MAGIC_WALL_FULL,
3048 static int ep_can_smash_player[] =
3074 static int ep_can_smash_enemies[] =
3083 static int ep_can_smash_everything[] =
3092 static int ep_explodes_by_fire[] =
3094 /* same elements as in 'ep_explodes_impact' */
3099 /* same elements as in 'ep_explodes_smashed' */
3109 EL_EM_DYNAMITE_ACTIVE,
3110 EL_DYNABOMB_PLAYER_1_ACTIVE,
3111 EL_DYNABOMB_PLAYER_2_ACTIVE,
3112 EL_DYNABOMB_PLAYER_3_ACTIVE,
3113 EL_DYNABOMB_PLAYER_4_ACTIVE,
3114 EL_DYNABOMB_INCREASE_NUMBER,
3115 EL_DYNABOMB_INCREASE_SIZE,
3116 EL_DYNABOMB_INCREASE_POWER,
3117 EL_SP_DISK_RED_ACTIVE,
3131 static int ep_explodes_smashed[] =
3133 /* same elements as in 'ep_explodes_impact' */
3147 static int ep_explodes_impact[] =
3156 static int ep_walkable_over[] =
3160 EL_SOKOBAN_FIELD_EMPTY,
3169 EL_EM_STEEL_EXIT_OPEN,
3171 EL_EM_STEEL_EXIT_OPENING,
3181 EL_GATE_1_GRAY_ACTIVE,
3182 EL_GATE_2_GRAY_ACTIVE,
3183 EL_GATE_3_GRAY_ACTIVE,
3184 EL_GATE_4_GRAY_ACTIVE,
3192 static int ep_walkable_inside[] =
3197 EL_TUBE_VERTICAL_LEFT,
3198 EL_TUBE_VERTICAL_RIGHT,
3199 EL_TUBE_HORIZONTAL_UP,
3200 EL_TUBE_HORIZONTAL_DOWN,
3209 static int ep_walkable_under[] =
3214 static int ep_passable_over[] =
3224 EL_EM_GATE_1_GRAY_ACTIVE,
3225 EL_EM_GATE_2_GRAY_ACTIVE,
3226 EL_EM_GATE_3_GRAY_ACTIVE,
3227 EL_EM_GATE_4_GRAY_ACTIVE,
3236 EL_EMC_GATE_5_GRAY_ACTIVE,
3237 EL_EMC_GATE_6_GRAY_ACTIVE,
3238 EL_EMC_GATE_7_GRAY_ACTIVE,
3239 EL_EMC_GATE_8_GRAY_ACTIVE,
3241 EL_DC_GATE_WHITE_GRAY,
3242 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3249 static int ep_passable_inside[] =
3255 EL_SP_PORT_HORIZONTAL,
3256 EL_SP_PORT_VERTICAL,
3258 EL_SP_GRAVITY_PORT_LEFT,
3259 EL_SP_GRAVITY_PORT_RIGHT,
3260 EL_SP_GRAVITY_PORT_UP,
3261 EL_SP_GRAVITY_PORT_DOWN,
3262 EL_SP_GRAVITY_ON_PORT_LEFT,
3263 EL_SP_GRAVITY_ON_PORT_RIGHT,
3264 EL_SP_GRAVITY_ON_PORT_UP,
3265 EL_SP_GRAVITY_ON_PORT_DOWN,
3266 EL_SP_GRAVITY_OFF_PORT_LEFT,
3267 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3268 EL_SP_GRAVITY_OFF_PORT_UP,
3269 EL_SP_GRAVITY_OFF_PORT_DOWN,
3274 static int ep_passable_under[] =
3279 static int ep_droppable[] =
3284 static int ep_explodes_1x1_old[] =
3289 static int ep_pushable[] =
3301 EL_SOKOBAN_FIELD_FULL,
3310 static int ep_explodes_cross_old[] =
3315 static int ep_protected[] =
3317 /* same elements as in 'ep_walkable_inside' */
3321 EL_TUBE_VERTICAL_LEFT,
3322 EL_TUBE_VERTICAL_RIGHT,
3323 EL_TUBE_HORIZONTAL_UP,
3324 EL_TUBE_HORIZONTAL_DOWN,
3330 /* same elements as in 'ep_passable_over' */
3339 EL_EM_GATE_1_GRAY_ACTIVE,
3340 EL_EM_GATE_2_GRAY_ACTIVE,
3341 EL_EM_GATE_3_GRAY_ACTIVE,
3342 EL_EM_GATE_4_GRAY_ACTIVE,
3351 EL_EMC_GATE_5_GRAY_ACTIVE,
3352 EL_EMC_GATE_6_GRAY_ACTIVE,
3353 EL_EMC_GATE_7_GRAY_ACTIVE,
3354 EL_EMC_GATE_8_GRAY_ACTIVE,
3356 EL_DC_GATE_WHITE_GRAY,
3357 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3361 /* same elements as in 'ep_passable_inside' */
3366 EL_SP_PORT_HORIZONTAL,
3367 EL_SP_PORT_VERTICAL,
3369 EL_SP_GRAVITY_PORT_LEFT,
3370 EL_SP_GRAVITY_PORT_RIGHT,
3371 EL_SP_GRAVITY_PORT_UP,
3372 EL_SP_GRAVITY_PORT_DOWN,
3373 EL_SP_GRAVITY_ON_PORT_LEFT,
3374 EL_SP_GRAVITY_ON_PORT_RIGHT,
3375 EL_SP_GRAVITY_ON_PORT_UP,
3376 EL_SP_GRAVITY_ON_PORT_DOWN,
3377 EL_SP_GRAVITY_OFF_PORT_LEFT,
3378 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3379 EL_SP_GRAVITY_OFF_PORT_UP,
3380 EL_SP_GRAVITY_OFF_PORT_DOWN,
3385 static int ep_throwable[] =
3390 static int ep_can_explode[] =
3392 /* same elements as in 'ep_explodes_impact' */
3397 /* same elements as in 'ep_explodes_smashed' */
3403 /* elements that can explode by explosion or by dragonfire */
3407 EL_EM_DYNAMITE_ACTIVE,
3408 EL_DYNABOMB_PLAYER_1_ACTIVE,
3409 EL_DYNABOMB_PLAYER_2_ACTIVE,
3410 EL_DYNABOMB_PLAYER_3_ACTIVE,
3411 EL_DYNABOMB_PLAYER_4_ACTIVE,
3412 EL_DYNABOMB_INCREASE_NUMBER,
3413 EL_DYNABOMB_INCREASE_SIZE,
3414 EL_DYNABOMB_INCREASE_POWER,
3415 EL_SP_DISK_RED_ACTIVE,
3423 /* elements that can explode only by explosion */
3429 static int ep_gravity_reachable[] =
3435 EL_INVISIBLE_SAND_ACTIVE,
3440 EL_SP_PORT_HORIZONTAL,
3441 EL_SP_PORT_VERTICAL,
3443 EL_SP_GRAVITY_PORT_LEFT,
3444 EL_SP_GRAVITY_PORT_RIGHT,
3445 EL_SP_GRAVITY_PORT_UP,
3446 EL_SP_GRAVITY_PORT_DOWN,
3447 EL_SP_GRAVITY_ON_PORT_LEFT,
3448 EL_SP_GRAVITY_ON_PORT_RIGHT,
3449 EL_SP_GRAVITY_ON_PORT_UP,
3450 EL_SP_GRAVITY_ON_PORT_DOWN,
3451 EL_SP_GRAVITY_OFF_PORT_LEFT,
3452 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3453 EL_SP_GRAVITY_OFF_PORT_UP,
3454 EL_SP_GRAVITY_OFF_PORT_DOWN,
3460 static int ep_player[] =
3467 EL_SOKOBAN_FIELD_PLAYER,
3473 static int ep_can_pass_magic_wall[] =
3487 static int ep_can_pass_dc_magic_wall[] =
3503 static int ep_switchable[] =
3507 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3508 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3509 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3510 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3511 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3512 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3513 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3514 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3515 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3516 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3517 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3518 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3519 EL_SWITCHGATE_SWITCH_UP,
3520 EL_SWITCHGATE_SWITCH_DOWN,
3521 EL_DC_SWITCHGATE_SWITCH_UP,
3522 EL_DC_SWITCHGATE_SWITCH_DOWN,
3524 EL_LIGHT_SWITCH_ACTIVE,
3526 EL_DC_TIMEGATE_SWITCH,
3527 EL_BALLOON_SWITCH_LEFT,
3528 EL_BALLOON_SWITCH_RIGHT,
3529 EL_BALLOON_SWITCH_UP,
3530 EL_BALLOON_SWITCH_DOWN,
3531 EL_BALLOON_SWITCH_ANY,
3532 EL_BALLOON_SWITCH_NONE,
3535 EL_EMC_MAGIC_BALL_SWITCH,
3536 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3541 static int ep_bd_element[] =
3575 static int ep_sp_element[] =
3577 /* should always be valid */
3580 /* standard classic Supaplex elements */
3587 EL_SP_HARDWARE_GRAY,
3595 EL_SP_GRAVITY_PORT_RIGHT,
3596 EL_SP_GRAVITY_PORT_DOWN,
3597 EL_SP_GRAVITY_PORT_LEFT,
3598 EL_SP_GRAVITY_PORT_UP,
3603 EL_SP_PORT_VERTICAL,
3604 EL_SP_PORT_HORIZONTAL,
3610 EL_SP_HARDWARE_BASE_1,
3611 EL_SP_HARDWARE_GREEN,
3612 EL_SP_HARDWARE_BLUE,
3614 EL_SP_HARDWARE_YELLOW,
3615 EL_SP_HARDWARE_BASE_2,
3616 EL_SP_HARDWARE_BASE_3,
3617 EL_SP_HARDWARE_BASE_4,
3618 EL_SP_HARDWARE_BASE_5,
3619 EL_SP_HARDWARE_BASE_6,
3623 /* additional elements that appeared in newer Supaplex levels */
3626 /* additional gravity port elements (not switching, but setting gravity) */
3627 EL_SP_GRAVITY_ON_PORT_LEFT,
3628 EL_SP_GRAVITY_ON_PORT_RIGHT,
3629 EL_SP_GRAVITY_ON_PORT_UP,
3630 EL_SP_GRAVITY_ON_PORT_DOWN,
3631 EL_SP_GRAVITY_OFF_PORT_LEFT,
3632 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3633 EL_SP_GRAVITY_OFF_PORT_UP,
3634 EL_SP_GRAVITY_OFF_PORT_DOWN,
3636 /* more than one Murphy in a level results in an inactive clone */
3639 /* runtime Supaplex elements */
3640 EL_SP_DISK_RED_ACTIVE,
3641 EL_SP_TERMINAL_ACTIVE,
3642 EL_SP_BUGGY_BASE_ACTIVATING,
3643 EL_SP_BUGGY_BASE_ACTIVE,
3650 static int ep_sb_element[] =
3655 EL_SOKOBAN_FIELD_EMPTY,
3656 EL_SOKOBAN_FIELD_FULL,
3657 EL_SOKOBAN_FIELD_PLAYER,
3662 EL_INVISIBLE_STEELWALL,
3667 static int ep_gem[] =
3679 static int ep_food_dark_yamyam[] =
3707 static int ep_food_penguin[] =
3721 static int ep_food_pig[] =
3733 static int ep_historic_wall[] =
3744 EL_GATE_1_GRAY_ACTIVE,
3745 EL_GATE_2_GRAY_ACTIVE,
3746 EL_GATE_3_GRAY_ACTIVE,
3747 EL_GATE_4_GRAY_ACTIVE,
3756 EL_EM_GATE_1_GRAY_ACTIVE,
3757 EL_EM_GATE_2_GRAY_ACTIVE,
3758 EL_EM_GATE_3_GRAY_ACTIVE,
3759 EL_EM_GATE_4_GRAY_ACTIVE,
3766 EL_EXPANDABLE_WALL_HORIZONTAL,
3767 EL_EXPANDABLE_WALL_VERTICAL,
3768 EL_EXPANDABLE_WALL_ANY,
3769 EL_EXPANDABLE_WALL_GROWING,
3770 EL_BD_EXPANDABLE_WALL,
3777 EL_SP_HARDWARE_GRAY,
3778 EL_SP_HARDWARE_GREEN,
3779 EL_SP_HARDWARE_BLUE,
3781 EL_SP_HARDWARE_YELLOW,
3782 EL_SP_HARDWARE_BASE_1,
3783 EL_SP_HARDWARE_BASE_2,
3784 EL_SP_HARDWARE_BASE_3,
3785 EL_SP_HARDWARE_BASE_4,
3786 EL_SP_HARDWARE_BASE_5,
3787 EL_SP_HARDWARE_BASE_6,
3789 EL_SP_TERMINAL_ACTIVE,
3792 EL_INVISIBLE_STEELWALL,
3793 EL_INVISIBLE_STEELWALL_ACTIVE,
3795 EL_INVISIBLE_WALL_ACTIVE,
3796 EL_STEELWALL_SLIPPERY,
3813 static int ep_historic_solid[] =
3817 EL_EXPANDABLE_WALL_HORIZONTAL,
3818 EL_EXPANDABLE_WALL_VERTICAL,
3819 EL_EXPANDABLE_WALL_ANY,
3820 EL_BD_EXPANDABLE_WALL,
3833 EL_QUICKSAND_FILLING,
3834 EL_QUICKSAND_EMPTYING,
3836 EL_MAGIC_WALL_ACTIVE,
3837 EL_MAGIC_WALL_EMPTYING,
3838 EL_MAGIC_WALL_FILLING,
3842 EL_BD_MAGIC_WALL_ACTIVE,
3843 EL_BD_MAGIC_WALL_EMPTYING,
3844 EL_BD_MAGIC_WALL_FULL,
3845 EL_BD_MAGIC_WALL_FILLING,
3846 EL_BD_MAGIC_WALL_DEAD,
3855 EL_SP_TERMINAL_ACTIVE,
3859 EL_INVISIBLE_WALL_ACTIVE,
3860 EL_SWITCHGATE_SWITCH_UP,
3861 EL_SWITCHGATE_SWITCH_DOWN,
3862 EL_DC_SWITCHGATE_SWITCH_UP,
3863 EL_DC_SWITCHGATE_SWITCH_DOWN,
3865 EL_TIMEGATE_SWITCH_ACTIVE,
3866 EL_DC_TIMEGATE_SWITCH,
3867 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3879 /* the following elements are a direct copy of "indestructible" elements,
3880 except "EL_ACID", which is "indestructible", but not "solid"! */
3885 EL_ACID_POOL_TOPLEFT,
3886 EL_ACID_POOL_TOPRIGHT,
3887 EL_ACID_POOL_BOTTOMLEFT,
3888 EL_ACID_POOL_BOTTOM,
3889 EL_ACID_POOL_BOTTOMRIGHT,
3890 EL_SP_HARDWARE_GRAY,
3891 EL_SP_HARDWARE_GREEN,
3892 EL_SP_HARDWARE_BLUE,
3894 EL_SP_HARDWARE_YELLOW,
3895 EL_SP_HARDWARE_BASE_1,
3896 EL_SP_HARDWARE_BASE_2,
3897 EL_SP_HARDWARE_BASE_3,
3898 EL_SP_HARDWARE_BASE_4,
3899 EL_SP_HARDWARE_BASE_5,
3900 EL_SP_HARDWARE_BASE_6,
3901 EL_INVISIBLE_STEELWALL,
3902 EL_INVISIBLE_STEELWALL_ACTIVE,
3903 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3904 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3905 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3906 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3907 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3908 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3909 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3910 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3911 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3912 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3913 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3914 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3916 EL_LIGHT_SWITCH_ACTIVE,
3917 EL_SIGN_EXCLAMATION,
3918 EL_SIGN_RADIOACTIVITY,
3925 EL_SIGN_ENTRY_FORBIDDEN,
3926 EL_SIGN_EMERGENCY_EXIT,
3934 EL_STEEL_EXIT_CLOSED,
3936 EL_DC_STEELWALL_1_LEFT,
3937 EL_DC_STEELWALL_1_RIGHT,
3938 EL_DC_STEELWALL_1_TOP,
3939 EL_DC_STEELWALL_1_BOTTOM,
3940 EL_DC_STEELWALL_1_HORIZONTAL,
3941 EL_DC_STEELWALL_1_VERTICAL,
3942 EL_DC_STEELWALL_1_TOPLEFT,
3943 EL_DC_STEELWALL_1_TOPRIGHT,
3944 EL_DC_STEELWALL_1_BOTTOMLEFT,
3945 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3946 EL_DC_STEELWALL_1_TOPLEFT_2,
3947 EL_DC_STEELWALL_1_TOPRIGHT_2,
3948 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3949 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3950 EL_DC_STEELWALL_2_LEFT,
3951 EL_DC_STEELWALL_2_RIGHT,
3952 EL_DC_STEELWALL_2_TOP,
3953 EL_DC_STEELWALL_2_BOTTOM,
3954 EL_DC_STEELWALL_2_HORIZONTAL,
3955 EL_DC_STEELWALL_2_VERTICAL,
3956 EL_DC_STEELWALL_2_MIDDLE,
3957 EL_DC_STEELWALL_2_SINGLE,
3958 EL_STEELWALL_SLIPPERY,
3972 EL_GATE_1_GRAY_ACTIVE,
3973 EL_GATE_2_GRAY_ACTIVE,
3974 EL_GATE_3_GRAY_ACTIVE,
3975 EL_GATE_4_GRAY_ACTIVE,
3984 EL_EM_GATE_1_GRAY_ACTIVE,
3985 EL_EM_GATE_2_GRAY_ACTIVE,
3986 EL_EM_GATE_3_GRAY_ACTIVE,
3987 EL_EM_GATE_4_GRAY_ACTIVE,
3989 EL_SWITCHGATE_OPENING,
3990 EL_SWITCHGATE_CLOSED,
3991 EL_SWITCHGATE_CLOSING,
3993 EL_TIMEGATE_OPENING,
3995 EL_TIMEGATE_CLOSING,
3999 EL_TUBE_VERTICAL_LEFT,
4000 EL_TUBE_VERTICAL_RIGHT,
4001 EL_TUBE_HORIZONTAL_UP,
4002 EL_TUBE_HORIZONTAL_DOWN,
4011 static int ep_classic_enemy[] =
4028 static int ep_belt[] =
4030 EL_CONVEYOR_BELT_1_LEFT,
4031 EL_CONVEYOR_BELT_1_MIDDLE,
4032 EL_CONVEYOR_BELT_1_RIGHT,
4033 EL_CONVEYOR_BELT_2_LEFT,
4034 EL_CONVEYOR_BELT_2_MIDDLE,
4035 EL_CONVEYOR_BELT_2_RIGHT,
4036 EL_CONVEYOR_BELT_3_LEFT,
4037 EL_CONVEYOR_BELT_3_MIDDLE,
4038 EL_CONVEYOR_BELT_3_RIGHT,
4039 EL_CONVEYOR_BELT_4_LEFT,
4040 EL_CONVEYOR_BELT_4_MIDDLE,
4041 EL_CONVEYOR_BELT_4_RIGHT,
4046 static int ep_belt_active[] =
4048 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
4049 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
4050 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
4051 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
4052 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
4053 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
4054 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
4055 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
4056 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
4057 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
4058 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
4059 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
4064 static int ep_belt_switch[] =
4066 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4067 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4068 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4069 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4070 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4071 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4072 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4073 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4074 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4075 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4076 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4077 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4082 static int ep_tube[] =
4089 EL_TUBE_HORIZONTAL_UP,
4090 EL_TUBE_HORIZONTAL_DOWN,
4092 EL_TUBE_VERTICAL_LEFT,
4093 EL_TUBE_VERTICAL_RIGHT,
4099 static int ep_acid_pool[] =
4101 EL_ACID_POOL_TOPLEFT,
4102 EL_ACID_POOL_TOPRIGHT,
4103 EL_ACID_POOL_BOTTOMLEFT,
4104 EL_ACID_POOL_BOTTOM,
4105 EL_ACID_POOL_BOTTOMRIGHT,
4110 static int ep_keygate[] =
4120 EL_GATE_1_GRAY_ACTIVE,
4121 EL_GATE_2_GRAY_ACTIVE,
4122 EL_GATE_3_GRAY_ACTIVE,
4123 EL_GATE_4_GRAY_ACTIVE,
4132 EL_EM_GATE_1_GRAY_ACTIVE,
4133 EL_EM_GATE_2_GRAY_ACTIVE,
4134 EL_EM_GATE_3_GRAY_ACTIVE,
4135 EL_EM_GATE_4_GRAY_ACTIVE,
4144 EL_EMC_GATE_5_GRAY_ACTIVE,
4145 EL_EMC_GATE_6_GRAY_ACTIVE,
4146 EL_EMC_GATE_7_GRAY_ACTIVE,
4147 EL_EMC_GATE_8_GRAY_ACTIVE,
4149 EL_DC_GATE_WHITE_GRAY,
4150 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4155 static int ep_amoeboid[] =
4167 static int ep_amoebalive[] =
4178 static int ep_has_editor_content[] =
4184 EL_SOKOBAN_FIELD_PLAYER,
4201 static int ep_can_turn_each_move[] =
4203 /* !!! do something with this one !!! */
4207 static int ep_can_grow[] =
4221 static int ep_active_bomb[] =
4224 EL_EM_DYNAMITE_ACTIVE,
4225 EL_DYNABOMB_PLAYER_1_ACTIVE,
4226 EL_DYNABOMB_PLAYER_2_ACTIVE,
4227 EL_DYNABOMB_PLAYER_3_ACTIVE,
4228 EL_DYNABOMB_PLAYER_4_ACTIVE,
4229 EL_SP_DISK_RED_ACTIVE,
4234 static int ep_inactive[] =
4244 EL_QUICKSAND_FAST_EMPTY,
4267 EL_GATE_1_GRAY_ACTIVE,
4268 EL_GATE_2_GRAY_ACTIVE,
4269 EL_GATE_3_GRAY_ACTIVE,
4270 EL_GATE_4_GRAY_ACTIVE,
4279 EL_EM_GATE_1_GRAY_ACTIVE,
4280 EL_EM_GATE_2_GRAY_ACTIVE,
4281 EL_EM_GATE_3_GRAY_ACTIVE,
4282 EL_EM_GATE_4_GRAY_ACTIVE,
4291 EL_EMC_GATE_5_GRAY_ACTIVE,
4292 EL_EMC_GATE_6_GRAY_ACTIVE,
4293 EL_EMC_GATE_7_GRAY_ACTIVE,
4294 EL_EMC_GATE_8_GRAY_ACTIVE,
4296 EL_DC_GATE_WHITE_GRAY,
4297 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4298 EL_DC_GATE_FAKE_GRAY,
4301 EL_INVISIBLE_STEELWALL,
4309 EL_WALL_EMERALD_YELLOW,
4310 EL_DYNABOMB_INCREASE_NUMBER,
4311 EL_DYNABOMB_INCREASE_SIZE,
4312 EL_DYNABOMB_INCREASE_POWER,
4316 EL_SOKOBAN_FIELD_EMPTY,
4317 EL_SOKOBAN_FIELD_FULL,
4318 EL_WALL_EMERALD_RED,
4319 EL_WALL_EMERALD_PURPLE,
4320 EL_ACID_POOL_TOPLEFT,
4321 EL_ACID_POOL_TOPRIGHT,
4322 EL_ACID_POOL_BOTTOMLEFT,
4323 EL_ACID_POOL_BOTTOM,
4324 EL_ACID_POOL_BOTTOMRIGHT,
4328 EL_BD_MAGIC_WALL_DEAD,
4330 EL_DC_MAGIC_WALL_DEAD,
4331 EL_AMOEBA_TO_DIAMOND,
4339 EL_SP_GRAVITY_PORT_RIGHT,
4340 EL_SP_GRAVITY_PORT_DOWN,
4341 EL_SP_GRAVITY_PORT_LEFT,
4342 EL_SP_GRAVITY_PORT_UP,
4343 EL_SP_PORT_HORIZONTAL,
4344 EL_SP_PORT_VERTICAL,
4355 EL_SP_HARDWARE_GRAY,
4356 EL_SP_HARDWARE_GREEN,
4357 EL_SP_HARDWARE_BLUE,
4359 EL_SP_HARDWARE_YELLOW,
4360 EL_SP_HARDWARE_BASE_1,
4361 EL_SP_HARDWARE_BASE_2,
4362 EL_SP_HARDWARE_BASE_3,
4363 EL_SP_HARDWARE_BASE_4,
4364 EL_SP_HARDWARE_BASE_5,
4365 EL_SP_HARDWARE_BASE_6,
4366 EL_SP_GRAVITY_ON_PORT_LEFT,
4367 EL_SP_GRAVITY_ON_PORT_RIGHT,
4368 EL_SP_GRAVITY_ON_PORT_UP,
4369 EL_SP_GRAVITY_ON_PORT_DOWN,
4370 EL_SP_GRAVITY_OFF_PORT_LEFT,
4371 EL_SP_GRAVITY_OFF_PORT_RIGHT,
4372 EL_SP_GRAVITY_OFF_PORT_UP,
4373 EL_SP_GRAVITY_OFF_PORT_DOWN,
4374 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4375 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4376 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4377 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4378 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4379 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4380 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4381 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4382 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4383 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4384 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4385 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4386 EL_SIGN_EXCLAMATION,
4387 EL_SIGN_RADIOACTIVITY,
4394 EL_SIGN_ENTRY_FORBIDDEN,
4395 EL_SIGN_EMERGENCY_EXIT,
4403 EL_DC_STEELWALL_1_LEFT,
4404 EL_DC_STEELWALL_1_RIGHT,
4405 EL_DC_STEELWALL_1_TOP,
4406 EL_DC_STEELWALL_1_BOTTOM,
4407 EL_DC_STEELWALL_1_HORIZONTAL,
4408 EL_DC_STEELWALL_1_VERTICAL,
4409 EL_DC_STEELWALL_1_TOPLEFT,
4410 EL_DC_STEELWALL_1_TOPRIGHT,
4411 EL_DC_STEELWALL_1_BOTTOMLEFT,
4412 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4413 EL_DC_STEELWALL_1_TOPLEFT_2,
4414 EL_DC_STEELWALL_1_TOPRIGHT_2,
4415 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4416 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4417 EL_DC_STEELWALL_2_LEFT,
4418 EL_DC_STEELWALL_2_RIGHT,
4419 EL_DC_STEELWALL_2_TOP,
4420 EL_DC_STEELWALL_2_BOTTOM,
4421 EL_DC_STEELWALL_2_HORIZONTAL,
4422 EL_DC_STEELWALL_2_VERTICAL,
4423 EL_DC_STEELWALL_2_MIDDLE,
4424 EL_DC_STEELWALL_2_SINGLE,
4425 EL_STEELWALL_SLIPPERY,
4430 EL_EMC_WALL_SLIPPERY_1,
4431 EL_EMC_WALL_SLIPPERY_2,
4432 EL_EMC_WALL_SLIPPERY_3,
4433 EL_EMC_WALL_SLIPPERY_4,
4454 static int ep_em_slippery_wall[] =
4459 static int ep_gfx_crumbled[] =
4470 static int ep_editor_cascade_active[] =
4472 EL_INTERNAL_CASCADE_BD_ACTIVE,
4473 EL_INTERNAL_CASCADE_EM_ACTIVE,
4474 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4475 EL_INTERNAL_CASCADE_RND_ACTIVE,
4476 EL_INTERNAL_CASCADE_SB_ACTIVE,
4477 EL_INTERNAL_CASCADE_SP_ACTIVE,
4478 EL_INTERNAL_CASCADE_DC_ACTIVE,
4479 EL_INTERNAL_CASCADE_DX_ACTIVE,
4480 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4481 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4482 EL_INTERNAL_CASCADE_CE_ACTIVE,
4483 EL_INTERNAL_CASCADE_GE_ACTIVE,
4484 EL_INTERNAL_CASCADE_REF_ACTIVE,
4485 EL_INTERNAL_CASCADE_USER_ACTIVE,
4486 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4491 static int ep_editor_cascade_inactive[] =
4493 EL_INTERNAL_CASCADE_BD,
4494 EL_INTERNAL_CASCADE_EM,
4495 EL_INTERNAL_CASCADE_EMC,
4496 EL_INTERNAL_CASCADE_RND,
4497 EL_INTERNAL_CASCADE_SB,
4498 EL_INTERNAL_CASCADE_SP,
4499 EL_INTERNAL_CASCADE_DC,
4500 EL_INTERNAL_CASCADE_DX,
4501 EL_INTERNAL_CASCADE_CHARS,
4502 EL_INTERNAL_CASCADE_STEEL_CHARS,
4503 EL_INTERNAL_CASCADE_CE,
4504 EL_INTERNAL_CASCADE_GE,
4505 EL_INTERNAL_CASCADE_REF,
4506 EL_INTERNAL_CASCADE_USER,
4507 EL_INTERNAL_CASCADE_DYNAMIC,
4512 static int ep_obsolete[] =
4516 EL_EM_KEY_1_FILE_OBSOLETE,
4517 EL_EM_KEY_2_FILE_OBSOLETE,
4518 EL_EM_KEY_3_FILE_OBSOLETE,
4519 EL_EM_KEY_4_FILE_OBSOLETE,
4520 EL_ENVELOPE_OBSOLETE,
4529 } element_properties[] =
4531 { ep_diggable, EP_DIGGABLE },
4532 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4533 { ep_dont_run_into, EP_DONT_RUN_INTO },
4534 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4535 { ep_dont_touch, EP_DONT_TOUCH },
4536 { ep_indestructible, EP_INDESTRUCTIBLE },
4537 { ep_slippery, EP_SLIPPERY },
4538 { ep_can_change, EP_CAN_CHANGE },
4539 { ep_can_move, EP_CAN_MOVE },
4540 { ep_can_fall, EP_CAN_FALL },
4541 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4542 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4543 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4544 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4545 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4546 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4547 { ep_walkable_over, EP_WALKABLE_OVER },
4548 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4549 { ep_walkable_under, EP_WALKABLE_UNDER },
4550 { ep_passable_over, EP_PASSABLE_OVER },
4551 { ep_passable_inside, EP_PASSABLE_INSIDE },
4552 { ep_passable_under, EP_PASSABLE_UNDER },
4553 { ep_droppable, EP_DROPPABLE },
4554 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4555 { ep_pushable, EP_PUSHABLE },
4556 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4557 { ep_protected, EP_PROTECTED },
4558 { ep_throwable, EP_THROWABLE },
4559 { ep_can_explode, EP_CAN_EXPLODE },
4560 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4562 { ep_player, EP_PLAYER },
4563 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4564 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4565 { ep_switchable, EP_SWITCHABLE },
4566 { ep_bd_element, EP_BD_ELEMENT },
4567 { ep_sp_element, EP_SP_ELEMENT },
4568 { ep_sb_element, EP_SB_ELEMENT },
4570 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4571 { ep_food_penguin, EP_FOOD_PENGUIN },
4572 { ep_food_pig, EP_FOOD_PIG },
4573 { ep_historic_wall, EP_HISTORIC_WALL },
4574 { ep_historic_solid, EP_HISTORIC_SOLID },
4575 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4576 { ep_belt, EP_BELT },
4577 { ep_belt_active, EP_BELT_ACTIVE },
4578 { ep_belt_switch, EP_BELT_SWITCH },
4579 { ep_tube, EP_TUBE },
4580 { ep_acid_pool, EP_ACID_POOL },
4581 { ep_keygate, EP_KEYGATE },
4582 { ep_amoeboid, EP_AMOEBOID },
4583 { ep_amoebalive, EP_AMOEBALIVE },
4584 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4585 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4586 { ep_can_grow, EP_CAN_GROW },
4587 { ep_active_bomb, EP_ACTIVE_BOMB },
4588 { ep_inactive, EP_INACTIVE },
4590 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4592 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4594 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4595 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4597 { ep_obsolete, EP_OBSOLETE },
4604 /* always start with reliable default values (element has no properties) */
4605 /* (but never initialize clipboard elements after the very first time) */
4606 /* (to be able to use clipboard elements between several levels) */
4607 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4608 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4609 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4610 SET_PROPERTY(i, j, FALSE);
4612 /* set all base element properties from above array definitions */
4613 for (i = 0; element_properties[i].elements != NULL; i++)
4614 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4615 SET_PROPERTY((element_properties[i].elements)[j],
4616 element_properties[i].property, TRUE);
4618 /* copy properties to some elements that are only stored in level file */
4619 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4620 for (j = 0; copy_properties[j][0] != -1; j++)
4621 if (HAS_PROPERTY(copy_properties[j][0], i))
4622 for (k = 1; k <= 4; k++)
4623 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4625 /* set static element properties that are not listed in array definitions */
4626 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4627 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4629 clipboard_elements_initialized = TRUE;
4632 void InitElementPropertiesEngine(int engine_version)
4634 static int no_wall_properties[] =
4637 EP_COLLECTIBLE_ONLY,
4639 EP_DONT_COLLIDE_WITH,
4642 EP_CAN_SMASH_PLAYER,
4643 EP_CAN_SMASH_ENEMIES,
4644 EP_CAN_SMASH_EVERYTHING,
4649 EP_FOOD_DARK_YAMYAM,
4665 /* important: after initialization in InitElementPropertiesStatic(), the
4666 elements are not again initialized to a default value; therefore all
4667 changes have to make sure that they leave the element with a defined
4668 property (which means that conditional property changes must be set to
4669 a reliable default value before) */
4671 /* resolve group elements */
4672 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4673 ResolveGroupElement(EL_GROUP_START + i);
4675 /* set all special, combined or engine dependent element properties */
4676 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4678 /* do not change (already initialized) clipboard elements here */
4679 if (IS_CLIPBOARD_ELEMENT(i))
4682 /* ---------- INACTIVE ------------------------------------------------- */
4683 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4684 i <= EL_CHAR_END) ||
4685 (i >= EL_STEEL_CHAR_START &&
4686 i <= EL_STEEL_CHAR_END)));
4688 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4689 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4690 IS_WALKABLE_INSIDE(i) ||
4691 IS_WALKABLE_UNDER(i)));
4693 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4694 IS_PASSABLE_INSIDE(i) ||
4695 IS_PASSABLE_UNDER(i)));
4697 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4698 IS_PASSABLE_OVER(i)));
4700 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4701 IS_PASSABLE_INSIDE(i)));
4703 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4704 IS_PASSABLE_UNDER(i)));
4706 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4709 /* ---------- COLLECTIBLE ---------------------------------------------- */
4710 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4714 /* ---------- SNAPPABLE ------------------------------------------------ */
4715 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4716 IS_COLLECTIBLE(i) ||
4720 /* ---------- WALL ----------------------------------------------------- */
4721 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4723 for (j = 0; no_wall_properties[j] != -1; j++)
4724 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4725 i >= EL_FIRST_RUNTIME_UNREAL)
4726 SET_PROPERTY(i, EP_WALL, FALSE);
4728 if (IS_HISTORIC_WALL(i))
4729 SET_PROPERTY(i, EP_WALL, TRUE);
4731 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4732 if (engine_version < VERSION_IDENT(2,2,0,0))
4733 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4735 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4737 !IS_COLLECTIBLE(i)));
4739 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4740 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4741 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4743 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4744 IS_INDESTRUCTIBLE(i)));
4746 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4748 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4749 else if (engine_version < VERSION_IDENT(2,2,0,0))
4750 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4752 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4756 if (IS_CUSTOM_ELEMENT(i))
4758 /* these are additional properties which are initially false when set */
4760 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4762 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4763 if (DONT_COLLIDE_WITH(i))
4764 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4766 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4767 if (CAN_SMASH_EVERYTHING(i))
4768 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4769 if (CAN_SMASH_ENEMIES(i))
4770 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4773 /* ---------- CAN_SMASH ------------------------------------------------ */
4774 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4775 CAN_SMASH_ENEMIES(i) ||
4776 CAN_SMASH_EVERYTHING(i)));
4778 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4779 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4780 EXPLODES_BY_FIRE(i)));
4782 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4783 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4784 EXPLODES_SMASHED(i)));
4786 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4787 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4788 EXPLODES_IMPACT(i)));
4790 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4791 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4793 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4794 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4795 i == EL_BLACK_ORB));
4797 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4798 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4800 IS_CUSTOM_ELEMENT(i)));
4802 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4803 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4804 i == EL_SP_ELECTRON));
4806 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4807 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4808 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4809 getMoveIntoAcidProperty(&level, i));
4811 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4812 if (MAYBE_DONT_COLLIDE_WITH(i))
4813 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4814 getDontCollideWithProperty(&level, i));
4816 /* ---------- SP_PORT -------------------------------------------------- */
4817 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4818 IS_PASSABLE_INSIDE(i)));
4820 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4821 for (j = 0; j < level.num_android_clone_elements; j++)
4822 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4824 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4826 /* ---------- CAN_CHANGE ----------------------------------------------- */
4827 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4828 for (j = 0; j < element_info[i].num_change_pages; j++)
4829 if (element_info[i].change_page[j].can_change)
4830 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4832 /* ---------- HAS_ACTION ----------------------------------------------- */
4833 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4834 for (j = 0; j < element_info[i].num_change_pages; j++)
4835 if (element_info[i].change_page[j].has_action)
4836 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4838 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4839 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4842 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4844 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4845 element_info[i].crumbled[ACTION_DEFAULT] !=
4846 element_info[i].graphic[ACTION_DEFAULT]);
4848 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
4849 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4850 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
4853 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4854 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4855 IS_EDITOR_CASCADE_INACTIVE(i)));
4858 /* dynamically adjust element properties according to game engine version */
4860 static int ep_em_slippery_wall[] =
4865 EL_EXPANDABLE_WALL_HORIZONTAL,
4866 EL_EXPANDABLE_WALL_VERTICAL,
4867 EL_EXPANDABLE_WALL_ANY,
4868 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4869 EL_EXPANDABLE_STEELWALL_VERTICAL,
4870 EL_EXPANDABLE_STEELWALL_ANY,
4871 EL_EXPANDABLE_STEELWALL_GROWING,
4875 static int ep_em_explodes_by_fire[] =
4878 EL_EM_DYNAMITE_ACTIVE,
4883 /* special EM style gems behaviour */
4884 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4885 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4886 level.em_slippery_gems);
4888 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4889 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4890 (level.em_slippery_gems &&
4891 engine_version > VERSION_IDENT(2,0,1,0)));
4893 /* special EM style explosion behaviour regarding chain reactions */
4894 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4895 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4896 level.em_explodes_by_fire);
4899 /* this is needed because some graphics depend on element properties */
4900 if (game_status == GAME_MODE_PLAYING)
4901 InitElementGraphicInfo();
4904 void InitElementPropertiesAfterLoading(int engine_version)
4908 /* set some other uninitialized values of custom elements in older levels */
4909 if (engine_version < VERSION_IDENT(3,1,0,0))
4911 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4913 int element = EL_CUSTOM_START + i;
4915 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4917 element_info[element].explosion_delay = 17;
4918 element_info[element].ignition_delay = 8;
4923 void InitElementPropertiesGfxElement()
4927 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4929 struct ElementInfo *ei = &element_info[i];
4931 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4935 static void InitGlobal()
4940 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4942 /* check if element_name_info entry defined for each element in "main.h" */
4943 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4944 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4946 element_info[i].token_name = element_name_info[i].token_name;
4947 element_info[i].class_name = element_name_info[i].class_name;
4948 element_info[i].editor_description= element_name_info[i].editor_description;
4951 printf("%04d: %s\n", i, element_name_info[i].token_name);
4955 /* create hash from image config list */
4956 image_config_hash = newSetupFileHash();
4957 for (i = 0; image_config[i].token != NULL; i++)
4958 setHashEntry(image_config_hash,
4959 image_config[i].token,
4960 image_config[i].value);
4962 /* create hash from element token list */
4963 element_token_hash = newSetupFileHash();
4964 for (i = 0; element_name_info[i].token_name != NULL; i++)
4965 setHashEntry(element_token_hash,
4966 element_name_info[i].token_name,
4969 /* create hash from graphic token list */
4970 graphic_token_hash = newSetupFileHash();
4971 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4972 if (strSuffix(image_config[i].value, ".pcx") ||
4973 strSuffix(image_config[i].value, ".wav") ||
4974 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4975 setHashEntry(graphic_token_hash,
4976 image_config[i].token,
4977 int2str(graphic++, 0));
4979 /* create hash from font token list */
4980 font_token_hash = newSetupFileHash();
4981 for (i = 0; font_info[i].token_name != NULL; i++)
4982 setHashEntry(font_token_hash,
4983 font_info[i].token_name,
4986 /* always start with reliable default values (all elements) */
4987 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4988 ActiveElement[i] = i;
4990 /* now add all entries that have an active state (active elements) */
4991 for (i = 0; element_with_active_state[i].element != -1; i++)
4993 int element = element_with_active_state[i].element;
4994 int element_active = element_with_active_state[i].element_active;
4996 ActiveElement[element] = element_active;
4999 /* always start with reliable default values (all buttons) */
5000 for (i = 0; i < NUM_IMAGE_FILES; i++)
5001 ActiveButton[i] = i;
5003 /* now add all entries that have an active state (active buttons) */
5004 for (i = 0; button_with_active_state[i].button != -1; i++)
5006 int button = button_with_active_state[i].button;
5007 int button_active = button_with_active_state[i].button_active;
5009 ActiveButton[button] = button_active;
5012 /* always start with reliable default values (all fonts) */
5013 for (i = 0; i < NUM_FONTS; i++)
5016 /* now add all entries that have an active state (active fonts) */
5017 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
5019 int font = font_with_active_state[i].font_nr;
5020 int font_active = font_with_active_state[i].font_nr_active;
5022 ActiveFont[font] = font_active;
5025 global.autoplay_leveldir = NULL;
5026 global.convert_leveldir = NULL;
5027 global.create_images_dir = NULL;
5029 global.frames_per_second = 0;
5030 global.fps_slowdown = FALSE;
5031 global.fps_slowdown_factor = 1;
5033 global.border_status = GAME_MODE_MAIN;
5035 global.fading_status = GAME_MODE_MAIN;
5036 global.fading_type = TYPE_ENTER_MENU;
5040 void Execute_Command(char *command)
5044 if (strEqual(command, "print graphicsinfo.conf"))
5046 printf("# You can configure additional/alternative image files here.\n");
5047 printf("# (The entries below are default and therefore commented out.)\n");
5049 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
5051 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5054 for (i = 0; image_config[i].token != NULL; i++)
5055 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
5056 image_config[i].value));
5060 else if (strEqual(command, "print soundsinfo.conf"))
5062 printf("# You can configure additional/alternative sound files here.\n");
5063 printf("# (The entries below are default and therefore commented out.)\n");
5065 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
5067 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5070 for (i = 0; sound_config[i].token != NULL; i++)
5071 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
5072 sound_config[i].value));
5076 else if (strEqual(command, "print musicinfo.conf"))
5078 printf("# You can configure additional/alternative music files here.\n");
5079 printf("# (The entries below are default and therefore commented out.)\n");
5081 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
5083 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5086 for (i = 0; music_config[i].token != NULL; i++)
5087 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
5088 music_config[i].value));
5092 else if (strEqual(command, "print editorsetup.conf"))
5094 printf("# You can configure your personal editor element list here.\n");
5095 printf("# (The entries below are default and therefore commented out.)\n");
5098 /* this is needed to be able to check element list for cascade elements */
5099 InitElementPropertiesStatic();
5100 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5102 PrintEditorElementList();
5106 else if (strEqual(command, "print helpanim.conf"))
5108 printf("# You can configure different element help animations here.\n");
5109 printf("# (The entries below are default and therefore commented out.)\n");
5112 for (i = 0; helpanim_config[i].token != NULL; i++)
5114 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
5115 helpanim_config[i].value));
5117 if (strEqual(helpanim_config[i].token, "end"))
5123 else if (strEqual(command, "print helptext.conf"))
5125 printf("# You can configure different element help text here.\n");
5126 printf("# (The entries below are default and therefore commented out.)\n");
5129 for (i = 0; helptext_config[i].token != NULL; i++)
5130 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
5131 helptext_config[i].value));
5135 else if (strPrefix(command, "dump level "))
5137 char *filename = &command[11];
5139 if (!fileExists(filename))
5140 Error(ERR_EXIT, "cannot open file '%s'", filename);
5142 LoadLevelFromFilename(&level, filename);
5147 else if (strPrefix(command, "dump tape "))
5149 char *filename = &command[10];
5151 if (!fileExists(filename))
5152 Error(ERR_EXIT, "cannot open file '%s'", filename);
5154 LoadTapeFromFilename(filename);
5159 else if (strPrefix(command, "autoplay "))
5161 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
5163 while (*str_ptr != '\0') /* continue parsing string */
5165 /* cut leading whitespace from string, replace it by string terminator */
5166 while (*str_ptr == ' ' || *str_ptr == '\t')
5169 if (*str_ptr == '\0') /* end of string reached */
5172 if (global.autoplay_leveldir == NULL) /* read level set string */
5174 global.autoplay_leveldir = str_ptr;
5175 global.autoplay_all = TRUE; /* default: play all tapes */
5177 for (i = 0; i < MAX_TAPES_PER_SET; i++)
5178 global.autoplay_level[i] = FALSE;
5180 else /* read level number string */
5182 int level_nr = atoi(str_ptr); /* get level_nr value */
5184 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5185 global.autoplay_level[level_nr] = TRUE;
5187 global.autoplay_all = FALSE;
5190 /* advance string pointer to the next whitespace (or end of string) */
5191 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5195 else if (strPrefix(command, "convert "))
5197 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
5198 char *str_ptr = strchr(str_copy, ' ');
5200 global.convert_leveldir = str_copy;
5201 global.convert_level_nr = -1;
5203 if (str_ptr != NULL) /* level number follows */
5205 *str_ptr++ = '\0'; /* terminate leveldir string */
5206 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
5209 else if (strPrefix(command, "create images "))
5211 #if defined(TARGET_SDL)
5212 global.create_images_dir = getStringCopy(&command[14]);
5214 if (access(global.create_images_dir, W_OK) != 0)
5215 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
5216 global.create_images_dir);
5218 Error(ERR_EXIT, "command only available for SDL target");
5223 #if defined(TARGET_SDL)
5224 else if (strEqual(command, "SDL_ListModes"))
5229 SDL_Init(SDL_INIT_VIDEO);
5231 /* get available fullscreen/hardware modes */
5232 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
5234 /* check if there are any modes available */
5237 printf("No modes available!\n");
5242 /* check if our resolution is restricted */
5243 if (modes == (SDL_Rect **)-1)
5245 printf("All resolutions available.\n");
5249 printf("Available Modes:\n");
5251 for(i = 0; modes[i]; i++)
5252 printf(" %d x %d\n", modes[i]->w, modes[i]->h);
5262 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
5266 static void InitSetup()
5268 LoadSetup(); /* global setup info */
5270 /* set some options from setup file */
5272 if (setup.options.verbose)
5273 options.verbose = TRUE;
5276 static void InitGameInfo()
5278 game.restart_level = FALSE;
5281 static void InitPlayerInfo()
5285 /* choose default local player */
5286 local_player = &stored_player[0];
5288 for (i = 0; i < MAX_PLAYERS; i++)
5289 stored_player[i].connected = FALSE;
5291 local_player->connected = TRUE;
5294 static void InitArtworkInfo()
5299 static char *get_string_in_brackets(char *string)
5301 char *string_in_brackets = checked_malloc(strlen(string) + 3);
5303 sprintf(string_in_brackets, "[%s]", string);
5305 return string_in_brackets;
5308 static char *get_level_id_suffix(int id_nr)
5310 char *id_suffix = checked_malloc(1 + 3 + 1);
5312 if (id_nr < 0 || id_nr > 999)
5315 sprintf(id_suffix, ".%03d", id_nr);
5321 static char *get_element_class_token(int element)
5323 char *element_class_name = element_info[element].class_name;
5324 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
5326 sprintf(element_class_token, "[%s]", element_class_name);
5328 return element_class_token;
5331 static char *get_action_class_token(int action)
5333 char *action_class_name = &element_action_info[action].suffix[1];
5334 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
5336 sprintf(action_class_token, "[%s]", action_class_name);
5338 return action_class_token;
5342 static void InitArtworkConfig()
5344 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
5345 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
5346 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
5347 static char *action_id_suffix[NUM_ACTIONS + 1];
5348 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5349 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5350 static char *level_id_suffix[MAX_LEVELS + 1];
5351 static char *dummy[1] = { NULL };
5352 static char *ignore_generic_tokens[] =
5358 static char **ignore_image_tokens;
5359 static char **ignore_sound_tokens;
5360 static char **ignore_music_tokens;
5361 int num_ignore_generic_tokens;
5362 int num_ignore_image_tokens;
5363 int num_ignore_sound_tokens;
5364 int num_ignore_music_tokens;
5367 /* dynamically determine list of generic tokens to be ignored */
5368 num_ignore_generic_tokens = 0;
5369 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5370 num_ignore_generic_tokens++;
5372 /* dynamically determine list of image tokens to be ignored */
5373 num_ignore_image_tokens = num_ignore_generic_tokens;
5374 for (i = 0; image_config_vars[i].token != NULL; i++)
5375 num_ignore_image_tokens++;
5376 ignore_image_tokens =
5377 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5378 for (i = 0; i < num_ignore_generic_tokens; i++)
5379 ignore_image_tokens[i] = ignore_generic_tokens[i];
5380 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5381 ignore_image_tokens[num_ignore_generic_tokens + i] =
5382 image_config_vars[i].token;
5383 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5385 /* dynamically determine list of sound tokens to be ignored */
5386 num_ignore_sound_tokens = num_ignore_generic_tokens;
5387 ignore_sound_tokens =
5388 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5389 for (i = 0; i < num_ignore_generic_tokens; i++)
5390 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5391 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5393 /* dynamically determine list of music tokens to be ignored */
5394 num_ignore_music_tokens = num_ignore_generic_tokens;
5395 ignore_music_tokens =
5396 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5397 for (i = 0; i < num_ignore_generic_tokens; i++)
5398 ignore_music_tokens[i] = ignore_generic_tokens[i];
5399 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5401 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5402 image_id_prefix[i] = element_info[i].token_name;
5403 for (i = 0; i < NUM_FONTS; i++)
5404 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5405 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
5407 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5408 sound_id_prefix[i] = element_info[i].token_name;
5409 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5410 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5411 get_string_in_brackets(element_info[i].class_name);
5412 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
5414 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5415 music_id_prefix[i] = music_prefix_info[i].prefix;
5416 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
5418 for (i = 0; i < NUM_ACTIONS; i++)
5419 action_id_suffix[i] = element_action_info[i].suffix;
5420 action_id_suffix[NUM_ACTIONS] = NULL;
5422 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5423 direction_id_suffix[i] = element_direction_info[i].suffix;
5424 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5426 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5427 special_id_suffix[i] = special_suffix_info[i].suffix;
5428 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5430 for (i = 0; i < MAX_LEVELS; i++)
5431 level_id_suffix[i] = get_level_id_suffix(i);
5432 level_id_suffix[MAX_LEVELS] = NULL;
5434 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5435 image_id_prefix, action_id_suffix, direction_id_suffix,
5436 special_id_suffix, ignore_image_tokens);
5437 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5438 sound_id_prefix, action_id_suffix, dummy,
5439 special_id_suffix, ignore_sound_tokens);
5440 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5441 music_id_prefix, special_id_suffix, level_id_suffix,
5442 dummy, ignore_music_tokens);
5445 static void InitMixer()
5452 void InitGfxBuffers()
5454 ReCreateBitmap(&bitmap_db_store, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5455 ReCreateBitmap(&bitmap_db_cross, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5456 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE, DEFAULT_DEPTH);
5457 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE, DEFAULT_DEPTH);
5458 ReCreateBitmap(&bitmap_db_door, 3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
5459 ReCreateBitmap(&bitmap_db_toons, FULL_SXSIZE, FULL_SYSIZE, DEFAULT_DEPTH);
5461 /* initialize screen properties */
5462 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5463 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5465 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5466 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5467 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5468 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5469 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5471 InitGfxBuffers_SP();
5476 struct GraphicInfo *graphic_info_last = graphic_info;
5477 char *filename_font_initial = NULL;
5478 char *filename_anim_initial = NULL;
5479 Bitmap *bitmap_font_initial = NULL;
5483 /* determine settings for initial font (for displaying startup messages) */
5484 for (i = 0; image_config[i].token != NULL; i++)
5486 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5488 char font_token[128];
5491 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5492 len_font_token = strlen(font_token);
5494 if (strEqual(image_config[i].token, font_token))
5495 filename_font_initial = image_config[i].value;
5496 else if (strlen(image_config[i].token) > len_font_token &&
5497 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5499 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5500 font_initial[j].src_x = atoi(image_config[i].value);
5501 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5502 font_initial[j].src_y = atoi(image_config[i].value);
5503 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5504 font_initial[j].width = atoi(image_config[i].value);
5505 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5506 font_initial[j].height = atoi(image_config[i].value);
5511 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5513 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5514 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5517 if (filename_font_initial == NULL) /* should not happen */
5518 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5523 /* create additional image buffers for double-buffering and cross-fading */
5524 bitmap_db_store = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5525 bitmap_db_cross = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5526 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
5527 bitmap_db_panel = CreateBitmap(DXSIZE, DYSIZE, DEFAULT_DEPTH);
5528 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
5529 bitmap_db_toons = CreateBitmap(FULL_SXSIZE, FULL_SYSIZE, DEFAULT_DEPTH);
5531 /* initialize screen properties */
5532 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5533 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5535 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5536 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5537 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5538 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5541 InitGfxCustomArtworkInfo();
5543 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5545 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5546 font_initial[j].bitmap = bitmap_font_initial;
5548 InitFontGraphicInfo();
5550 font_height = getFontHeight(FC_RED);
5553 DrawInitText(getWindowTitleString(), 20, FC_YELLOW);
5555 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
5557 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
5558 DrawInitText(PROGRAM_WEBSITE_STRING, WIN_YSIZE - 20 - font_height, FC_RED);
5560 DrawInitText("Loading graphics", 120, FC_GREEN);
5564 /* initialize busy animation with default values */
5565 int parameter[NUM_GFX_ARGS];
5566 for (i = 0; i < NUM_GFX_ARGS; i++)
5567 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5568 image_config_suffix[i].token,
5569 image_config_suffix[i].type);
5571 for (i = 0; i < NUM_GFX_ARGS; i++)
5572 printf("::: '%s' => %d\n", image_config_suffix[i].token, parameter[i]);
5576 /* determine settings for busy animation (when displaying startup messages) */
5577 for (i = 0; image_config[i].token != NULL; i++)
5579 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5580 int len_anim_token = strlen(anim_token);
5582 if (strEqual(image_config[i].token, anim_token))
5583 filename_anim_initial = image_config[i].value;
5584 else if (strlen(image_config[i].token) > len_anim_token &&
5585 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5588 for (j = 0; image_config_suffix[j].token != NULL; j++)
5590 if (strEqual(&image_config[i].token[len_anim_token],
5591 image_config_suffix[j].token))
5593 get_graphic_parameter_value(image_config[i].value,
5594 image_config_suffix[j].token,
5595 image_config_suffix[j].type);
5598 if (strEqual(&image_config[i].token[len_anim_token], ".x"))
5599 anim_initial.src_x = atoi(image_config[i].value);
5600 else if (strEqual(&image_config[i].token[len_anim_token], ".y"))
5601 anim_initial.src_y = atoi(image_config[i].value);
5602 else if (strEqual(&image_config[i].token[len_anim_token], ".width"))
5603 anim_initial.width = atoi(image_config[i].value);
5604 else if (strEqual(&image_config[i].token[len_anim_token], ".height"))
5605 anim_initial.height = atoi(image_config[i].value);
5606 else if (strEqual(&image_config[i].token[len_anim_token], ".frames"))
5607 anim_initial.anim_frames = atoi(image_config[i].value);
5608 else if (strEqual(&image_config[i].token[len_anim_token],
5609 ".frames_per_line"))
5610 anim_initial.anim_frames_per_line = atoi(image_config[i].value);
5611 else if (strEqual(&image_config[i].token[len_anim_token], ".delay"))
5612 anim_initial.anim_delay = atoi(image_config[i].value);
5617 #if defined(CREATE_SPECIAL_EDITION_RND_JUE)
5618 filename_anim_initial = "loading.pcx";
5620 parameter[GFX_ARG_X] = 0;
5621 parameter[GFX_ARG_Y] = 0;
5622 parameter[GFX_ARG_WIDTH] = 128;
5623 parameter[GFX_ARG_HEIGHT] = 40;
5624 parameter[GFX_ARG_FRAMES] = 32;
5625 parameter[GFX_ARG_DELAY] = 4;
5626 parameter[GFX_ARG_FRAMES_PER_LINE] = ARG_UNDEFINED_VALUE;
5629 if (filename_anim_initial == NULL) /* should not happen */
5630 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5632 anim_initial.bitmap = LoadCustomImage(filename_anim_initial);
5634 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
5636 set_graphic_parameters_ext(0, parameter, anim_initial.bitmap);
5639 printf("::: INIT_GFX: anim_frames_per_line == %d [%d / %d] [%d, %d]\n",
5640 graphic_info[0].anim_frames_per_line,
5641 get_scaled_graphic_width(0),
5642 graphic_info[0].width,
5643 getOriginalImageWidthFromImageID(0),
5644 graphic_info[0].scale_up_factor);
5647 graphic_info = graphic_info_last;
5649 init.busy.width = anim_initial.width;
5650 init.busy.height = anim_initial.height;
5652 InitMenuDesignSettings_Static();
5653 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5655 /* use copy of busy animation to prevent change while reloading artwork */
5660 void RedrawBackground()
5662 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
5663 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
5665 redraw_mask = REDRAW_ALL;
5668 void InitGfxBackground()
5672 fieldbuffer = bitmap_db_field;
5673 SetDrawtoField(DRAW_BACKBUFFER);
5676 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5680 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
5681 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
5684 for (x = 0; x < MAX_BUF_XSIZE; x++)
5685 for (y = 0; y < MAX_BUF_YSIZE; y++)
5688 redraw_mask = REDRAW_ALL;
5691 static void InitLevelInfo()
5693 LoadLevelInfo(); /* global level info */
5694 LoadLevelSetup_LastSeries(); /* last played series info */
5695 LoadLevelSetup_SeriesInfo(); /* last played level info */
5698 static void InitLevelArtworkInfo()
5700 LoadLevelArtworkInfo();
5703 static void InitImages()
5705 print_timestamp_init("InitImages");
5708 printf("::: leveldir_current->identifier == '%s'\n",
5709 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5710 printf("::: leveldir_current->graphics_path == '%s'\n",
5711 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5712 printf("::: leveldir_current->graphics_set == '%s'\n",
5713 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5714 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5715 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5718 setLevelArtworkDir(artwork.gfx_first);
5721 printf("::: leveldir_current->identifier == '%s'\n",
5722 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5723 printf("::: leveldir_current->graphics_path == '%s'\n",
5724 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5725 printf("::: leveldir_current->graphics_set == '%s'\n",
5726 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5727 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5728 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5732 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5733 leveldir_current->identifier,
5734 artwork.gfx_current_identifier,
5735 artwork.gfx_current->identifier,
5736 leveldir_current->graphics_set,
5737 leveldir_current->graphics_path);
5740 UPDATE_BUSY_STATE();
5742 ReloadCustomImages();
5743 print_timestamp_time("ReloadCustomImages");
5745 UPDATE_BUSY_STATE();
5747 LoadCustomElementDescriptions();
5748 print_timestamp_time("LoadCustomElementDescriptions");
5750 UPDATE_BUSY_STATE();
5752 LoadMenuDesignSettings();
5753 print_timestamp_time("LoadMenuDesignSettings");
5755 UPDATE_BUSY_STATE();
5757 ReinitializeGraphics();
5758 print_timestamp_time("ReinitializeGraphics");
5760 UPDATE_BUSY_STATE();
5762 print_timestamp_done("InitImages");
5765 static void InitSound(char *identifier)
5767 print_timestamp_init("InitSound");
5769 if (identifier == NULL)
5770 identifier = artwork.snd_current->identifier;
5772 /* set artwork path to send it to the sound server process */
5773 setLevelArtworkDir(artwork.snd_first);
5775 InitReloadCustomSounds(identifier);
5776 print_timestamp_time("InitReloadCustomSounds");
5778 ReinitializeSounds();
5779 print_timestamp_time("ReinitializeSounds");
5781 print_timestamp_done("InitSound");
5784 static void InitMusic(char *identifier)
5786 print_timestamp_init("InitMusic");
5788 if (identifier == NULL)
5789 identifier = artwork.mus_current->identifier;
5791 /* set artwork path to send it to the sound server process */
5792 setLevelArtworkDir(artwork.mus_first);
5794 InitReloadCustomMusic(identifier);
5795 print_timestamp_time("InitReloadCustomMusic");
5797 ReinitializeMusic();
5798 print_timestamp_time("ReinitializeMusic");
5800 print_timestamp_done("InitMusic");
5803 void InitNetworkServer()
5805 #if defined(NETWORK_AVALIABLE)
5809 if (!options.network)
5812 #if defined(NETWORK_AVALIABLE)
5813 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5815 if (!ConnectToServer(options.server_host, options.server_port))
5816 Error(ERR_EXIT, "cannot connect to network game server");
5818 SendToServer_PlayerName(setup.player_name);
5819 SendToServer_ProtocolVersion();
5822 SendToServer_NrWanted(nr_wanted);
5826 static boolean CheckArtworkConfigForCustomElements(char *filename)
5828 SetupFileHash *setup_file_hash;
5829 boolean redefined_ce_found = FALSE;
5831 /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */
5833 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5835 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5837 char *token = HASH_ITERATION_TOKEN(itr);
5839 if (strPrefix(token, "custom_"))
5841 redefined_ce_found = TRUE;
5846 END_HASH_ITERATION(setup_file_hash, itr)
5848 freeSetupFileHash(setup_file_hash);
5851 return redefined_ce_found;
5854 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5856 char *filename_base, *filename_local;
5857 boolean redefined_ce_found = FALSE;
5859 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5862 printf("::: leveldir_current->identifier == '%s'\n",
5863 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5864 printf("::: leveldir_current->graphics_path == '%s'\n",
5865 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5866 printf("::: leveldir_current->graphics_set == '%s'\n",
5867 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5868 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5869 leveldir_current == NULL ? "[NULL]" :
5870 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5873 /* first look for special artwork configured in level series config */
5874 filename_base = getCustomArtworkLevelConfigFilename(type);
5877 printf("::: filename_base == '%s'\n", filename_base);
5880 if (fileExists(filename_base))
5881 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5883 filename_local = getCustomArtworkConfigFilename(type);
5886 printf("::: filename_local == '%s'\n", filename_local);
5889 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5890 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5893 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5896 return redefined_ce_found;
5899 static void InitOverrideArtwork()
5901 boolean redefined_ce_found = FALSE;
5903 /* to check if this level set redefines any CEs, do not use overriding */
5904 gfx.override_level_graphics = FALSE;
5905 gfx.override_level_sounds = FALSE;
5906 gfx.override_level_music = FALSE;
5908 /* now check if this level set has definitions for custom elements */
5909 if (setup.override_level_graphics == AUTO ||
5910 setup.override_level_sounds == AUTO ||
5911 setup.override_level_music == AUTO)
5912 redefined_ce_found =
5913 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5914 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5915 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5918 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5921 if (redefined_ce_found)
5923 /* this level set has CE definitions: change "AUTO" to "FALSE" */
5924 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5925 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
5926 gfx.override_level_music = (setup.override_level_music == TRUE);
5930 /* this level set has no CE definitions: change "AUTO" to "TRUE" */
5931 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5932 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
5933 gfx.override_level_music = (setup.override_level_music != FALSE);
5937 printf("::: => %d, %d, %d\n",
5938 gfx.override_level_graphics,
5939 gfx.override_level_sounds,
5940 gfx.override_level_music);
5944 static char *getNewArtworkIdentifier(int type)
5946 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5947 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5948 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5949 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5950 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5952 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5954 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
5956 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5957 char *leveldir_identifier = leveldir_current->identifier;
5959 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
5960 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5962 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
5964 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5965 char *artwork_current_identifier;
5966 char *artwork_new_identifier = NULL; /* default: nothing has changed */
5968 /* leveldir_current may be invalid (level group, parent link) */
5969 if (!validLevelSeries(leveldir_current))
5972 /* 1st step: determine artwork set to be activated in descending order:
5973 --------------------------------------------------------------------
5974 1. setup artwork (when configured to override everything else)
5975 2. artwork set configured in "levelinfo.conf" of current level set
5976 (artwork in level directory will have priority when loading later)
5977 3. artwork in level directory (stored in artwork sub-directory)
5978 4. setup artwork (currently configured in setup menu) */
5980 if (setup_override_artwork)
5981 artwork_current_identifier = setup_artwork_set;
5982 else if (leveldir_artwork_set != NULL)
5983 artwork_current_identifier = leveldir_artwork_set;
5984 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5985 artwork_current_identifier = leveldir_identifier;
5987 artwork_current_identifier = setup_artwork_set;
5990 /* 2nd step: check if it is really needed to reload artwork set
5991 ------------------------------------------------------------ */
5994 if (type == ARTWORK_TYPE_GRAPHICS)
5995 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
5996 artwork_new_identifier,
5997 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5998 artwork_current_identifier,
5999 leveldir_current->graphics_set,
6000 leveldir_current->identifier);
6003 /* ---------- reload if level set and also artwork set has changed ------- */
6004 if (leveldir_current_identifier[type] != leveldir_identifier &&
6005 (last_has_level_artwork_set[type] || has_level_artwork_set))
6006 artwork_new_identifier = artwork_current_identifier;
6008 leveldir_current_identifier[type] = leveldir_identifier;
6009 last_has_level_artwork_set[type] = has_level_artwork_set;
6012 if (type == ARTWORK_TYPE_GRAPHICS)
6013 printf("::: 1: '%s'\n", artwork_new_identifier);
6016 /* ---------- reload if "override artwork" setting has changed ----------- */
6017 if (last_override_level_artwork[type] != setup_override_artwork)
6018 artwork_new_identifier = artwork_current_identifier;
6020 last_override_level_artwork[type] = setup_override_artwork;
6023 if (type == ARTWORK_TYPE_GRAPHICS)
6024 printf("::: 2: '%s'\n", artwork_new_identifier);
6027 /* ---------- reload if current artwork identifier has changed ----------- */
6028 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
6029 artwork_current_identifier))
6030 artwork_new_identifier = artwork_current_identifier;
6032 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
6035 if (type == ARTWORK_TYPE_GRAPHICS)
6036 printf("::: 3: '%s'\n", artwork_new_identifier);
6039 /* ---------- do not reload directly after starting ---------------------- */
6040 if (!initialized[type])
6041 artwork_new_identifier = NULL;
6043 initialized[type] = TRUE;
6046 if (type == ARTWORK_TYPE_GRAPHICS)
6047 printf("::: 4: '%s'\n", artwork_new_identifier);
6051 if (type == ARTWORK_TYPE_GRAPHICS)
6052 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
6053 artwork.gfx_current_identifier, artwork_current_identifier,
6054 artwork.gfx_current->identifier, leveldir_current->graphics_set,
6055 artwork_new_identifier);
6058 return artwork_new_identifier;
6061 void ReloadCustomArtwork(int force_reload)
6063 int last_game_status = game_status; /* save current game status */
6064 char *gfx_new_identifier;
6065 char *snd_new_identifier;
6066 char *mus_new_identifier;
6067 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
6068 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
6069 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
6070 boolean reload_needed;
6072 InitOverrideArtwork();
6074 force_reload_gfx |= AdjustGraphicsForEMC();
6076 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
6077 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
6078 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
6080 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
6081 snd_new_identifier != NULL || force_reload_snd ||
6082 mus_new_identifier != NULL || force_reload_mus);
6087 print_timestamp_init("ReloadCustomArtwork");
6089 game_status = GAME_MODE_LOADING;
6091 FadeOut(REDRAW_ALL);
6094 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6096 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
6098 print_timestamp_time("ClearRectangle");
6101 printf("::: fading in ... %d\n", fading.fade_mode);
6105 printf("::: done\n");
6108 if (gfx_new_identifier != NULL || force_reload_gfx)
6111 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
6112 artwork.gfx_current_identifier,
6114 artwork.gfx_current->identifier,
6115 leveldir_current->graphics_set);
6119 print_timestamp_time("InitImages");
6122 if (snd_new_identifier != NULL || force_reload_snd)
6124 InitSound(snd_new_identifier);
6125 print_timestamp_time("InitSound");
6128 if (mus_new_identifier != NULL || force_reload_mus)
6130 InitMusic(mus_new_identifier);
6131 print_timestamp_time("InitMusic");
6134 game_status = last_game_status; /* restore current game status */
6136 init_last = init; /* switch to new busy animation */
6139 printf("::: ----------------DELAY 1 ...\n");
6144 printf("::: FadeOut @ ReloadCustomArtwork ...\n");
6146 FadeOut(REDRAW_ALL);
6148 printf("::: FadeOut @ ReloadCustomArtwork done\n");
6153 /* force redraw of (open or closed) door graphics */
6154 SetDoorState(DOOR_OPEN_ALL);
6155 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
6160 FadeSetEnterScreen();
6161 FadeSkipNextFadeOut();
6162 // FadeSetDisabled();
6167 fading = fading_none;
6172 redraw_mask = REDRAW_ALL;
6175 print_timestamp_done("ReloadCustomArtwork");
6178 void KeyboardAutoRepeatOffUnlessAutoplay()
6180 if (global.autoplay_leveldir == NULL)
6181 KeyboardAutoRepeatOff();
6185 /* ========================================================================= */
6187 /* ========================================================================= */
6191 print_timestamp_init("OpenAll");
6193 game_status = GAME_MODE_LOADING;
6199 InitGlobal(); /* initialize some global variables */
6201 print_timestamp_time("[init global stuff]");
6203 if (options.execute_command)
6204 Execute_Command(options.execute_command);
6206 if (options.serveronly)
6208 #if defined(PLATFORM_UNIX)
6209 NetworkServer(options.server_port, options.serveronly);
6211 Error(ERR_WARN, "networking only supported in Unix version");
6214 exit(0); /* never reached, server loops forever */
6221 InitArtworkInfo(); /* needed before loading gfx, sound & music */
6222 InitArtworkConfig(); /* needed before forking sound child process */
6229 InitRND(NEW_RANDOMIZE);
6230 InitSimpleRandom(NEW_RANDOMIZE);
6234 print_timestamp_time("[init setup/config stuff]");
6237 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
6239 InitEventFilter(FilterMouseMotionEvents);
6241 print_timestamp_time("[init video stuff]");
6243 InitElementPropertiesStatic();
6244 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
6245 InitElementPropertiesGfxElement();
6247 print_timestamp_time("[init element properties stuff]");
6251 print_timestamp_time("InitGfx");
6254 print_timestamp_time("InitLevelInfo");
6256 InitLevelArtworkInfo();
6257 print_timestamp_time("InitLevelArtworkInfo");
6259 InitOverrideArtwork(); /* needs to know current level directory */
6260 print_timestamp_time("InitOverrideArtwork");
6262 InitImages(); /* needs to know current level directory */
6263 print_timestamp_time("InitImages");
6265 InitSound(NULL); /* needs to know current level directory */
6266 print_timestamp_time("InitSound");
6268 InitMusic(NULL); /* needs to know current level directory */
6269 print_timestamp_time("InitMusic");
6271 InitGfxBackground();
6281 if (global.autoplay_leveldir)
6286 else if (global.convert_leveldir)
6291 else if (global.create_images_dir)
6293 CreateLevelSketchImages();
6297 game_status = GAME_MODE_MAIN;
6300 FadeSetEnterScreen();
6301 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
6302 FadeSkipNextFadeOut();
6303 // FadeSetDisabled();
6305 fading = fading_none;
6308 print_timestamp_time("[post-artwork]");
6310 print_timestamp_done("OpenAll");
6314 InitNetworkServer();
6317 void CloseAllAndExit(int exit_value)
6322 CloseAudio(); /* called after freeing sounds (needed for SDL) */
6334 #if defined(TARGET_SDL)
6335 if (network_server) /* terminate network server */
6336 SDL_KillThread(server_thread);
6339 CloseVideoDisplay();
6340 ClosePlatformDependentStuff();
6342 if (exit_value != 0)
6343 NotifyUserAboutErrorFile();