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];
1505 /* this is only used for drawing menu buttons and text */
1506 g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
1507 g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
1508 g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
1509 g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
1512 static void set_graphic_parameters(int graphic)
1515 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1516 char **parameter_raw = image->parameter;
1517 Bitmap *src_bitmap = getBitmapFromImageID(graphic);
1518 int parameter[NUM_GFX_ARGS];
1521 /* if fallback to default artwork is done, also use the default parameters */
1522 if (image->fallback_to_default)
1523 parameter_raw = image->default_parameter;
1525 /* get integer values from string parameters */
1526 for (i = 0; i < NUM_GFX_ARGS; i++)
1527 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1528 image_config_suffix[i].token,
1529 image_config_suffix[i].type);
1531 set_graphic_parameters_ext(graphic, parameter, src_bitmap);
1535 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1536 char **parameter_raw = image->parameter;
1537 Bitmap *src_bitmap = getBitmapFromImageID(graphic);
1538 int parameter[NUM_GFX_ARGS];
1539 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1540 int anim_frames_per_line = 1;
1543 /* if fallback to default artwork is done, also use the default parameters */
1544 if (image->fallback_to_default)
1545 parameter_raw = image->default_parameter;
1547 /* get integer values from string parameters */
1548 for (i = 0; i < NUM_GFX_ARGS; i++)
1549 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1550 image_config_suffix[i].token,
1551 image_config_suffix[i].type);
1553 graphic_info[graphic].bitmap = src_bitmap;
1555 /* always start with reliable default values */
1556 graphic_info[graphic].src_image_width = 0;
1557 graphic_info[graphic].src_image_height = 0;
1558 graphic_info[graphic].src_x = 0;
1559 graphic_info[graphic].src_y = 0;
1560 graphic_info[graphic].width = TILEX; /* default for element graphics */
1561 graphic_info[graphic].height = TILEY; /* default for element graphics */
1562 graphic_info[graphic].offset_x = 0; /* one or both of these values ... */
1563 graphic_info[graphic].offset_y = 0; /* ... will be corrected later */
1564 graphic_info[graphic].offset2_x = 0; /* one or both of these values ... */
1565 graphic_info[graphic].offset2_y = 0; /* ... will be corrected later */
1566 graphic_info[graphic].swap_double_tiles = -1; /* auto-detect tile swapping */
1567 graphic_info[graphic].crumbled_like = -1; /* do not use clone element */
1568 graphic_info[graphic].diggable_like = -1; /* do not use clone element */
1569 graphic_info[graphic].border_size = TILEX / 8; /* "CRUMBLED" border size */
1570 graphic_info[graphic].scale_up_factor = 1; /* default: no scaling up */
1571 graphic_info[graphic].clone_from = -1; /* do not use clone graphic */
1572 graphic_info[graphic].anim_delay_fixed = 0;
1573 graphic_info[graphic].anim_delay_random = 0;
1574 graphic_info[graphic].post_delay_fixed = 0;
1575 graphic_info[graphic].post_delay_random = 0;
1576 graphic_info[graphic].fade_mode = FADE_MODE_DEFAULT;
1577 graphic_info[graphic].fade_delay = -1;
1578 graphic_info[graphic].post_delay = -1;
1579 graphic_info[graphic].auto_delay = -1;
1580 graphic_info[graphic].align = ALIGN_CENTER; /* default for title screens */
1581 graphic_info[graphic].valign = VALIGN_MIDDLE; /* default for title screens */
1582 graphic_info[graphic].sort_priority = 0; /* default for title screens */
1585 /* optional zoom factor for scaling up the image to a larger size */
1586 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1587 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1588 if (graphic_info[graphic].scale_up_factor < 1)
1589 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
1593 if (graphic_info[graphic].use_image_size)
1595 /* set new default bitmap size (with scaling, but without small images) */
1596 graphic_info[graphic].width = get_scaled_graphic_width(graphic);
1597 graphic_info[graphic].height = get_scaled_graphic_height(graphic);
1601 /* optional x and y tile position of animation frame sequence */
1602 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1603 graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
1604 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1605 graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
1607 /* optional x and y pixel position of animation frame sequence */
1608 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1609 graphic_info[graphic].src_x = parameter[GFX_ARG_X];
1610 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1611 graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
1613 /* optional width and height of each animation frame */
1614 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1615 graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
1616 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1617 graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
1620 /* optional zoom factor for scaling up the image to a larger size */
1621 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1622 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1623 if (graphic_info[graphic].scale_up_factor < 1)
1624 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
1629 /* get final bitmap size (with scaling, but without small images) */
1630 int src_image_width = get_scaled_graphic_width(graphic);
1631 int src_image_height = get_scaled_graphic_height(graphic);
1633 anim_frames_per_row = src_image_width / graphic_info[graphic].width;
1634 anim_frames_per_col = src_image_height / graphic_info[graphic].height;
1636 graphic_info[graphic].src_image_width = src_image_width;
1637 graphic_info[graphic].src_image_height = src_image_height;
1640 /* correct x or y offset dependent of vertical or horizontal frame order */
1641 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1643 graphic_info[graphic].offset_y =
1644 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1645 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
1646 anim_frames_per_line = anim_frames_per_col;
1648 else /* frames are ordered horizontally */
1650 graphic_info[graphic].offset_x =
1651 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1652 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
1653 anim_frames_per_line = anim_frames_per_row;
1656 /* optionally, the x and y offset of frames can be specified directly */
1657 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1658 graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
1659 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1660 graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
1662 /* optionally, moving animations may have separate start and end graphics */
1663 graphic_info[graphic].double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1665 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1666 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1668 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1669 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1670 graphic_info[graphic].offset2_y =
1671 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1672 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].height);
1673 else /* frames are ordered horizontally */
1674 graphic_info[graphic].offset2_x =
1675 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1676 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].width);
1678 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1679 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1680 graphic_info[graphic].offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1681 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1682 graphic_info[graphic].offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1684 /* optionally, the second movement tile can be specified as start tile */
1685 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1686 graphic_info[graphic].swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1688 /* automatically determine correct number of frames, if not defined */
1689 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1690 graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
1691 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1692 graphic_info[graphic].anim_frames = anim_frames_per_row;
1693 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1694 graphic_info[graphic].anim_frames = anim_frames_per_col;
1696 graphic_info[graphic].anim_frames = 1;
1698 if (graphic_info[graphic].anim_frames == 0) /* frames must be at least 1 */
1699 graphic_info[graphic].anim_frames = 1;
1701 graphic_info[graphic].anim_frames_per_line =
1702 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1703 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1705 graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
1706 if (graphic_info[graphic].anim_delay == 0) /* delay must be at least 1 */
1707 graphic_info[graphic].anim_delay = 1;
1709 graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
1711 if (graphic_info[graphic].anim_frames == 1)
1712 graphic_info[graphic].anim_mode = ANIM_NONE;
1715 /* automatically determine correct start frame, if not defined */
1716 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1717 graphic_info[graphic].anim_start_frame = 0;
1718 else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
1719 graphic_info[graphic].anim_start_frame =
1720 graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1722 graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
1724 /* animation synchronized with global frame counter, not move position */
1725 graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1727 /* optional element for cloning crumble graphics */
1728 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1729 graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1731 /* optional element for cloning digging graphics */
1732 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1733 graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1735 /* optional border size for "crumbling" diggable graphics */
1736 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1737 graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
1739 /* this is only used for player "boring" and "sleeping" actions */
1740 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1741 graphic_info[graphic].anim_delay_fixed =
1742 parameter[GFX_ARG_ANIM_DELAY_FIXED];
1743 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1744 graphic_info[graphic].anim_delay_random =
1745 parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1746 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1747 graphic_info[graphic].post_delay_fixed =
1748 parameter[GFX_ARG_POST_DELAY_FIXED];
1749 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1750 graphic_info[graphic].post_delay_random =
1751 parameter[GFX_ARG_POST_DELAY_RANDOM];
1753 /* this is only used for toon animations */
1754 graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
1755 graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY];
1757 /* this is only used for drawing font characters */
1758 graphic_info[graphic].draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1759 graphic_info[graphic].draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1761 /* this is only used for drawing envelope graphics */
1762 graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1764 /* optional graphic for cloning all graphics settings */
1765 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1766 graphic_info[graphic].clone_from = parameter[GFX_ARG_CLONE_FROM];
1768 /* optional settings for drawing title screens and title messages */
1769 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1770 graphic_info[graphic].fade_mode = parameter[GFX_ARG_FADE_MODE];
1771 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1772 graphic_info[graphic].fade_delay = parameter[GFX_ARG_FADE_DELAY];
1773 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1774 graphic_info[graphic].post_delay = parameter[GFX_ARG_POST_DELAY];
1775 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1776 graphic_info[graphic].auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1777 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1778 graphic_info[graphic].align = parameter[GFX_ARG_ALIGN];
1779 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1780 graphic_info[graphic].valign = parameter[GFX_ARG_VALIGN];
1781 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1782 graphic_info[graphic].sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1785 UPDATE_BUSY_STATE();
1788 static void set_cloned_graphic_parameters(int graphic)
1790 int fallback_graphic = IMG_CHAR_EXCLAM;
1791 int max_num_images = getImageListSize();
1792 int clone_graphic = graphic_info[graphic].clone_from;
1793 int num_references_followed = 1;
1795 while (graphic_info[clone_graphic].clone_from != -1 &&
1796 num_references_followed < max_num_images)
1798 clone_graphic = graphic_info[clone_graphic].clone_from;
1800 num_references_followed++;
1803 if (num_references_followed >= max_num_images)
1805 Error(ERR_INFO_LINE, "-");
1806 Error(ERR_INFO, "warning: error found in config file:");
1807 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1808 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1809 Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1810 Error(ERR_INFO, "custom graphic rejected for this element/action");
1812 if (graphic == fallback_graphic)
1813 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1815 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1816 Error(ERR_INFO_LINE, "-");
1818 graphic_info[graphic] = graphic_info[fallback_graphic];
1822 graphic_info[graphic] = graphic_info[clone_graphic];
1823 graphic_info[graphic].clone_from = clone_graphic;
1827 static void InitGraphicInfo()
1829 int fallback_graphic = IMG_CHAR_EXCLAM;
1830 int num_images = getImageListSize();
1833 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1834 static boolean clipmasks_initialized = FALSE;
1836 XGCValues clip_gc_values;
1837 unsigned long clip_gc_valuemask;
1838 GC copy_clipmask_gc = None;
1841 /* use image size as default values for width and height for these images */
1842 static int full_size_graphics[] =
1847 IMG_BACKGROUND_ENVELOPE_1,
1848 IMG_BACKGROUND_ENVELOPE_2,
1849 IMG_BACKGROUND_ENVELOPE_3,
1850 IMG_BACKGROUND_ENVELOPE_4,
1853 IMG_BACKGROUND_TITLE_INITIAL,
1854 IMG_BACKGROUND_TITLE,
1855 IMG_BACKGROUND_MAIN,
1856 IMG_BACKGROUND_LEVELS,
1857 IMG_BACKGROUND_SCORES,
1858 IMG_BACKGROUND_EDITOR,
1859 IMG_BACKGROUND_INFO,
1860 IMG_BACKGROUND_INFO_ELEMENTS,
1861 IMG_BACKGROUND_INFO_MUSIC,
1862 IMG_BACKGROUND_INFO_CREDITS,
1863 IMG_BACKGROUND_INFO_PROGRAM,
1864 IMG_BACKGROUND_INFO_LEVELSET,
1865 IMG_BACKGROUND_SETUP,
1866 IMG_BACKGROUND_DOOR,
1868 IMG_TITLESCREEN_INITIAL_1,
1869 IMG_TITLESCREEN_INITIAL_2,
1870 IMG_TITLESCREEN_INITIAL_3,
1871 IMG_TITLESCREEN_INITIAL_4,
1872 IMG_TITLESCREEN_INITIAL_5,
1882 checked_free(graphic_info);
1884 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1887 /* initialize "use_image_size" flag with default value */
1888 for (i = 0; i < num_images; i++)
1889 graphic_info[i].use_image_size = FALSE;
1891 /* initialize "use_image_size" flag from static configuration above */
1892 for (i = 0; full_size_graphics[i] != -1; i++)
1893 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1896 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1897 if (clipmasks_initialized)
1899 for (i = 0; i < num_images; i++)
1901 if (graphic_info[i].clip_mask)
1902 XFreePixmap(display, graphic_info[i].clip_mask);
1903 if (graphic_info[i].clip_gc)
1904 XFreeGC(display, graphic_info[i].clip_gc);
1906 graphic_info[i].clip_mask = None;
1907 graphic_info[i].clip_gc = None;
1912 /* first set all graphic paramaters ... */
1913 for (i = 0; i < num_images; i++)
1914 set_graphic_parameters(i);
1916 /* ... then copy these parameters for cloned graphics */
1917 for (i = 0; i < num_images; i++)
1918 if (graphic_info[i].clone_from != -1)
1919 set_cloned_graphic_parameters(i);
1921 for (i = 0; i < num_images; i++)
1926 int first_frame, last_frame;
1927 int src_bitmap_width, src_bitmap_height;
1929 /* now check if no animation frames are outside of the loaded image */
1931 if (graphic_info[i].bitmap == NULL)
1932 continue; /* skip check for optional images that are undefined */
1934 /* get image size (this can differ from the standard element tile size!) */
1935 width = graphic_info[i].width;
1936 height = graphic_info[i].height;
1938 /* get final bitmap size (with scaling, but without small images) */
1939 src_bitmap_width = graphic_info[i].src_image_width;
1940 src_bitmap_height = graphic_info[i].src_image_height;
1942 /* check if first animation frame is inside specified bitmap */
1945 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1948 /* this avoids calculating wrong start position for out-of-bounds frame */
1949 src_x = graphic_info[i].src_x;
1950 src_y = graphic_info[i].src_y;
1953 if (src_x < 0 || src_y < 0 ||
1954 src_x + width > src_bitmap_width ||
1955 src_y + height > src_bitmap_height)
1957 Error(ERR_INFO_LINE, "-");
1958 Error(ERR_INFO, "warning: error found in config file:");
1959 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1960 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1961 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1963 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1964 src_x, src_y, src_bitmap_width, src_bitmap_height);
1965 Error(ERR_INFO, "custom graphic rejected for this element/action");
1967 if (i == fallback_graphic)
1968 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1970 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1971 Error(ERR_INFO_LINE, "-");
1973 graphic_info[i] = graphic_info[fallback_graphic];
1976 /* check if last animation frame is inside specified bitmap */
1978 last_frame = graphic_info[i].anim_frames - 1;
1979 getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1981 if (src_x < 0 || src_y < 0 ||
1982 src_x + width > src_bitmap_width ||
1983 src_y + height > src_bitmap_height)
1985 Error(ERR_INFO_LINE, "-");
1986 Error(ERR_INFO, "warning: error found in config file:");
1987 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1988 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1989 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1991 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1992 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1993 Error(ERR_INFO, "custom graphic rejected for this element/action");
1995 if (i == fallback_graphic)
1996 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1998 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1999 Error(ERR_INFO_LINE, "-");
2001 graphic_info[i] = graphic_info[fallback_graphic];
2004 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
2005 /* currently we only need a tile clip mask from the first frame */
2006 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
2008 if (copy_clipmask_gc == None)
2010 clip_gc_values.graphics_exposures = False;
2011 clip_gc_valuemask = GCGraphicsExposures;
2012 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
2013 clip_gc_valuemask, &clip_gc_values);
2016 graphic_info[i].clip_mask =
2017 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
2019 src_pixmap = src_bitmap->clip_mask;
2020 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
2021 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
2023 clip_gc_values.graphics_exposures = False;
2024 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
2025 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
2027 graphic_info[i].clip_gc =
2028 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
2032 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
2033 if (copy_clipmask_gc)
2034 XFreeGC(display, copy_clipmask_gc);
2036 clipmasks_initialized = TRUE;
2040 static void InitElementSoundInfo()
2042 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
2043 int num_property_mappings = getSoundListPropertyMappingSize();
2046 /* set values to -1 to identify later as "uninitialized" values */
2047 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2048 for (act = 0; act < NUM_ACTIONS; act++)
2049 element_info[i].sound[act] = -1;
2051 /* initialize element/sound mapping from static configuration */
2052 for (i = 0; element_to_sound[i].element > -1; i++)
2054 int element = element_to_sound[i].element;
2055 int action = element_to_sound[i].action;
2056 int sound = element_to_sound[i].sound;
2057 boolean is_class = element_to_sound[i].is_class;
2060 action = ACTION_DEFAULT;
2063 element_info[element].sound[action] = sound;
2065 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2066 if (strEqual(element_info[j].class_name,
2067 element_info[element].class_name))
2068 element_info[j].sound[action] = sound;
2071 /* initialize element class/sound mapping from dynamic configuration */
2072 for (i = 0; i < num_property_mappings; i++)
2074 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
2075 int action = property_mapping[i].ext1_index;
2076 int sound = property_mapping[i].artwork_index;
2078 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
2082 action = ACTION_DEFAULT;
2084 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2085 if (strEqual(element_info[j].class_name,
2086 element_info[element_class].class_name))
2087 element_info[j].sound[action] = sound;
2090 /* initialize element/sound mapping from dynamic configuration */
2091 for (i = 0; i < num_property_mappings; i++)
2093 int element = property_mapping[i].base_index;
2094 int action = property_mapping[i].ext1_index;
2095 int sound = property_mapping[i].artwork_index;
2097 if (element >= MAX_NUM_ELEMENTS)
2101 action = ACTION_DEFAULT;
2103 element_info[element].sound[action] = sound;
2106 /* now set all '-1' values to element specific default values */
2107 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2109 for (act = 0; act < NUM_ACTIONS; act++)
2111 /* generic default action sound (defined by "[default]" directive) */
2112 int default_action_sound = element_info[EL_DEFAULT].sound[act];
2114 /* look for special default action sound (classic game specific) */
2115 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
2116 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
2117 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
2118 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
2119 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
2120 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
2122 /* !!! there's no such thing as a "default action sound" !!! */
2124 /* look for element specific default sound (independent from action) */
2125 if (element_info[i].sound[ACTION_DEFAULT] != -1)
2126 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
2130 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
2131 /* !!! make this better !!! */
2132 if (i == EL_EMPTY_SPACE)
2133 default_action_sound = element_info[EL_DEFAULT].sound[act];
2136 /* no sound for this specific action -- use default action sound */
2137 if (element_info[i].sound[act] == -1)
2138 element_info[i].sound[act] = default_action_sound;
2142 /* copy sound settings to some elements that are only stored in level file
2143 in native R'n'D levels, but are used by game engine in native EM levels */
2144 for (i = 0; copy_properties[i][0] != -1; i++)
2145 for (j = 1; j <= 4; j++)
2146 for (act = 0; act < NUM_ACTIONS; act++)
2147 element_info[copy_properties[i][j]].sound[act] =
2148 element_info[copy_properties[i][0]].sound[act];
2151 static void InitGameModeSoundInfo()
2155 /* set values to -1 to identify later as "uninitialized" values */
2156 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2159 /* initialize gamemode/sound mapping from static configuration */
2160 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
2162 int gamemode = gamemode_to_sound[i].gamemode;
2163 int sound = gamemode_to_sound[i].sound;
2166 gamemode = GAME_MODE_DEFAULT;
2168 menu.sound[gamemode] = sound;
2171 /* now set all '-1' values to levelset specific default values */
2172 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2173 if (menu.sound[i] == -1)
2174 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
2177 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2178 if (menu.sound[i] != -1)
2179 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
2183 static void set_sound_parameters(int sound, char **parameter_raw)
2185 int parameter[NUM_SND_ARGS];
2188 /* get integer values from string parameters */
2189 for (i = 0; i < NUM_SND_ARGS; i++)
2191 get_parameter_value(parameter_raw[i],
2192 sound_config_suffix[i].token,
2193 sound_config_suffix[i].type);
2195 /* explicit loop mode setting in configuration overrides default value */
2196 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2197 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
2199 /* sound volume to change the original volume when loading the sound file */
2200 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
2202 /* sound priority to give certain sounds a higher or lower priority */
2203 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
2206 static void InitSoundInfo()
2208 int *sound_effect_properties;
2209 int num_sounds = getSoundListSize();
2212 checked_free(sound_info);
2214 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
2215 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
2217 /* initialize sound effect for all elements to "no sound" */
2218 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2219 for (j = 0; j < NUM_ACTIONS; j++)
2220 element_info[i].sound[j] = SND_UNDEFINED;
2222 for (i = 0; i < num_sounds; i++)
2224 struct FileInfo *sound = getSoundListEntry(i);
2225 int len_effect_text = strlen(sound->token);
2227 sound_effect_properties[i] = ACTION_OTHER;
2228 sound_info[i].loop = FALSE; /* default: play sound only once */
2231 printf("::: sound %d: '%s'\n", i, sound->token);
2234 /* determine all loop sounds and identify certain sound classes */
2236 for (j = 0; element_action_info[j].suffix; j++)
2238 int len_action_text = strlen(element_action_info[j].suffix);
2240 if (len_action_text < len_effect_text &&
2241 strEqual(&sound->token[len_effect_text - len_action_text],
2242 element_action_info[j].suffix))
2244 sound_effect_properties[i] = element_action_info[j].value;
2245 sound_info[i].loop = element_action_info[j].is_loop_sound;
2251 /* associate elements and some selected sound actions */
2253 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2255 if (element_info[j].class_name)
2257 int len_class_text = strlen(element_info[j].class_name);
2259 if (len_class_text + 1 < len_effect_text &&
2260 strncmp(sound->token,
2261 element_info[j].class_name, len_class_text) == 0 &&
2262 sound->token[len_class_text] == '.')
2264 int sound_action_value = sound_effect_properties[i];
2266 element_info[j].sound[sound_action_value] = i;
2271 set_sound_parameters(i, sound->parameter);
2274 free(sound_effect_properties);
2277 static void InitGameModeMusicInfo()
2279 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
2280 int num_property_mappings = getMusicListPropertyMappingSize();
2281 int default_levelset_music = -1;
2284 /* set values to -1 to identify later as "uninitialized" values */
2285 for (i = 0; i < MAX_LEVELS; i++)
2286 levelset.music[i] = -1;
2287 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2290 /* initialize gamemode/music mapping from static configuration */
2291 for (i = 0; gamemode_to_music[i].music > -1; i++)
2293 int gamemode = gamemode_to_music[i].gamemode;
2294 int music = gamemode_to_music[i].music;
2297 printf("::: gamemode == %d, music == %d\n", gamemode, music);
2301 gamemode = GAME_MODE_DEFAULT;
2303 menu.music[gamemode] = music;
2306 /* initialize gamemode/music mapping from dynamic configuration */
2307 for (i = 0; i < num_property_mappings; i++)
2309 int prefix = property_mapping[i].base_index;
2310 int gamemode = property_mapping[i].ext1_index;
2311 int level = property_mapping[i].ext2_index;
2312 int music = property_mapping[i].artwork_index;
2315 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
2316 prefix, gamemode, level, music);
2319 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
2323 gamemode = GAME_MODE_DEFAULT;
2325 /* level specific music only allowed for in-game music */
2326 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
2327 gamemode = GAME_MODE_PLAYING;
2332 default_levelset_music = music;
2335 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
2336 levelset.music[level] = music;
2337 if (gamemode != GAME_MODE_PLAYING)
2338 menu.music[gamemode] = music;
2341 /* now set all '-1' values to menu specific default values */
2342 /* (undefined values of "levelset.music[]" might stay at "-1" to
2343 allow dynamic selection of music files from music directory!) */
2344 for (i = 0; i < MAX_LEVELS; i++)
2345 if (levelset.music[i] == -1)
2346 levelset.music[i] = default_levelset_music;
2347 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2348 if (menu.music[i] == -1)
2349 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
2352 for (i = 0; i < MAX_LEVELS; i++)
2353 if (levelset.music[i] != -1)
2354 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
2355 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2356 if (menu.music[i] != -1)
2357 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
2361 static void set_music_parameters(int music, char **parameter_raw)
2363 int parameter[NUM_MUS_ARGS];
2366 /* get integer values from string parameters */
2367 for (i = 0; i < NUM_MUS_ARGS; i++)
2369 get_parameter_value(parameter_raw[i],
2370 music_config_suffix[i].token,
2371 music_config_suffix[i].type);
2373 /* explicit loop mode setting in configuration overrides default value */
2374 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2375 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
2378 static void InitMusicInfo()
2380 int num_music = getMusicListSize();
2383 checked_free(music_info);
2385 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
2387 for (i = 0; i < num_music; i++)
2389 struct FileInfo *music = getMusicListEntry(i);
2390 int len_music_text = strlen(music->token);
2392 music_info[i].loop = TRUE; /* default: play music in loop mode */
2394 /* determine all loop music */
2396 for (j = 0; music_prefix_info[j].prefix; j++)
2398 int len_prefix_text = strlen(music_prefix_info[j].prefix);
2400 if (len_prefix_text < len_music_text &&
2401 strncmp(music->token,
2402 music_prefix_info[j].prefix, len_prefix_text) == 0)
2404 music_info[i].loop = music_prefix_info[j].is_loop_music;
2410 set_music_parameters(i, music->parameter);
2414 static void ReinitializeGraphics()
2416 print_timestamp_init("ReinitializeGraphics");
2418 InitGraphicInfo(); /* graphic properties mapping */
2419 print_timestamp_time("InitGraphicInfo");
2420 InitElementGraphicInfo(); /* element game graphic mapping */
2421 print_timestamp_time("InitElementGraphicInfo");
2422 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
2423 print_timestamp_time("InitElementSpecialGraphicInfo");
2425 InitElementSmallImages(); /* scale elements to all needed sizes */
2426 print_timestamp_time("InitElementSmallImages");
2427 InitScaledImages(); /* scale all other images, if needed */
2428 print_timestamp_time("InitScaledImages");
2429 InitFontGraphicInfo(); /* initialize text drawing functions */
2430 print_timestamp_time("InitFontGraphicInfo");
2432 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
2433 print_timestamp_time("InitGraphicInfo_EM");
2435 SetMainBackgroundImage(IMG_BACKGROUND);
2436 print_timestamp_time("SetMainBackgroundImage");
2437 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2438 print_timestamp_time("SetDoorBackgroundImage");
2441 print_timestamp_time("InitGadgets");
2443 print_timestamp_time("InitToons");
2445 print_timestamp_done("ReinitializeGraphics");
2448 static void ReinitializeSounds()
2450 InitSoundInfo(); /* sound properties mapping */
2451 InitElementSoundInfo(); /* element game sound mapping */
2452 InitGameModeSoundInfo(); /* game mode sound mapping */
2454 InitPlayLevelSound(); /* internal game sound settings */
2457 static void ReinitializeMusic()
2459 InitMusicInfo(); /* music properties mapping */
2460 InitGameModeMusicInfo(); /* game mode music mapping */
2463 static int get_special_property_bit(int element, int property_bit_nr)
2465 struct PropertyBitInfo
2471 static struct PropertyBitInfo pb_can_move_into_acid[] =
2473 /* the player may be able fall into acid when gravity is activated */
2478 { EL_SP_MURPHY, 0 },
2479 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2481 /* all elements that can move may be able to also move into acid */
2484 { EL_BUG_RIGHT, 1 },
2487 { EL_SPACESHIP, 2 },
2488 { EL_SPACESHIP_LEFT, 2 },
2489 { EL_SPACESHIP_RIGHT, 2 },
2490 { EL_SPACESHIP_UP, 2 },
2491 { EL_SPACESHIP_DOWN, 2 },
2492 { EL_BD_BUTTERFLY, 3 },
2493 { EL_BD_BUTTERFLY_LEFT, 3 },
2494 { EL_BD_BUTTERFLY_RIGHT, 3 },
2495 { EL_BD_BUTTERFLY_UP, 3 },
2496 { EL_BD_BUTTERFLY_DOWN, 3 },
2497 { EL_BD_FIREFLY, 4 },
2498 { EL_BD_FIREFLY_LEFT, 4 },
2499 { EL_BD_FIREFLY_RIGHT, 4 },
2500 { EL_BD_FIREFLY_UP, 4 },
2501 { EL_BD_FIREFLY_DOWN, 4 },
2503 { EL_YAMYAM_LEFT, 5 },
2504 { EL_YAMYAM_RIGHT, 5 },
2505 { EL_YAMYAM_UP, 5 },
2506 { EL_YAMYAM_DOWN, 5 },
2507 { EL_DARK_YAMYAM, 6 },
2510 { EL_PACMAN_LEFT, 8 },
2511 { EL_PACMAN_RIGHT, 8 },
2512 { EL_PACMAN_UP, 8 },
2513 { EL_PACMAN_DOWN, 8 },
2515 { EL_MOLE_LEFT, 9 },
2516 { EL_MOLE_RIGHT, 9 },
2518 { EL_MOLE_DOWN, 9 },
2522 { EL_SATELLITE, 13 },
2523 { EL_SP_SNIKSNAK, 14 },
2524 { EL_SP_ELECTRON, 15 },
2527 { EL_EMC_ANDROID, 18 },
2532 static struct PropertyBitInfo pb_dont_collide_with[] =
2534 { EL_SP_SNIKSNAK, 0 },
2535 { EL_SP_ELECTRON, 1 },
2543 struct PropertyBitInfo *pb_info;
2546 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2547 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2552 struct PropertyBitInfo *pb_info = NULL;
2555 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2556 if (pb_definition[i].bit_nr == property_bit_nr)
2557 pb_info = pb_definition[i].pb_info;
2559 if (pb_info == NULL)
2562 for (i = 0; pb_info[i].element != -1; i++)
2563 if (pb_info[i].element == element)
2564 return pb_info[i].bit_nr;
2569 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2570 boolean property_value)
2572 int bit_nr = get_special_property_bit(element, property_bit_nr);
2577 *bitfield |= (1 << bit_nr);
2579 *bitfield &= ~(1 << bit_nr);
2583 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2585 int bit_nr = get_special_property_bit(element, property_bit_nr);
2588 return ((*bitfield & (1 << bit_nr)) != 0);
2593 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2595 static int group_nr;
2596 static struct ElementGroupInfo *group;
2597 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2600 if (actual_group == NULL) /* not yet initialized */
2603 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
2605 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2606 group_element - EL_GROUP_START + 1);
2608 /* replace element which caused too deep recursion by question mark */
2609 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2614 if (recursion_depth == 0) /* initialization */
2616 group = actual_group;
2617 group_nr = GROUP_NR(group_element);
2619 group->num_elements_resolved = 0;
2620 group->choice_pos = 0;
2622 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2623 element_info[i].in_group[group_nr] = FALSE;
2626 for (i = 0; i < actual_group->num_elements; i++)
2628 int element = actual_group->element[i];
2630 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2633 if (IS_GROUP_ELEMENT(element))
2634 ResolveGroupElementExt(element, recursion_depth + 1);
2637 group->element_resolved[group->num_elements_resolved++] = element;
2638 element_info[element].in_group[group_nr] = TRUE;
2643 void ResolveGroupElement(int group_element)
2645 ResolveGroupElementExt(group_element, 0);
2648 void InitElementPropertiesStatic()
2650 static boolean clipboard_elements_initialized = FALSE;
2652 static int ep_diggable[] =
2657 EL_SP_BUGGY_BASE_ACTIVATING,
2660 EL_INVISIBLE_SAND_ACTIVE,
2663 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2664 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2669 EL_SP_BUGGY_BASE_ACTIVE,
2676 static int ep_collectible_only[] =
2698 EL_DYNABOMB_INCREASE_NUMBER,
2699 EL_DYNABOMB_INCREASE_SIZE,
2700 EL_DYNABOMB_INCREASE_POWER,
2718 /* !!! handle separately !!! */
2719 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2725 static int ep_dont_run_into[] =
2727 /* same elements as in 'ep_dont_touch' */
2733 /* same elements as in 'ep_dont_collide_with' */
2745 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2750 EL_SP_BUGGY_BASE_ACTIVE,
2757 static int ep_dont_collide_with[] =
2759 /* same elements as in 'ep_dont_touch' */
2776 static int ep_dont_touch[] =
2786 static int ep_indestructible[] =
2790 EL_ACID_POOL_TOPLEFT,
2791 EL_ACID_POOL_TOPRIGHT,
2792 EL_ACID_POOL_BOTTOMLEFT,
2793 EL_ACID_POOL_BOTTOM,
2794 EL_ACID_POOL_BOTTOMRIGHT,
2795 EL_SP_HARDWARE_GRAY,
2796 EL_SP_HARDWARE_GREEN,
2797 EL_SP_HARDWARE_BLUE,
2799 EL_SP_HARDWARE_YELLOW,
2800 EL_SP_HARDWARE_BASE_1,
2801 EL_SP_HARDWARE_BASE_2,
2802 EL_SP_HARDWARE_BASE_3,
2803 EL_SP_HARDWARE_BASE_4,
2804 EL_SP_HARDWARE_BASE_5,
2805 EL_SP_HARDWARE_BASE_6,
2806 EL_INVISIBLE_STEELWALL,
2807 EL_INVISIBLE_STEELWALL_ACTIVE,
2808 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2809 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2810 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2811 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2812 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2813 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2814 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2815 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2816 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2817 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2818 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2819 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2821 EL_LIGHT_SWITCH_ACTIVE,
2822 EL_SIGN_EXCLAMATION,
2823 EL_SIGN_RADIOACTIVITY,
2830 EL_SIGN_ENTRY_FORBIDDEN,
2831 EL_SIGN_EMERGENCY_EXIT,
2839 EL_STEEL_EXIT_CLOSED,
2841 EL_STEEL_EXIT_OPENING,
2842 EL_STEEL_EXIT_CLOSING,
2843 EL_EM_STEEL_EXIT_CLOSED,
2844 EL_EM_STEEL_EXIT_OPEN,
2845 EL_EM_STEEL_EXIT_OPENING,
2846 EL_EM_STEEL_EXIT_CLOSING,
2847 EL_DC_STEELWALL_1_LEFT,
2848 EL_DC_STEELWALL_1_RIGHT,
2849 EL_DC_STEELWALL_1_TOP,
2850 EL_DC_STEELWALL_1_BOTTOM,
2851 EL_DC_STEELWALL_1_HORIZONTAL,
2852 EL_DC_STEELWALL_1_VERTICAL,
2853 EL_DC_STEELWALL_1_TOPLEFT,
2854 EL_DC_STEELWALL_1_TOPRIGHT,
2855 EL_DC_STEELWALL_1_BOTTOMLEFT,
2856 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2857 EL_DC_STEELWALL_1_TOPLEFT_2,
2858 EL_DC_STEELWALL_1_TOPRIGHT_2,
2859 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2860 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2861 EL_DC_STEELWALL_2_LEFT,
2862 EL_DC_STEELWALL_2_RIGHT,
2863 EL_DC_STEELWALL_2_TOP,
2864 EL_DC_STEELWALL_2_BOTTOM,
2865 EL_DC_STEELWALL_2_HORIZONTAL,
2866 EL_DC_STEELWALL_2_VERTICAL,
2867 EL_DC_STEELWALL_2_MIDDLE,
2868 EL_DC_STEELWALL_2_SINGLE,
2869 EL_STEELWALL_SLIPPERY,
2883 EL_GATE_1_GRAY_ACTIVE,
2884 EL_GATE_2_GRAY_ACTIVE,
2885 EL_GATE_3_GRAY_ACTIVE,
2886 EL_GATE_4_GRAY_ACTIVE,
2895 EL_EM_GATE_1_GRAY_ACTIVE,
2896 EL_EM_GATE_2_GRAY_ACTIVE,
2897 EL_EM_GATE_3_GRAY_ACTIVE,
2898 EL_EM_GATE_4_GRAY_ACTIVE,
2907 EL_EMC_GATE_5_GRAY_ACTIVE,
2908 EL_EMC_GATE_6_GRAY_ACTIVE,
2909 EL_EMC_GATE_7_GRAY_ACTIVE,
2910 EL_EMC_GATE_8_GRAY_ACTIVE,
2912 EL_DC_GATE_WHITE_GRAY,
2913 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2914 EL_DC_GATE_FAKE_GRAY,
2916 EL_SWITCHGATE_OPENING,
2917 EL_SWITCHGATE_CLOSED,
2918 EL_SWITCHGATE_CLOSING,
2920 EL_DC_SWITCHGATE_SWITCH_UP,
2921 EL_DC_SWITCHGATE_SWITCH_DOWN,
2924 EL_TIMEGATE_OPENING,
2926 EL_TIMEGATE_CLOSING,
2928 EL_DC_TIMEGATE_SWITCH,
2929 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2934 EL_TUBE_VERTICAL_LEFT,
2935 EL_TUBE_VERTICAL_RIGHT,
2936 EL_TUBE_HORIZONTAL_UP,
2937 EL_TUBE_HORIZONTAL_DOWN,
2942 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2943 EL_EXPANDABLE_STEELWALL_VERTICAL,
2944 EL_EXPANDABLE_STEELWALL_ANY,
2949 static int ep_slippery[] =
2963 EL_ROBOT_WHEEL_ACTIVE,
2969 EL_ACID_POOL_TOPLEFT,
2970 EL_ACID_POOL_TOPRIGHT,
2980 EL_STEELWALL_SLIPPERY,
2983 EL_EMC_WALL_SLIPPERY_1,
2984 EL_EMC_WALL_SLIPPERY_2,
2985 EL_EMC_WALL_SLIPPERY_3,
2986 EL_EMC_WALL_SLIPPERY_4,
2988 EL_EMC_MAGIC_BALL_ACTIVE,
2993 static int ep_can_change[] =
2998 static int ep_can_move[] =
3000 /* same elements as in 'pb_can_move_into_acid' */
3023 static int ep_can_fall[] =
3037 EL_QUICKSAND_FAST_FULL,
3039 EL_BD_MAGIC_WALL_FULL,
3040 EL_DC_MAGIC_WALL_FULL,
3054 static int ep_can_smash_player[] =
3080 static int ep_can_smash_enemies[] =
3089 static int ep_can_smash_everything[] =
3098 static int ep_explodes_by_fire[] =
3100 /* same elements as in 'ep_explodes_impact' */
3105 /* same elements as in 'ep_explodes_smashed' */
3115 EL_EM_DYNAMITE_ACTIVE,
3116 EL_DYNABOMB_PLAYER_1_ACTIVE,
3117 EL_DYNABOMB_PLAYER_2_ACTIVE,
3118 EL_DYNABOMB_PLAYER_3_ACTIVE,
3119 EL_DYNABOMB_PLAYER_4_ACTIVE,
3120 EL_DYNABOMB_INCREASE_NUMBER,
3121 EL_DYNABOMB_INCREASE_SIZE,
3122 EL_DYNABOMB_INCREASE_POWER,
3123 EL_SP_DISK_RED_ACTIVE,
3137 static int ep_explodes_smashed[] =
3139 /* same elements as in 'ep_explodes_impact' */
3153 static int ep_explodes_impact[] =
3162 static int ep_walkable_over[] =
3166 EL_SOKOBAN_FIELD_EMPTY,
3175 EL_EM_STEEL_EXIT_OPEN,
3177 EL_EM_STEEL_EXIT_OPENING,
3187 EL_GATE_1_GRAY_ACTIVE,
3188 EL_GATE_2_GRAY_ACTIVE,
3189 EL_GATE_3_GRAY_ACTIVE,
3190 EL_GATE_4_GRAY_ACTIVE,
3198 static int ep_walkable_inside[] =
3203 EL_TUBE_VERTICAL_LEFT,
3204 EL_TUBE_VERTICAL_RIGHT,
3205 EL_TUBE_HORIZONTAL_UP,
3206 EL_TUBE_HORIZONTAL_DOWN,
3215 static int ep_walkable_under[] =
3220 static int ep_passable_over[] =
3230 EL_EM_GATE_1_GRAY_ACTIVE,
3231 EL_EM_GATE_2_GRAY_ACTIVE,
3232 EL_EM_GATE_3_GRAY_ACTIVE,
3233 EL_EM_GATE_4_GRAY_ACTIVE,
3242 EL_EMC_GATE_5_GRAY_ACTIVE,
3243 EL_EMC_GATE_6_GRAY_ACTIVE,
3244 EL_EMC_GATE_7_GRAY_ACTIVE,
3245 EL_EMC_GATE_8_GRAY_ACTIVE,
3247 EL_DC_GATE_WHITE_GRAY,
3248 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3255 static int ep_passable_inside[] =
3261 EL_SP_PORT_HORIZONTAL,
3262 EL_SP_PORT_VERTICAL,
3264 EL_SP_GRAVITY_PORT_LEFT,
3265 EL_SP_GRAVITY_PORT_RIGHT,
3266 EL_SP_GRAVITY_PORT_UP,
3267 EL_SP_GRAVITY_PORT_DOWN,
3268 EL_SP_GRAVITY_ON_PORT_LEFT,
3269 EL_SP_GRAVITY_ON_PORT_RIGHT,
3270 EL_SP_GRAVITY_ON_PORT_UP,
3271 EL_SP_GRAVITY_ON_PORT_DOWN,
3272 EL_SP_GRAVITY_OFF_PORT_LEFT,
3273 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3274 EL_SP_GRAVITY_OFF_PORT_UP,
3275 EL_SP_GRAVITY_OFF_PORT_DOWN,
3280 static int ep_passable_under[] =
3285 static int ep_droppable[] =
3290 static int ep_explodes_1x1_old[] =
3295 static int ep_pushable[] =
3307 EL_SOKOBAN_FIELD_FULL,
3316 static int ep_explodes_cross_old[] =
3321 static int ep_protected[] =
3323 /* same elements as in 'ep_walkable_inside' */
3327 EL_TUBE_VERTICAL_LEFT,
3328 EL_TUBE_VERTICAL_RIGHT,
3329 EL_TUBE_HORIZONTAL_UP,
3330 EL_TUBE_HORIZONTAL_DOWN,
3336 /* same elements as in 'ep_passable_over' */
3345 EL_EM_GATE_1_GRAY_ACTIVE,
3346 EL_EM_GATE_2_GRAY_ACTIVE,
3347 EL_EM_GATE_3_GRAY_ACTIVE,
3348 EL_EM_GATE_4_GRAY_ACTIVE,
3357 EL_EMC_GATE_5_GRAY_ACTIVE,
3358 EL_EMC_GATE_6_GRAY_ACTIVE,
3359 EL_EMC_GATE_7_GRAY_ACTIVE,
3360 EL_EMC_GATE_8_GRAY_ACTIVE,
3362 EL_DC_GATE_WHITE_GRAY,
3363 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3367 /* same elements as in 'ep_passable_inside' */
3372 EL_SP_PORT_HORIZONTAL,
3373 EL_SP_PORT_VERTICAL,
3375 EL_SP_GRAVITY_PORT_LEFT,
3376 EL_SP_GRAVITY_PORT_RIGHT,
3377 EL_SP_GRAVITY_PORT_UP,
3378 EL_SP_GRAVITY_PORT_DOWN,
3379 EL_SP_GRAVITY_ON_PORT_LEFT,
3380 EL_SP_GRAVITY_ON_PORT_RIGHT,
3381 EL_SP_GRAVITY_ON_PORT_UP,
3382 EL_SP_GRAVITY_ON_PORT_DOWN,
3383 EL_SP_GRAVITY_OFF_PORT_LEFT,
3384 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3385 EL_SP_GRAVITY_OFF_PORT_UP,
3386 EL_SP_GRAVITY_OFF_PORT_DOWN,
3391 static int ep_throwable[] =
3396 static int ep_can_explode[] =
3398 /* same elements as in 'ep_explodes_impact' */
3403 /* same elements as in 'ep_explodes_smashed' */
3409 /* elements that can explode by explosion or by dragonfire */
3413 EL_EM_DYNAMITE_ACTIVE,
3414 EL_DYNABOMB_PLAYER_1_ACTIVE,
3415 EL_DYNABOMB_PLAYER_2_ACTIVE,
3416 EL_DYNABOMB_PLAYER_3_ACTIVE,
3417 EL_DYNABOMB_PLAYER_4_ACTIVE,
3418 EL_DYNABOMB_INCREASE_NUMBER,
3419 EL_DYNABOMB_INCREASE_SIZE,
3420 EL_DYNABOMB_INCREASE_POWER,
3421 EL_SP_DISK_RED_ACTIVE,
3429 /* elements that can explode only by explosion */
3435 static int ep_gravity_reachable[] =
3441 EL_INVISIBLE_SAND_ACTIVE,
3446 EL_SP_PORT_HORIZONTAL,
3447 EL_SP_PORT_VERTICAL,
3449 EL_SP_GRAVITY_PORT_LEFT,
3450 EL_SP_GRAVITY_PORT_RIGHT,
3451 EL_SP_GRAVITY_PORT_UP,
3452 EL_SP_GRAVITY_PORT_DOWN,
3453 EL_SP_GRAVITY_ON_PORT_LEFT,
3454 EL_SP_GRAVITY_ON_PORT_RIGHT,
3455 EL_SP_GRAVITY_ON_PORT_UP,
3456 EL_SP_GRAVITY_ON_PORT_DOWN,
3457 EL_SP_GRAVITY_OFF_PORT_LEFT,
3458 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3459 EL_SP_GRAVITY_OFF_PORT_UP,
3460 EL_SP_GRAVITY_OFF_PORT_DOWN,
3466 static int ep_player[] =
3473 EL_SOKOBAN_FIELD_PLAYER,
3479 static int ep_can_pass_magic_wall[] =
3493 static int ep_can_pass_dc_magic_wall[] =
3509 static int ep_switchable[] =
3513 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3514 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3515 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3516 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3517 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3518 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3519 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3520 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3521 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3522 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3523 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3524 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3525 EL_SWITCHGATE_SWITCH_UP,
3526 EL_SWITCHGATE_SWITCH_DOWN,
3527 EL_DC_SWITCHGATE_SWITCH_UP,
3528 EL_DC_SWITCHGATE_SWITCH_DOWN,
3530 EL_LIGHT_SWITCH_ACTIVE,
3532 EL_DC_TIMEGATE_SWITCH,
3533 EL_BALLOON_SWITCH_LEFT,
3534 EL_BALLOON_SWITCH_RIGHT,
3535 EL_BALLOON_SWITCH_UP,
3536 EL_BALLOON_SWITCH_DOWN,
3537 EL_BALLOON_SWITCH_ANY,
3538 EL_BALLOON_SWITCH_NONE,
3541 EL_EMC_MAGIC_BALL_SWITCH,
3542 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3547 static int ep_bd_element[] =
3581 static int ep_sp_element[] =
3583 /* should always be valid */
3586 /* standard classic Supaplex elements */
3593 EL_SP_HARDWARE_GRAY,
3601 EL_SP_GRAVITY_PORT_RIGHT,
3602 EL_SP_GRAVITY_PORT_DOWN,
3603 EL_SP_GRAVITY_PORT_LEFT,
3604 EL_SP_GRAVITY_PORT_UP,
3609 EL_SP_PORT_VERTICAL,
3610 EL_SP_PORT_HORIZONTAL,
3616 EL_SP_HARDWARE_BASE_1,
3617 EL_SP_HARDWARE_GREEN,
3618 EL_SP_HARDWARE_BLUE,
3620 EL_SP_HARDWARE_YELLOW,
3621 EL_SP_HARDWARE_BASE_2,
3622 EL_SP_HARDWARE_BASE_3,
3623 EL_SP_HARDWARE_BASE_4,
3624 EL_SP_HARDWARE_BASE_5,
3625 EL_SP_HARDWARE_BASE_6,
3629 /* additional elements that appeared in newer Supaplex levels */
3632 /* additional gravity port elements (not switching, but setting gravity) */
3633 EL_SP_GRAVITY_ON_PORT_LEFT,
3634 EL_SP_GRAVITY_ON_PORT_RIGHT,
3635 EL_SP_GRAVITY_ON_PORT_UP,
3636 EL_SP_GRAVITY_ON_PORT_DOWN,
3637 EL_SP_GRAVITY_OFF_PORT_LEFT,
3638 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3639 EL_SP_GRAVITY_OFF_PORT_UP,
3640 EL_SP_GRAVITY_OFF_PORT_DOWN,
3642 /* more than one Murphy in a level results in an inactive clone */
3645 /* runtime Supaplex elements */
3646 EL_SP_DISK_RED_ACTIVE,
3647 EL_SP_TERMINAL_ACTIVE,
3648 EL_SP_BUGGY_BASE_ACTIVATING,
3649 EL_SP_BUGGY_BASE_ACTIVE,
3656 static int ep_sb_element[] =
3661 EL_SOKOBAN_FIELD_EMPTY,
3662 EL_SOKOBAN_FIELD_FULL,
3663 EL_SOKOBAN_FIELD_PLAYER,
3668 EL_INVISIBLE_STEELWALL,
3673 static int ep_gem[] =
3685 static int ep_food_dark_yamyam[] =
3713 static int ep_food_penguin[] =
3727 static int ep_food_pig[] =
3739 static int ep_historic_wall[] =
3750 EL_GATE_1_GRAY_ACTIVE,
3751 EL_GATE_2_GRAY_ACTIVE,
3752 EL_GATE_3_GRAY_ACTIVE,
3753 EL_GATE_4_GRAY_ACTIVE,
3762 EL_EM_GATE_1_GRAY_ACTIVE,
3763 EL_EM_GATE_2_GRAY_ACTIVE,
3764 EL_EM_GATE_3_GRAY_ACTIVE,
3765 EL_EM_GATE_4_GRAY_ACTIVE,
3772 EL_EXPANDABLE_WALL_HORIZONTAL,
3773 EL_EXPANDABLE_WALL_VERTICAL,
3774 EL_EXPANDABLE_WALL_ANY,
3775 EL_EXPANDABLE_WALL_GROWING,
3776 EL_BD_EXPANDABLE_WALL,
3783 EL_SP_HARDWARE_GRAY,
3784 EL_SP_HARDWARE_GREEN,
3785 EL_SP_HARDWARE_BLUE,
3787 EL_SP_HARDWARE_YELLOW,
3788 EL_SP_HARDWARE_BASE_1,
3789 EL_SP_HARDWARE_BASE_2,
3790 EL_SP_HARDWARE_BASE_3,
3791 EL_SP_HARDWARE_BASE_4,
3792 EL_SP_HARDWARE_BASE_5,
3793 EL_SP_HARDWARE_BASE_6,
3795 EL_SP_TERMINAL_ACTIVE,
3798 EL_INVISIBLE_STEELWALL,
3799 EL_INVISIBLE_STEELWALL_ACTIVE,
3801 EL_INVISIBLE_WALL_ACTIVE,
3802 EL_STEELWALL_SLIPPERY,
3819 static int ep_historic_solid[] =
3823 EL_EXPANDABLE_WALL_HORIZONTAL,
3824 EL_EXPANDABLE_WALL_VERTICAL,
3825 EL_EXPANDABLE_WALL_ANY,
3826 EL_BD_EXPANDABLE_WALL,
3839 EL_QUICKSAND_FILLING,
3840 EL_QUICKSAND_EMPTYING,
3842 EL_MAGIC_WALL_ACTIVE,
3843 EL_MAGIC_WALL_EMPTYING,
3844 EL_MAGIC_WALL_FILLING,
3848 EL_BD_MAGIC_WALL_ACTIVE,
3849 EL_BD_MAGIC_WALL_EMPTYING,
3850 EL_BD_MAGIC_WALL_FULL,
3851 EL_BD_MAGIC_WALL_FILLING,
3852 EL_BD_MAGIC_WALL_DEAD,
3861 EL_SP_TERMINAL_ACTIVE,
3865 EL_INVISIBLE_WALL_ACTIVE,
3866 EL_SWITCHGATE_SWITCH_UP,
3867 EL_SWITCHGATE_SWITCH_DOWN,
3868 EL_DC_SWITCHGATE_SWITCH_UP,
3869 EL_DC_SWITCHGATE_SWITCH_DOWN,
3871 EL_TIMEGATE_SWITCH_ACTIVE,
3872 EL_DC_TIMEGATE_SWITCH,
3873 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3885 /* the following elements are a direct copy of "indestructible" elements,
3886 except "EL_ACID", which is "indestructible", but not "solid"! */
3891 EL_ACID_POOL_TOPLEFT,
3892 EL_ACID_POOL_TOPRIGHT,
3893 EL_ACID_POOL_BOTTOMLEFT,
3894 EL_ACID_POOL_BOTTOM,
3895 EL_ACID_POOL_BOTTOMRIGHT,
3896 EL_SP_HARDWARE_GRAY,
3897 EL_SP_HARDWARE_GREEN,
3898 EL_SP_HARDWARE_BLUE,
3900 EL_SP_HARDWARE_YELLOW,
3901 EL_SP_HARDWARE_BASE_1,
3902 EL_SP_HARDWARE_BASE_2,
3903 EL_SP_HARDWARE_BASE_3,
3904 EL_SP_HARDWARE_BASE_4,
3905 EL_SP_HARDWARE_BASE_5,
3906 EL_SP_HARDWARE_BASE_6,
3907 EL_INVISIBLE_STEELWALL,
3908 EL_INVISIBLE_STEELWALL_ACTIVE,
3909 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3910 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3911 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3912 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3913 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3914 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3915 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3916 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3917 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3918 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3919 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3920 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3922 EL_LIGHT_SWITCH_ACTIVE,
3923 EL_SIGN_EXCLAMATION,
3924 EL_SIGN_RADIOACTIVITY,
3931 EL_SIGN_ENTRY_FORBIDDEN,
3932 EL_SIGN_EMERGENCY_EXIT,
3940 EL_STEEL_EXIT_CLOSED,
3942 EL_DC_STEELWALL_1_LEFT,
3943 EL_DC_STEELWALL_1_RIGHT,
3944 EL_DC_STEELWALL_1_TOP,
3945 EL_DC_STEELWALL_1_BOTTOM,
3946 EL_DC_STEELWALL_1_HORIZONTAL,
3947 EL_DC_STEELWALL_1_VERTICAL,
3948 EL_DC_STEELWALL_1_TOPLEFT,
3949 EL_DC_STEELWALL_1_TOPRIGHT,
3950 EL_DC_STEELWALL_1_BOTTOMLEFT,
3951 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3952 EL_DC_STEELWALL_1_TOPLEFT_2,
3953 EL_DC_STEELWALL_1_TOPRIGHT_2,
3954 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3955 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3956 EL_DC_STEELWALL_2_LEFT,
3957 EL_DC_STEELWALL_2_RIGHT,
3958 EL_DC_STEELWALL_2_TOP,
3959 EL_DC_STEELWALL_2_BOTTOM,
3960 EL_DC_STEELWALL_2_HORIZONTAL,
3961 EL_DC_STEELWALL_2_VERTICAL,
3962 EL_DC_STEELWALL_2_MIDDLE,
3963 EL_DC_STEELWALL_2_SINGLE,
3964 EL_STEELWALL_SLIPPERY,
3978 EL_GATE_1_GRAY_ACTIVE,
3979 EL_GATE_2_GRAY_ACTIVE,
3980 EL_GATE_3_GRAY_ACTIVE,
3981 EL_GATE_4_GRAY_ACTIVE,
3990 EL_EM_GATE_1_GRAY_ACTIVE,
3991 EL_EM_GATE_2_GRAY_ACTIVE,
3992 EL_EM_GATE_3_GRAY_ACTIVE,
3993 EL_EM_GATE_4_GRAY_ACTIVE,
3995 EL_SWITCHGATE_OPENING,
3996 EL_SWITCHGATE_CLOSED,
3997 EL_SWITCHGATE_CLOSING,
3999 EL_TIMEGATE_OPENING,
4001 EL_TIMEGATE_CLOSING,
4005 EL_TUBE_VERTICAL_LEFT,
4006 EL_TUBE_VERTICAL_RIGHT,
4007 EL_TUBE_HORIZONTAL_UP,
4008 EL_TUBE_HORIZONTAL_DOWN,
4017 static int ep_classic_enemy[] =
4034 static int ep_belt[] =
4036 EL_CONVEYOR_BELT_1_LEFT,
4037 EL_CONVEYOR_BELT_1_MIDDLE,
4038 EL_CONVEYOR_BELT_1_RIGHT,
4039 EL_CONVEYOR_BELT_2_LEFT,
4040 EL_CONVEYOR_BELT_2_MIDDLE,
4041 EL_CONVEYOR_BELT_2_RIGHT,
4042 EL_CONVEYOR_BELT_3_LEFT,
4043 EL_CONVEYOR_BELT_3_MIDDLE,
4044 EL_CONVEYOR_BELT_3_RIGHT,
4045 EL_CONVEYOR_BELT_4_LEFT,
4046 EL_CONVEYOR_BELT_4_MIDDLE,
4047 EL_CONVEYOR_BELT_4_RIGHT,
4052 static int ep_belt_active[] =
4054 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
4055 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
4056 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
4057 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
4058 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
4059 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
4060 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
4061 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
4062 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
4063 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
4064 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
4065 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
4070 static int ep_belt_switch[] =
4072 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4073 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4074 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4075 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4076 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4077 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4078 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4079 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4080 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4081 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4082 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4083 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4088 static int ep_tube[] =
4095 EL_TUBE_HORIZONTAL_UP,
4096 EL_TUBE_HORIZONTAL_DOWN,
4098 EL_TUBE_VERTICAL_LEFT,
4099 EL_TUBE_VERTICAL_RIGHT,
4105 static int ep_acid_pool[] =
4107 EL_ACID_POOL_TOPLEFT,
4108 EL_ACID_POOL_TOPRIGHT,
4109 EL_ACID_POOL_BOTTOMLEFT,
4110 EL_ACID_POOL_BOTTOM,
4111 EL_ACID_POOL_BOTTOMRIGHT,
4116 static int ep_keygate[] =
4126 EL_GATE_1_GRAY_ACTIVE,
4127 EL_GATE_2_GRAY_ACTIVE,
4128 EL_GATE_3_GRAY_ACTIVE,
4129 EL_GATE_4_GRAY_ACTIVE,
4138 EL_EM_GATE_1_GRAY_ACTIVE,
4139 EL_EM_GATE_2_GRAY_ACTIVE,
4140 EL_EM_GATE_3_GRAY_ACTIVE,
4141 EL_EM_GATE_4_GRAY_ACTIVE,
4150 EL_EMC_GATE_5_GRAY_ACTIVE,
4151 EL_EMC_GATE_6_GRAY_ACTIVE,
4152 EL_EMC_GATE_7_GRAY_ACTIVE,
4153 EL_EMC_GATE_8_GRAY_ACTIVE,
4155 EL_DC_GATE_WHITE_GRAY,
4156 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4161 static int ep_amoeboid[] =
4173 static int ep_amoebalive[] =
4184 static int ep_has_editor_content[] =
4190 EL_SOKOBAN_FIELD_PLAYER,
4207 static int ep_can_turn_each_move[] =
4209 /* !!! do something with this one !!! */
4213 static int ep_can_grow[] =
4227 static int ep_active_bomb[] =
4230 EL_EM_DYNAMITE_ACTIVE,
4231 EL_DYNABOMB_PLAYER_1_ACTIVE,
4232 EL_DYNABOMB_PLAYER_2_ACTIVE,
4233 EL_DYNABOMB_PLAYER_3_ACTIVE,
4234 EL_DYNABOMB_PLAYER_4_ACTIVE,
4235 EL_SP_DISK_RED_ACTIVE,
4240 static int ep_inactive[] =
4250 EL_QUICKSAND_FAST_EMPTY,
4273 EL_GATE_1_GRAY_ACTIVE,
4274 EL_GATE_2_GRAY_ACTIVE,
4275 EL_GATE_3_GRAY_ACTIVE,
4276 EL_GATE_4_GRAY_ACTIVE,
4285 EL_EM_GATE_1_GRAY_ACTIVE,
4286 EL_EM_GATE_2_GRAY_ACTIVE,
4287 EL_EM_GATE_3_GRAY_ACTIVE,
4288 EL_EM_GATE_4_GRAY_ACTIVE,
4297 EL_EMC_GATE_5_GRAY_ACTIVE,
4298 EL_EMC_GATE_6_GRAY_ACTIVE,
4299 EL_EMC_GATE_7_GRAY_ACTIVE,
4300 EL_EMC_GATE_8_GRAY_ACTIVE,
4302 EL_DC_GATE_WHITE_GRAY,
4303 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4304 EL_DC_GATE_FAKE_GRAY,
4307 EL_INVISIBLE_STEELWALL,
4315 EL_WALL_EMERALD_YELLOW,
4316 EL_DYNABOMB_INCREASE_NUMBER,
4317 EL_DYNABOMB_INCREASE_SIZE,
4318 EL_DYNABOMB_INCREASE_POWER,
4322 EL_SOKOBAN_FIELD_EMPTY,
4323 EL_SOKOBAN_FIELD_FULL,
4324 EL_WALL_EMERALD_RED,
4325 EL_WALL_EMERALD_PURPLE,
4326 EL_ACID_POOL_TOPLEFT,
4327 EL_ACID_POOL_TOPRIGHT,
4328 EL_ACID_POOL_BOTTOMLEFT,
4329 EL_ACID_POOL_BOTTOM,
4330 EL_ACID_POOL_BOTTOMRIGHT,
4334 EL_BD_MAGIC_WALL_DEAD,
4336 EL_DC_MAGIC_WALL_DEAD,
4337 EL_AMOEBA_TO_DIAMOND,
4345 EL_SP_GRAVITY_PORT_RIGHT,
4346 EL_SP_GRAVITY_PORT_DOWN,
4347 EL_SP_GRAVITY_PORT_LEFT,
4348 EL_SP_GRAVITY_PORT_UP,
4349 EL_SP_PORT_HORIZONTAL,
4350 EL_SP_PORT_VERTICAL,
4361 EL_SP_HARDWARE_GRAY,
4362 EL_SP_HARDWARE_GREEN,
4363 EL_SP_HARDWARE_BLUE,
4365 EL_SP_HARDWARE_YELLOW,
4366 EL_SP_HARDWARE_BASE_1,
4367 EL_SP_HARDWARE_BASE_2,
4368 EL_SP_HARDWARE_BASE_3,
4369 EL_SP_HARDWARE_BASE_4,
4370 EL_SP_HARDWARE_BASE_5,
4371 EL_SP_HARDWARE_BASE_6,
4372 EL_SP_GRAVITY_ON_PORT_LEFT,
4373 EL_SP_GRAVITY_ON_PORT_RIGHT,
4374 EL_SP_GRAVITY_ON_PORT_UP,
4375 EL_SP_GRAVITY_ON_PORT_DOWN,
4376 EL_SP_GRAVITY_OFF_PORT_LEFT,
4377 EL_SP_GRAVITY_OFF_PORT_RIGHT,
4378 EL_SP_GRAVITY_OFF_PORT_UP,
4379 EL_SP_GRAVITY_OFF_PORT_DOWN,
4380 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4381 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4382 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4383 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4384 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4385 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4386 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4387 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4388 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4389 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4390 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4391 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4392 EL_SIGN_EXCLAMATION,
4393 EL_SIGN_RADIOACTIVITY,
4400 EL_SIGN_ENTRY_FORBIDDEN,
4401 EL_SIGN_EMERGENCY_EXIT,
4409 EL_DC_STEELWALL_1_LEFT,
4410 EL_DC_STEELWALL_1_RIGHT,
4411 EL_DC_STEELWALL_1_TOP,
4412 EL_DC_STEELWALL_1_BOTTOM,
4413 EL_DC_STEELWALL_1_HORIZONTAL,
4414 EL_DC_STEELWALL_1_VERTICAL,
4415 EL_DC_STEELWALL_1_TOPLEFT,
4416 EL_DC_STEELWALL_1_TOPRIGHT,
4417 EL_DC_STEELWALL_1_BOTTOMLEFT,
4418 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4419 EL_DC_STEELWALL_1_TOPLEFT_2,
4420 EL_DC_STEELWALL_1_TOPRIGHT_2,
4421 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4422 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4423 EL_DC_STEELWALL_2_LEFT,
4424 EL_DC_STEELWALL_2_RIGHT,
4425 EL_DC_STEELWALL_2_TOP,
4426 EL_DC_STEELWALL_2_BOTTOM,
4427 EL_DC_STEELWALL_2_HORIZONTAL,
4428 EL_DC_STEELWALL_2_VERTICAL,
4429 EL_DC_STEELWALL_2_MIDDLE,
4430 EL_DC_STEELWALL_2_SINGLE,
4431 EL_STEELWALL_SLIPPERY,
4436 EL_EMC_WALL_SLIPPERY_1,
4437 EL_EMC_WALL_SLIPPERY_2,
4438 EL_EMC_WALL_SLIPPERY_3,
4439 EL_EMC_WALL_SLIPPERY_4,
4460 static int ep_em_slippery_wall[] =
4465 static int ep_gfx_crumbled[] =
4476 static int ep_editor_cascade_active[] =
4478 EL_INTERNAL_CASCADE_BD_ACTIVE,
4479 EL_INTERNAL_CASCADE_EM_ACTIVE,
4480 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4481 EL_INTERNAL_CASCADE_RND_ACTIVE,
4482 EL_INTERNAL_CASCADE_SB_ACTIVE,
4483 EL_INTERNAL_CASCADE_SP_ACTIVE,
4484 EL_INTERNAL_CASCADE_DC_ACTIVE,
4485 EL_INTERNAL_CASCADE_DX_ACTIVE,
4486 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4487 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4488 EL_INTERNAL_CASCADE_CE_ACTIVE,
4489 EL_INTERNAL_CASCADE_GE_ACTIVE,
4490 EL_INTERNAL_CASCADE_REF_ACTIVE,
4491 EL_INTERNAL_CASCADE_USER_ACTIVE,
4492 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4497 static int ep_editor_cascade_inactive[] =
4499 EL_INTERNAL_CASCADE_BD,
4500 EL_INTERNAL_CASCADE_EM,
4501 EL_INTERNAL_CASCADE_EMC,
4502 EL_INTERNAL_CASCADE_RND,
4503 EL_INTERNAL_CASCADE_SB,
4504 EL_INTERNAL_CASCADE_SP,
4505 EL_INTERNAL_CASCADE_DC,
4506 EL_INTERNAL_CASCADE_DX,
4507 EL_INTERNAL_CASCADE_CHARS,
4508 EL_INTERNAL_CASCADE_STEEL_CHARS,
4509 EL_INTERNAL_CASCADE_CE,
4510 EL_INTERNAL_CASCADE_GE,
4511 EL_INTERNAL_CASCADE_REF,
4512 EL_INTERNAL_CASCADE_USER,
4513 EL_INTERNAL_CASCADE_DYNAMIC,
4518 static int ep_obsolete[] =
4522 EL_EM_KEY_1_FILE_OBSOLETE,
4523 EL_EM_KEY_2_FILE_OBSOLETE,
4524 EL_EM_KEY_3_FILE_OBSOLETE,
4525 EL_EM_KEY_4_FILE_OBSOLETE,
4526 EL_ENVELOPE_OBSOLETE,
4535 } element_properties[] =
4537 { ep_diggable, EP_DIGGABLE },
4538 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4539 { ep_dont_run_into, EP_DONT_RUN_INTO },
4540 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4541 { ep_dont_touch, EP_DONT_TOUCH },
4542 { ep_indestructible, EP_INDESTRUCTIBLE },
4543 { ep_slippery, EP_SLIPPERY },
4544 { ep_can_change, EP_CAN_CHANGE },
4545 { ep_can_move, EP_CAN_MOVE },
4546 { ep_can_fall, EP_CAN_FALL },
4547 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4548 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4549 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4550 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4551 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4552 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4553 { ep_walkable_over, EP_WALKABLE_OVER },
4554 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4555 { ep_walkable_under, EP_WALKABLE_UNDER },
4556 { ep_passable_over, EP_PASSABLE_OVER },
4557 { ep_passable_inside, EP_PASSABLE_INSIDE },
4558 { ep_passable_under, EP_PASSABLE_UNDER },
4559 { ep_droppable, EP_DROPPABLE },
4560 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4561 { ep_pushable, EP_PUSHABLE },
4562 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4563 { ep_protected, EP_PROTECTED },
4564 { ep_throwable, EP_THROWABLE },
4565 { ep_can_explode, EP_CAN_EXPLODE },
4566 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4568 { ep_player, EP_PLAYER },
4569 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4570 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4571 { ep_switchable, EP_SWITCHABLE },
4572 { ep_bd_element, EP_BD_ELEMENT },
4573 { ep_sp_element, EP_SP_ELEMENT },
4574 { ep_sb_element, EP_SB_ELEMENT },
4576 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4577 { ep_food_penguin, EP_FOOD_PENGUIN },
4578 { ep_food_pig, EP_FOOD_PIG },
4579 { ep_historic_wall, EP_HISTORIC_WALL },
4580 { ep_historic_solid, EP_HISTORIC_SOLID },
4581 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4582 { ep_belt, EP_BELT },
4583 { ep_belt_active, EP_BELT_ACTIVE },
4584 { ep_belt_switch, EP_BELT_SWITCH },
4585 { ep_tube, EP_TUBE },
4586 { ep_acid_pool, EP_ACID_POOL },
4587 { ep_keygate, EP_KEYGATE },
4588 { ep_amoeboid, EP_AMOEBOID },
4589 { ep_amoebalive, EP_AMOEBALIVE },
4590 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4591 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4592 { ep_can_grow, EP_CAN_GROW },
4593 { ep_active_bomb, EP_ACTIVE_BOMB },
4594 { ep_inactive, EP_INACTIVE },
4596 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4598 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4600 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4601 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4603 { ep_obsolete, EP_OBSOLETE },
4610 /* always start with reliable default values (element has no properties) */
4611 /* (but never initialize clipboard elements after the very first time) */
4612 /* (to be able to use clipboard elements between several levels) */
4613 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4614 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4615 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4616 SET_PROPERTY(i, j, FALSE);
4618 /* set all base element properties from above array definitions */
4619 for (i = 0; element_properties[i].elements != NULL; i++)
4620 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4621 SET_PROPERTY((element_properties[i].elements)[j],
4622 element_properties[i].property, TRUE);
4624 /* copy properties to some elements that are only stored in level file */
4625 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4626 for (j = 0; copy_properties[j][0] != -1; j++)
4627 if (HAS_PROPERTY(copy_properties[j][0], i))
4628 for (k = 1; k <= 4; k++)
4629 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4631 /* set static element properties that are not listed in array definitions */
4632 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4633 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4635 clipboard_elements_initialized = TRUE;
4638 void InitElementPropertiesEngine(int engine_version)
4640 static int no_wall_properties[] =
4643 EP_COLLECTIBLE_ONLY,
4645 EP_DONT_COLLIDE_WITH,
4648 EP_CAN_SMASH_PLAYER,
4649 EP_CAN_SMASH_ENEMIES,
4650 EP_CAN_SMASH_EVERYTHING,
4655 EP_FOOD_DARK_YAMYAM,
4671 /* important: after initialization in InitElementPropertiesStatic(), the
4672 elements are not again initialized to a default value; therefore all
4673 changes have to make sure that they leave the element with a defined
4674 property (which means that conditional property changes must be set to
4675 a reliable default value before) */
4677 /* resolve group elements */
4678 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4679 ResolveGroupElement(EL_GROUP_START + i);
4681 /* set all special, combined or engine dependent element properties */
4682 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4684 /* do not change (already initialized) clipboard elements here */
4685 if (IS_CLIPBOARD_ELEMENT(i))
4688 /* ---------- INACTIVE ------------------------------------------------- */
4689 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4690 i <= EL_CHAR_END) ||
4691 (i >= EL_STEEL_CHAR_START &&
4692 i <= EL_STEEL_CHAR_END)));
4694 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4695 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4696 IS_WALKABLE_INSIDE(i) ||
4697 IS_WALKABLE_UNDER(i)));
4699 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4700 IS_PASSABLE_INSIDE(i) ||
4701 IS_PASSABLE_UNDER(i)));
4703 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4704 IS_PASSABLE_OVER(i)));
4706 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4707 IS_PASSABLE_INSIDE(i)));
4709 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4710 IS_PASSABLE_UNDER(i)));
4712 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4715 /* ---------- COLLECTIBLE ---------------------------------------------- */
4716 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4720 /* ---------- SNAPPABLE ------------------------------------------------ */
4721 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4722 IS_COLLECTIBLE(i) ||
4726 /* ---------- WALL ----------------------------------------------------- */
4727 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4729 for (j = 0; no_wall_properties[j] != -1; j++)
4730 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4731 i >= EL_FIRST_RUNTIME_UNREAL)
4732 SET_PROPERTY(i, EP_WALL, FALSE);
4734 if (IS_HISTORIC_WALL(i))
4735 SET_PROPERTY(i, EP_WALL, TRUE);
4737 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4738 if (engine_version < VERSION_IDENT(2,2,0,0))
4739 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4741 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4743 !IS_COLLECTIBLE(i)));
4745 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4746 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4747 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4749 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4750 IS_INDESTRUCTIBLE(i)));
4752 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4754 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4755 else if (engine_version < VERSION_IDENT(2,2,0,0))
4756 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4758 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4762 if (IS_CUSTOM_ELEMENT(i))
4764 /* these are additional properties which are initially false when set */
4766 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4768 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4769 if (DONT_COLLIDE_WITH(i))
4770 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4772 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4773 if (CAN_SMASH_EVERYTHING(i))
4774 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4775 if (CAN_SMASH_ENEMIES(i))
4776 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4779 /* ---------- CAN_SMASH ------------------------------------------------ */
4780 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4781 CAN_SMASH_ENEMIES(i) ||
4782 CAN_SMASH_EVERYTHING(i)));
4784 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4785 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4786 EXPLODES_BY_FIRE(i)));
4788 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4789 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4790 EXPLODES_SMASHED(i)));
4792 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4793 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4794 EXPLODES_IMPACT(i)));
4796 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4797 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4799 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4800 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4801 i == EL_BLACK_ORB));
4803 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4804 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4806 IS_CUSTOM_ELEMENT(i)));
4808 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4809 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4810 i == EL_SP_ELECTRON));
4812 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4813 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4814 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4815 getMoveIntoAcidProperty(&level, i));
4817 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4818 if (MAYBE_DONT_COLLIDE_WITH(i))
4819 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4820 getDontCollideWithProperty(&level, i));
4822 /* ---------- SP_PORT -------------------------------------------------- */
4823 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4824 IS_PASSABLE_INSIDE(i)));
4826 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4827 for (j = 0; j < level.num_android_clone_elements; j++)
4828 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4830 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4832 /* ---------- CAN_CHANGE ----------------------------------------------- */
4833 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4834 for (j = 0; j < element_info[i].num_change_pages; j++)
4835 if (element_info[i].change_page[j].can_change)
4836 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4838 /* ---------- HAS_ACTION ----------------------------------------------- */
4839 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4840 for (j = 0; j < element_info[i].num_change_pages; j++)
4841 if (element_info[i].change_page[j].has_action)
4842 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4844 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4845 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4848 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4850 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4851 element_info[i].crumbled[ACTION_DEFAULT] !=
4852 element_info[i].graphic[ACTION_DEFAULT]);
4854 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
4855 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4856 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
4859 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4860 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4861 IS_EDITOR_CASCADE_INACTIVE(i)));
4864 /* dynamically adjust element properties according to game engine version */
4866 static int ep_em_slippery_wall[] =
4871 EL_EXPANDABLE_WALL_HORIZONTAL,
4872 EL_EXPANDABLE_WALL_VERTICAL,
4873 EL_EXPANDABLE_WALL_ANY,
4874 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4875 EL_EXPANDABLE_STEELWALL_VERTICAL,
4876 EL_EXPANDABLE_STEELWALL_ANY,
4877 EL_EXPANDABLE_STEELWALL_GROWING,
4881 static int ep_em_explodes_by_fire[] =
4884 EL_EM_DYNAMITE_ACTIVE,
4889 /* special EM style gems behaviour */
4890 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4891 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4892 level.em_slippery_gems);
4894 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4895 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4896 (level.em_slippery_gems &&
4897 engine_version > VERSION_IDENT(2,0,1,0)));
4899 /* special EM style explosion behaviour regarding chain reactions */
4900 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4901 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4902 level.em_explodes_by_fire);
4905 /* this is needed because some graphics depend on element properties */
4906 if (game_status == GAME_MODE_PLAYING)
4907 InitElementGraphicInfo();
4910 void InitElementPropertiesAfterLoading(int engine_version)
4914 /* set some other uninitialized values of custom elements in older levels */
4915 if (engine_version < VERSION_IDENT(3,1,0,0))
4917 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4919 int element = EL_CUSTOM_START + i;
4921 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4923 element_info[element].explosion_delay = 17;
4924 element_info[element].ignition_delay = 8;
4929 void InitElementPropertiesGfxElement()
4933 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4935 struct ElementInfo *ei = &element_info[i];
4937 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4941 static void InitGlobal()
4946 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4948 /* check if element_name_info entry defined for each element in "main.h" */
4949 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4950 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4952 element_info[i].token_name = element_name_info[i].token_name;
4953 element_info[i].class_name = element_name_info[i].class_name;
4954 element_info[i].editor_description= element_name_info[i].editor_description;
4957 printf("%04d: %s\n", i, element_name_info[i].token_name);
4961 /* create hash from image config list */
4962 image_config_hash = newSetupFileHash();
4963 for (i = 0; image_config[i].token != NULL; i++)
4964 setHashEntry(image_config_hash,
4965 image_config[i].token,
4966 image_config[i].value);
4968 /* create hash from element token list */
4969 element_token_hash = newSetupFileHash();
4970 for (i = 0; element_name_info[i].token_name != NULL; i++)
4971 setHashEntry(element_token_hash,
4972 element_name_info[i].token_name,
4975 /* create hash from graphic token list */
4976 graphic_token_hash = newSetupFileHash();
4977 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4978 if (strSuffix(image_config[i].value, ".pcx") ||
4979 strSuffix(image_config[i].value, ".wav") ||
4980 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4981 setHashEntry(graphic_token_hash,
4982 image_config[i].token,
4983 int2str(graphic++, 0));
4985 /* create hash from font token list */
4986 font_token_hash = newSetupFileHash();
4987 for (i = 0; font_info[i].token_name != NULL; i++)
4988 setHashEntry(font_token_hash,
4989 font_info[i].token_name,
4992 /* always start with reliable default values (all elements) */
4993 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4994 ActiveElement[i] = i;
4996 /* now add all entries that have an active state (active elements) */
4997 for (i = 0; element_with_active_state[i].element != -1; i++)
4999 int element = element_with_active_state[i].element;
5000 int element_active = element_with_active_state[i].element_active;
5002 ActiveElement[element] = element_active;
5005 /* always start with reliable default values (all buttons) */
5006 for (i = 0; i < NUM_IMAGE_FILES; i++)
5007 ActiveButton[i] = i;
5009 /* now add all entries that have an active state (active buttons) */
5010 for (i = 0; button_with_active_state[i].button != -1; i++)
5012 int button = button_with_active_state[i].button;
5013 int button_active = button_with_active_state[i].button_active;
5015 ActiveButton[button] = button_active;
5018 /* always start with reliable default values (all fonts) */
5019 for (i = 0; i < NUM_FONTS; i++)
5022 /* now add all entries that have an active state (active fonts) */
5023 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
5025 int font = font_with_active_state[i].font_nr;
5026 int font_active = font_with_active_state[i].font_nr_active;
5028 ActiveFont[font] = font_active;
5031 global.autoplay_leveldir = NULL;
5032 global.convert_leveldir = NULL;
5033 global.create_images_dir = NULL;
5035 global.frames_per_second = 0;
5036 global.fps_slowdown = FALSE;
5037 global.fps_slowdown_factor = 1;
5039 global.border_status = GAME_MODE_MAIN;
5041 global.fading_status = GAME_MODE_MAIN;
5042 global.fading_type = TYPE_ENTER_MENU;
5046 void Execute_Command(char *command)
5050 if (strEqual(command, "print graphicsinfo.conf"))
5052 printf("# You can configure additional/alternative image files here.\n");
5053 printf("# (The entries below are default and therefore commented out.)\n");
5055 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
5057 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5060 for (i = 0; image_config[i].token != NULL; i++)
5061 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
5062 image_config[i].value));
5066 else if (strEqual(command, "print soundsinfo.conf"))
5068 printf("# You can configure additional/alternative sound files here.\n");
5069 printf("# (The entries below are default and therefore commented out.)\n");
5071 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
5073 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5076 for (i = 0; sound_config[i].token != NULL; i++)
5077 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
5078 sound_config[i].value));
5082 else if (strEqual(command, "print musicinfo.conf"))
5084 printf("# You can configure additional/alternative music files here.\n");
5085 printf("# (The entries below are default and therefore commented out.)\n");
5087 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
5089 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5092 for (i = 0; music_config[i].token != NULL; i++)
5093 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
5094 music_config[i].value));
5098 else if (strEqual(command, "print editorsetup.conf"))
5100 printf("# You can configure your personal editor element list here.\n");
5101 printf("# (The entries below are default and therefore commented out.)\n");
5104 /* this is needed to be able to check element list for cascade elements */
5105 InitElementPropertiesStatic();
5106 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5108 PrintEditorElementList();
5112 else if (strEqual(command, "print helpanim.conf"))
5114 printf("# You can configure different element help animations here.\n");
5115 printf("# (The entries below are default and therefore commented out.)\n");
5118 for (i = 0; helpanim_config[i].token != NULL; i++)
5120 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
5121 helpanim_config[i].value));
5123 if (strEqual(helpanim_config[i].token, "end"))
5129 else if (strEqual(command, "print helptext.conf"))
5131 printf("# You can configure different element help text here.\n");
5132 printf("# (The entries below are default and therefore commented out.)\n");
5135 for (i = 0; helptext_config[i].token != NULL; i++)
5136 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
5137 helptext_config[i].value));
5141 else if (strPrefix(command, "dump level "))
5143 char *filename = &command[11];
5145 if (!fileExists(filename))
5146 Error(ERR_EXIT, "cannot open file '%s'", filename);
5148 LoadLevelFromFilename(&level, filename);
5153 else if (strPrefix(command, "dump tape "))
5155 char *filename = &command[10];
5157 if (!fileExists(filename))
5158 Error(ERR_EXIT, "cannot open file '%s'", filename);
5160 LoadTapeFromFilename(filename);
5165 else if (strPrefix(command, "autoplay "))
5167 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
5169 while (*str_ptr != '\0') /* continue parsing string */
5171 /* cut leading whitespace from string, replace it by string terminator */
5172 while (*str_ptr == ' ' || *str_ptr == '\t')
5175 if (*str_ptr == '\0') /* end of string reached */
5178 if (global.autoplay_leveldir == NULL) /* read level set string */
5180 global.autoplay_leveldir = str_ptr;
5181 global.autoplay_all = TRUE; /* default: play all tapes */
5183 for (i = 0; i < MAX_TAPES_PER_SET; i++)
5184 global.autoplay_level[i] = FALSE;
5186 else /* read level number string */
5188 int level_nr = atoi(str_ptr); /* get level_nr value */
5190 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5191 global.autoplay_level[level_nr] = TRUE;
5193 global.autoplay_all = FALSE;
5196 /* advance string pointer to the next whitespace (or end of string) */
5197 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5201 else if (strPrefix(command, "convert "))
5203 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
5204 char *str_ptr = strchr(str_copy, ' ');
5206 global.convert_leveldir = str_copy;
5207 global.convert_level_nr = -1;
5209 if (str_ptr != NULL) /* level number follows */
5211 *str_ptr++ = '\0'; /* terminate leveldir string */
5212 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
5215 else if (strPrefix(command, "create images "))
5217 #if defined(TARGET_SDL)
5218 global.create_images_dir = getStringCopy(&command[14]);
5220 if (access(global.create_images_dir, W_OK) != 0)
5221 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
5222 global.create_images_dir);
5224 Error(ERR_EXIT, "command only available for SDL target");
5229 #if defined(TARGET_SDL)
5230 else if (strEqual(command, "SDL_ListModes"))
5235 SDL_Init(SDL_INIT_VIDEO);
5237 /* get available fullscreen/hardware modes */
5238 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
5240 /* check if there are any modes available */
5243 printf("No modes available!\n");
5248 /* check if our resolution is restricted */
5249 if (modes == (SDL_Rect **)-1)
5251 printf("All resolutions available.\n");
5255 printf("Available Modes:\n");
5257 for(i = 0; modes[i]; i++)
5258 printf(" %d x %d\n", modes[i]->w, modes[i]->h);
5268 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
5272 static void InitSetup()
5274 LoadSetup(); /* global setup info */
5276 /* set some options from setup file */
5278 if (setup.options.verbose)
5279 options.verbose = TRUE;
5282 static void InitGameInfo()
5284 game.restart_level = FALSE;
5287 static void InitPlayerInfo()
5291 /* choose default local player */
5292 local_player = &stored_player[0];
5294 for (i = 0; i < MAX_PLAYERS; i++)
5295 stored_player[i].connected = FALSE;
5297 local_player->connected = TRUE;
5300 static void InitArtworkInfo()
5305 static char *get_string_in_brackets(char *string)
5307 char *string_in_brackets = checked_malloc(strlen(string) + 3);
5309 sprintf(string_in_brackets, "[%s]", string);
5311 return string_in_brackets;
5314 static char *get_level_id_suffix(int id_nr)
5316 char *id_suffix = checked_malloc(1 + 3 + 1);
5318 if (id_nr < 0 || id_nr > 999)
5321 sprintf(id_suffix, ".%03d", id_nr);
5327 static char *get_element_class_token(int element)
5329 char *element_class_name = element_info[element].class_name;
5330 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
5332 sprintf(element_class_token, "[%s]", element_class_name);
5334 return element_class_token;
5337 static char *get_action_class_token(int action)
5339 char *action_class_name = &element_action_info[action].suffix[1];
5340 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
5342 sprintf(action_class_token, "[%s]", action_class_name);
5344 return action_class_token;
5348 static void InitArtworkConfig()
5350 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
5351 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
5352 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
5353 static char *action_id_suffix[NUM_ACTIONS + 1];
5354 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5355 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5356 static char *level_id_suffix[MAX_LEVELS + 1];
5357 static char *dummy[1] = { NULL };
5358 static char *ignore_generic_tokens[] =
5364 static char **ignore_image_tokens;
5365 static char **ignore_sound_tokens;
5366 static char **ignore_music_tokens;
5367 int num_ignore_generic_tokens;
5368 int num_ignore_image_tokens;
5369 int num_ignore_sound_tokens;
5370 int num_ignore_music_tokens;
5373 /* dynamically determine list of generic tokens to be ignored */
5374 num_ignore_generic_tokens = 0;
5375 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5376 num_ignore_generic_tokens++;
5378 /* dynamically determine list of image tokens to be ignored */
5379 num_ignore_image_tokens = num_ignore_generic_tokens;
5380 for (i = 0; image_config_vars[i].token != NULL; i++)
5381 num_ignore_image_tokens++;
5382 ignore_image_tokens =
5383 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5384 for (i = 0; i < num_ignore_generic_tokens; i++)
5385 ignore_image_tokens[i] = ignore_generic_tokens[i];
5386 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5387 ignore_image_tokens[num_ignore_generic_tokens + i] =
5388 image_config_vars[i].token;
5389 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5391 /* dynamically determine list of sound tokens to be ignored */
5392 num_ignore_sound_tokens = num_ignore_generic_tokens;
5393 ignore_sound_tokens =
5394 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5395 for (i = 0; i < num_ignore_generic_tokens; i++)
5396 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5397 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5399 /* dynamically determine list of music tokens to be ignored */
5400 num_ignore_music_tokens = num_ignore_generic_tokens;
5401 ignore_music_tokens =
5402 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5403 for (i = 0; i < num_ignore_generic_tokens; i++)
5404 ignore_music_tokens[i] = ignore_generic_tokens[i];
5405 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5407 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5408 image_id_prefix[i] = element_info[i].token_name;
5409 for (i = 0; i < NUM_FONTS; i++)
5410 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5411 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
5413 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5414 sound_id_prefix[i] = element_info[i].token_name;
5415 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5416 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5417 get_string_in_brackets(element_info[i].class_name);
5418 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
5420 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5421 music_id_prefix[i] = music_prefix_info[i].prefix;
5422 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
5424 for (i = 0; i < NUM_ACTIONS; i++)
5425 action_id_suffix[i] = element_action_info[i].suffix;
5426 action_id_suffix[NUM_ACTIONS] = NULL;
5428 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5429 direction_id_suffix[i] = element_direction_info[i].suffix;
5430 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5432 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5433 special_id_suffix[i] = special_suffix_info[i].suffix;
5434 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5436 for (i = 0; i < MAX_LEVELS; i++)
5437 level_id_suffix[i] = get_level_id_suffix(i);
5438 level_id_suffix[MAX_LEVELS] = NULL;
5440 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5441 image_id_prefix, action_id_suffix, direction_id_suffix,
5442 special_id_suffix, ignore_image_tokens);
5443 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5444 sound_id_prefix, action_id_suffix, dummy,
5445 special_id_suffix, ignore_sound_tokens);
5446 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5447 music_id_prefix, special_id_suffix, level_id_suffix,
5448 dummy, ignore_music_tokens);
5451 static void InitMixer()
5458 void InitGfxBuffers()
5460 ReCreateBitmap(&bitmap_db_store, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5461 ReCreateBitmap(&bitmap_db_cross, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5462 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE, DEFAULT_DEPTH);
5463 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE, DEFAULT_DEPTH);
5464 ReCreateBitmap(&bitmap_db_door, 3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
5465 ReCreateBitmap(&bitmap_db_toons, FULL_SXSIZE, FULL_SYSIZE, DEFAULT_DEPTH);
5467 /* initialize screen properties */
5468 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5469 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5471 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5472 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5473 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5474 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5475 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5477 InitGfxBuffers_SP();
5482 struct GraphicInfo *graphic_info_last = graphic_info;
5483 char *filename_font_initial = NULL;
5484 char *filename_anim_initial = NULL;
5485 Bitmap *bitmap_font_initial = NULL;
5489 /* determine settings for initial font (for displaying startup messages) */
5490 for (i = 0; image_config[i].token != NULL; i++)
5492 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5494 char font_token[128];
5497 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5498 len_font_token = strlen(font_token);
5500 if (strEqual(image_config[i].token, font_token))
5501 filename_font_initial = image_config[i].value;
5502 else if (strlen(image_config[i].token) > len_font_token &&
5503 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5505 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5506 font_initial[j].src_x = atoi(image_config[i].value);
5507 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5508 font_initial[j].src_y = atoi(image_config[i].value);
5509 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5510 font_initial[j].width = atoi(image_config[i].value);
5511 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5512 font_initial[j].height = atoi(image_config[i].value);
5517 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5519 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5520 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5523 if (filename_font_initial == NULL) /* should not happen */
5524 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5529 /* create additional image buffers for double-buffering and cross-fading */
5530 bitmap_db_store = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5531 bitmap_db_cross = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5532 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
5533 bitmap_db_panel = CreateBitmap(DXSIZE, DYSIZE, DEFAULT_DEPTH);
5534 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
5535 bitmap_db_toons = CreateBitmap(FULL_SXSIZE, FULL_SYSIZE, DEFAULT_DEPTH);
5537 /* initialize screen properties */
5538 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5539 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5541 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5542 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5543 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5544 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5547 InitGfxCustomArtworkInfo();
5549 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5551 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5552 font_initial[j].bitmap = bitmap_font_initial;
5554 InitFontGraphicInfo();
5556 font_height = getFontHeight(FC_RED);
5559 DrawInitText(getWindowTitleString(), 20, FC_YELLOW);
5561 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
5563 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
5564 DrawInitText(PROGRAM_WEBSITE_STRING, WIN_YSIZE - 20 - font_height, FC_RED);
5566 DrawInitText("Loading graphics", 120, FC_GREEN);
5570 /* initialize busy animation with default values */
5571 int parameter[NUM_GFX_ARGS];
5572 for (i = 0; i < NUM_GFX_ARGS; i++)
5573 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5574 image_config_suffix[i].token,
5575 image_config_suffix[i].type);
5577 for (i = 0; i < NUM_GFX_ARGS; i++)
5578 printf("::: '%s' => %d\n", image_config_suffix[i].token, parameter[i]);
5582 /* determine settings for busy animation (when displaying startup messages) */
5583 for (i = 0; image_config[i].token != NULL; i++)
5585 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5586 int len_anim_token = strlen(anim_token);
5588 if (strEqual(image_config[i].token, anim_token))
5589 filename_anim_initial = image_config[i].value;
5590 else if (strlen(image_config[i].token) > len_anim_token &&
5591 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5594 for (j = 0; image_config_suffix[j].token != NULL; j++)
5596 if (strEqual(&image_config[i].token[len_anim_token],
5597 image_config_suffix[j].token))
5599 get_graphic_parameter_value(image_config[i].value,
5600 image_config_suffix[j].token,
5601 image_config_suffix[j].type);
5604 if (strEqual(&image_config[i].token[len_anim_token], ".x"))
5605 anim_initial.src_x = atoi(image_config[i].value);
5606 else if (strEqual(&image_config[i].token[len_anim_token], ".y"))
5607 anim_initial.src_y = atoi(image_config[i].value);
5608 else if (strEqual(&image_config[i].token[len_anim_token], ".width"))
5609 anim_initial.width = atoi(image_config[i].value);
5610 else if (strEqual(&image_config[i].token[len_anim_token], ".height"))
5611 anim_initial.height = atoi(image_config[i].value);
5612 else if (strEqual(&image_config[i].token[len_anim_token], ".frames"))
5613 anim_initial.anim_frames = atoi(image_config[i].value);
5614 else if (strEqual(&image_config[i].token[len_anim_token],
5615 ".frames_per_line"))
5616 anim_initial.anim_frames_per_line = atoi(image_config[i].value);
5617 else if (strEqual(&image_config[i].token[len_anim_token], ".delay"))
5618 anim_initial.anim_delay = atoi(image_config[i].value);
5623 #if defined(CREATE_SPECIAL_EDITION_RND_JUE)
5624 filename_anim_initial = "loading.pcx";
5626 parameter[GFX_ARG_X] = 0;
5627 parameter[GFX_ARG_Y] = 0;
5628 parameter[GFX_ARG_WIDTH] = 128;
5629 parameter[GFX_ARG_HEIGHT] = 40;
5630 parameter[GFX_ARG_FRAMES] = 32;
5631 parameter[GFX_ARG_DELAY] = 4;
5632 parameter[GFX_ARG_FRAMES_PER_LINE] = ARG_UNDEFINED_VALUE;
5635 if (filename_anim_initial == NULL) /* should not happen */
5636 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5638 anim_initial.bitmap = LoadCustomImage(filename_anim_initial);
5640 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
5642 set_graphic_parameters_ext(0, parameter, anim_initial.bitmap);
5645 printf("::: INIT_GFX: anim_frames_per_line == %d [%d / %d] [%d, %d]\n",
5646 graphic_info[0].anim_frames_per_line,
5647 get_scaled_graphic_width(0),
5648 graphic_info[0].width,
5649 getOriginalImageWidthFromImageID(0),
5650 graphic_info[0].scale_up_factor);
5653 graphic_info = graphic_info_last;
5655 init.busy.width = anim_initial.width;
5656 init.busy.height = anim_initial.height;
5658 InitMenuDesignSettings_Static();
5659 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5661 /* use copy of busy animation to prevent change while reloading artwork */
5666 void RedrawBackground()
5668 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
5669 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
5671 redraw_mask = REDRAW_ALL;
5674 void InitGfxBackground()
5678 fieldbuffer = bitmap_db_field;
5679 SetDrawtoField(DRAW_BACKBUFFER);
5682 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5686 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
5687 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
5690 for (x = 0; x < MAX_BUF_XSIZE; x++)
5691 for (y = 0; y < MAX_BUF_YSIZE; y++)
5694 redraw_mask = REDRAW_ALL;
5697 static void InitLevelInfo()
5699 LoadLevelInfo(); /* global level info */
5700 LoadLevelSetup_LastSeries(); /* last played series info */
5701 LoadLevelSetup_SeriesInfo(); /* last played level info */
5704 static void InitLevelArtworkInfo()
5706 LoadLevelArtworkInfo();
5709 static void InitImages()
5711 print_timestamp_init("InitImages");
5714 printf("::: leveldir_current->identifier == '%s'\n",
5715 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5716 printf("::: leveldir_current->graphics_path == '%s'\n",
5717 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5718 printf("::: leveldir_current->graphics_set == '%s'\n",
5719 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5720 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5721 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5724 setLevelArtworkDir(artwork.gfx_first);
5727 printf("::: leveldir_current->identifier == '%s'\n",
5728 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5729 printf("::: leveldir_current->graphics_path == '%s'\n",
5730 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5731 printf("::: leveldir_current->graphics_set == '%s'\n",
5732 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5733 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5734 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5738 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5739 leveldir_current->identifier,
5740 artwork.gfx_current_identifier,
5741 artwork.gfx_current->identifier,
5742 leveldir_current->graphics_set,
5743 leveldir_current->graphics_path);
5746 UPDATE_BUSY_STATE();
5748 ReloadCustomImages();
5749 print_timestamp_time("ReloadCustomImages");
5751 UPDATE_BUSY_STATE();
5753 LoadCustomElementDescriptions();
5754 print_timestamp_time("LoadCustomElementDescriptions");
5756 UPDATE_BUSY_STATE();
5758 LoadMenuDesignSettings();
5759 print_timestamp_time("LoadMenuDesignSettings");
5761 UPDATE_BUSY_STATE();
5763 ReinitializeGraphics();
5764 print_timestamp_time("ReinitializeGraphics");
5766 UPDATE_BUSY_STATE();
5768 print_timestamp_done("InitImages");
5771 static void InitSound(char *identifier)
5773 print_timestamp_init("InitSound");
5775 if (identifier == NULL)
5776 identifier = artwork.snd_current->identifier;
5778 /* set artwork path to send it to the sound server process */
5779 setLevelArtworkDir(artwork.snd_first);
5781 InitReloadCustomSounds(identifier);
5782 print_timestamp_time("InitReloadCustomSounds");
5784 ReinitializeSounds();
5785 print_timestamp_time("ReinitializeSounds");
5787 print_timestamp_done("InitSound");
5790 static void InitMusic(char *identifier)
5792 print_timestamp_init("InitMusic");
5794 if (identifier == NULL)
5795 identifier = artwork.mus_current->identifier;
5797 /* set artwork path to send it to the sound server process */
5798 setLevelArtworkDir(artwork.mus_first);
5800 InitReloadCustomMusic(identifier);
5801 print_timestamp_time("InitReloadCustomMusic");
5803 ReinitializeMusic();
5804 print_timestamp_time("ReinitializeMusic");
5806 print_timestamp_done("InitMusic");
5809 void InitNetworkServer()
5811 #if defined(NETWORK_AVALIABLE)
5815 if (!options.network)
5818 #if defined(NETWORK_AVALIABLE)
5819 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5821 if (!ConnectToServer(options.server_host, options.server_port))
5822 Error(ERR_EXIT, "cannot connect to network game server");
5824 SendToServer_PlayerName(setup.player_name);
5825 SendToServer_ProtocolVersion();
5828 SendToServer_NrWanted(nr_wanted);
5832 static boolean CheckArtworkConfigForCustomElements(char *filename)
5834 SetupFileHash *setup_file_hash;
5835 boolean redefined_ce_found = FALSE;
5837 /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */
5839 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5841 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5843 char *token = HASH_ITERATION_TOKEN(itr);
5845 if (strPrefix(token, "custom_"))
5847 redefined_ce_found = TRUE;
5852 END_HASH_ITERATION(setup_file_hash, itr)
5854 freeSetupFileHash(setup_file_hash);
5857 return redefined_ce_found;
5860 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5862 char *filename_base, *filename_local;
5863 boolean redefined_ce_found = FALSE;
5865 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5868 printf("::: leveldir_current->identifier == '%s'\n",
5869 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5870 printf("::: leveldir_current->graphics_path == '%s'\n",
5871 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5872 printf("::: leveldir_current->graphics_set == '%s'\n",
5873 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5874 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5875 leveldir_current == NULL ? "[NULL]" :
5876 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5879 /* first look for special artwork configured in level series config */
5880 filename_base = getCustomArtworkLevelConfigFilename(type);
5883 printf("::: filename_base == '%s'\n", filename_base);
5886 if (fileExists(filename_base))
5887 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5889 filename_local = getCustomArtworkConfigFilename(type);
5892 printf("::: filename_local == '%s'\n", filename_local);
5895 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5896 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5899 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5902 return redefined_ce_found;
5905 static void InitOverrideArtwork()
5907 boolean redefined_ce_found = FALSE;
5909 /* to check if this level set redefines any CEs, do not use overriding */
5910 gfx.override_level_graphics = FALSE;
5911 gfx.override_level_sounds = FALSE;
5912 gfx.override_level_music = FALSE;
5914 /* now check if this level set has definitions for custom elements */
5915 if (setup.override_level_graphics == AUTO ||
5916 setup.override_level_sounds == AUTO ||
5917 setup.override_level_music == AUTO)
5918 redefined_ce_found =
5919 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5920 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5921 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5924 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5927 if (redefined_ce_found)
5929 /* this level set has CE definitions: change "AUTO" to "FALSE" */
5930 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5931 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
5932 gfx.override_level_music = (setup.override_level_music == TRUE);
5936 /* this level set has no CE definitions: change "AUTO" to "TRUE" */
5937 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5938 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
5939 gfx.override_level_music = (setup.override_level_music != FALSE);
5943 printf("::: => %d, %d, %d\n",
5944 gfx.override_level_graphics,
5945 gfx.override_level_sounds,
5946 gfx.override_level_music);
5950 static char *getNewArtworkIdentifier(int type)
5952 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5953 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5954 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5955 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5956 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5958 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5960 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
5962 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5963 char *leveldir_identifier = leveldir_current->identifier;
5965 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
5966 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5968 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
5970 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5971 char *artwork_current_identifier;
5972 char *artwork_new_identifier = NULL; /* default: nothing has changed */
5974 /* leveldir_current may be invalid (level group, parent link) */
5975 if (!validLevelSeries(leveldir_current))
5978 /* 1st step: determine artwork set to be activated in descending order:
5979 --------------------------------------------------------------------
5980 1. setup artwork (when configured to override everything else)
5981 2. artwork set configured in "levelinfo.conf" of current level set
5982 (artwork in level directory will have priority when loading later)
5983 3. artwork in level directory (stored in artwork sub-directory)
5984 4. setup artwork (currently configured in setup menu) */
5986 if (setup_override_artwork)
5987 artwork_current_identifier = setup_artwork_set;
5988 else if (leveldir_artwork_set != NULL)
5989 artwork_current_identifier = leveldir_artwork_set;
5990 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5991 artwork_current_identifier = leveldir_identifier;
5993 artwork_current_identifier = setup_artwork_set;
5996 /* 2nd step: check if it is really needed to reload artwork set
5997 ------------------------------------------------------------ */
6000 if (type == ARTWORK_TYPE_GRAPHICS)
6001 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
6002 artwork_new_identifier,
6003 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
6004 artwork_current_identifier,
6005 leveldir_current->graphics_set,
6006 leveldir_current->identifier);
6009 /* ---------- reload if level set and also artwork set has changed ------- */
6010 if (leveldir_current_identifier[type] != leveldir_identifier &&
6011 (last_has_level_artwork_set[type] || has_level_artwork_set))
6012 artwork_new_identifier = artwork_current_identifier;
6014 leveldir_current_identifier[type] = leveldir_identifier;
6015 last_has_level_artwork_set[type] = has_level_artwork_set;
6018 if (type == ARTWORK_TYPE_GRAPHICS)
6019 printf("::: 1: '%s'\n", artwork_new_identifier);
6022 /* ---------- reload if "override artwork" setting has changed ----------- */
6023 if (last_override_level_artwork[type] != setup_override_artwork)
6024 artwork_new_identifier = artwork_current_identifier;
6026 last_override_level_artwork[type] = setup_override_artwork;
6029 if (type == ARTWORK_TYPE_GRAPHICS)
6030 printf("::: 2: '%s'\n", artwork_new_identifier);
6033 /* ---------- reload if current artwork identifier has changed ----------- */
6034 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
6035 artwork_current_identifier))
6036 artwork_new_identifier = artwork_current_identifier;
6038 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
6041 if (type == ARTWORK_TYPE_GRAPHICS)
6042 printf("::: 3: '%s'\n", artwork_new_identifier);
6045 /* ---------- do not reload directly after starting ---------------------- */
6046 if (!initialized[type])
6047 artwork_new_identifier = NULL;
6049 initialized[type] = TRUE;
6052 if (type == ARTWORK_TYPE_GRAPHICS)
6053 printf("::: 4: '%s'\n", artwork_new_identifier);
6057 if (type == ARTWORK_TYPE_GRAPHICS)
6058 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
6059 artwork.gfx_current_identifier, artwork_current_identifier,
6060 artwork.gfx_current->identifier, leveldir_current->graphics_set,
6061 artwork_new_identifier);
6064 return artwork_new_identifier;
6067 void ReloadCustomArtwork(int force_reload)
6069 int last_game_status = game_status; /* save current game status */
6070 char *gfx_new_identifier;
6071 char *snd_new_identifier;
6072 char *mus_new_identifier;
6073 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
6074 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
6075 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
6076 boolean reload_needed;
6078 InitOverrideArtwork();
6080 force_reload_gfx |= AdjustGraphicsForEMC();
6082 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
6083 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
6084 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
6086 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
6087 snd_new_identifier != NULL || force_reload_snd ||
6088 mus_new_identifier != NULL || force_reload_mus);
6093 print_timestamp_init("ReloadCustomArtwork");
6095 game_status = GAME_MODE_LOADING;
6097 FadeOut(REDRAW_ALL);
6100 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6102 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
6104 print_timestamp_time("ClearRectangle");
6107 printf("::: fading in ... %d\n", fading.fade_mode);
6111 printf("::: done\n");
6114 if (gfx_new_identifier != NULL || force_reload_gfx)
6117 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
6118 artwork.gfx_current_identifier,
6120 artwork.gfx_current->identifier,
6121 leveldir_current->graphics_set);
6125 print_timestamp_time("InitImages");
6128 if (snd_new_identifier != NULL || force_reload_snd)
6130 InitSound(snd_new_identifier);
6131 print_timestamp_time("InitSound");
6134 if (mus_new_identifier != NULL || force_reload_mus)
6136 InitMusic(mus_new_identifier);
6137 print_timestamp_time("InitMusic");
6140 game_status = last_game_status; /* restore current game status */
6142 init_last = init; /* switch to new busy animation */
6145 printf("::: ----------------DELAY 1 ...\n");
6150 printf("::: FadeOut @ ReloadCustomArtwork ...\n");
6152 FadeOut(REDRAW_ALL);
6154 printf("::: FadeOut @ ReloadCustomArtwork done\n");
6159 /* force redraw of (open or closed) door graphics */
6160 SetDoorState(DOOR_OPEN_ALL);
6161 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
6166 FadeSetEnterScreen();
6167 FadeSkipNextFadeOut();
6168 // FadeSetDisabled();
6173 fading = fading_none;
6178 redraw_mask = REDRAW_ALL;
6181 print_timestamp_done("ReloadCustomArtwork");
6184 void KeyboardAutoRepeatOffUnlessAutoplay()
6186 if (global.autoplay_leveldir == NULL)
6187 KeyboardAutoRepeatOff();
6191 /* ========================================================================= */
6193 /* ========================================================================= */
6197 print_timestamp_init("OpenAll");
6199 game_status = GAME_MODE_LOADING;
6205 InitGlobal(); /* initialize some global variables */
6207 print_timestamp_time("[init global stuff]");
6209 if (options.execute_command)
6210 Execute_Command(options.execute_command);
6212 if (options.serveronly)
6214 #if defined(PLATFORM_UNIX)
6215 NetworkServer(options.server_port, options.serveronly);
6217 Error(ERR_WARN, "networking only supported in Unix version");
6220 exit(0); /* never reached, server loops forever */
6227 InitArtworkInfo(); /* needed before loading gfx, sound & music */
6228 InitArtworkConfig(); /* needed before forking sound child process */
6235 InitRND(NEW_RANDOMIZE);
6236 InitSimpleRandom(NEW_RANDOMIZE);
6240 print_timestamp_time("[init setup/config stuff]");
6243 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
6245 InitEventFilter(FilterMouseMotionEvents);
6247 print_timestamp_time("[init video stuff]");
6249 InitElementPropertiesStatic();
6250 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
6251 InitElementPropertiesGfxElement();
6253 print_timestamp_time("[init element properties stuff]");
6257 print_timestamp_time("InitGfx");
6260 print_timestamp_time("InitLevelInfo");
6262 InitLevelArtworkInfo();
6263 print_timestamp_time("InitLevelArtworkInfo");
6265 InitOverrideArtwork(); /* needs to know current level directory */
6266 print_timestamp_time("InitOverrideArtwork");
6268 InitImages(); /* needs to know current level directory */
6269 print_timestamp_time("InitImages");
6271 InitSound(NULL); /* needs to know current level directory */
6272 print_timestamp_time("InitSound");
6274 InitMusic(NULL); /* needs to know current level directory */
6275 print_timestamp_time("InitMusic");
6277 InitGfxBackground();
6287 if (global.autoplay_leveldir)
6292 else if (global.convert_leveldir)
6297 else if (global.create_images_dir)
6299 CreateLevelSketchImages();
6303 game_status = GAME_MODE_MAIN;
6306 FadeSetEnterScreen();
6307 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
6308 FadeSkipNextFadeOut();
6309 // FadeSetDisabled();
6311 fading = fading_none;
6314 print_timestamp_time("[post-artwork]");
6316 print_timestamp_done("OpenAll");
6320 InitNetworkServer();
6323 void CloseAllAndExit(int exit_value)
6328 CloseAudio(); /* called after freeing sounds (needed for SDL) */
6340 #if defined(TARGET_SDL)
6341 if (network_server) /* terminate network server */
6342 SDL_KillThread(server_thread);
6345 CloseVideoDisplay();
6346 ClosePlatformDependentStuff();
6348 if (exit_value != 0)
6349 NotifyUserAboutErrorFile();