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 0
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 int action_delay = 0;
163 unsigned int 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 int last_counter = -1;
179 unsigned int current_counter = Counter();
180 unsigned int 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 getFixedGraphicSource(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 getFixedGraphicSourceExt(graphic, 0, &dummy,
866 &src_x_back, &src_y_back, TRUE);
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];
1341 Error(ERR_INFO_LINE, "-");
1342 Error(ERR_WARN, "invalid value %d for '%s.width' (fallback done to %d)",
1343 g->width, getTokenFromImageID(graphic), TILEX);
1344 Error(ERR_INFO_LINE, "-");
1346 g->width = TILEX; /* will be checked to be inside bitmap later */
1351 Error(ERR_INFO_LINE, "-");
1352 Error(ERR_WARN, "invalid value %d for '%s.height' (fallback done to %d)",
1353 g->height, getTokenFromImageID(graphic), TILEY);
1354 Error(ERR_INFO_LINE, "-");
1356 g->height = TILEY; /* will be checked to be inside bitmap later */
1361 /* optional zoom factor for scaling up the image to a larger size */
1362 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1363 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1364 if (g->scale_up_factor < 1)
1365 g->scale_up_factor = 1; /* no scaling */
1370 /* get final bitmap size (with scaling, but without small images) */
1371 int src_image_width = get_scaled_graphic_width(graphic);
1372 int src_image_height = get_scaled_graphic_height(graphic);
1374 if (src_image_width == 0 || src_image_height == 0)
1376 /* only happens when loaded outside artwork system (like "global.busy") */
1377 src_image_width = src_bitmap->width;
1378 src_image_height = src_bitmap->height;
1381 anim_frames_per_row = src_image_width / g->width;
1382 anim_frames_per_col = src_image_height / g->height;
1384 g->src_image_width = src_image_width;
1385 g->src_image_height = src_image_height;
1388 /* correct x or y offset dependent of vertical or horizontal frame order */
1389 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1391 g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1392 parameter[GFX_ARG_OFFSET] : g->height);
1393 anim_frames_per_line = anim_frames_per_col;
1395 else /* frames are ordered horizontally */
1397 g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1398 parameter[GFX_ARG_OFFSET] : g->width);
1399 anim_frames_per_line = anim_frames_per_row;
1402 /* optionally, the x and y offset of frames can be specified directly */
1403 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1404 g->offset_x = parameter[GFX_ARG_XOFFSET];
1405 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1406 g->offset_y = parameter[GFX_ARG_YOFFSET];
1408 /* optionally, moving animations may have separate start and end graphics */
1409 g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1411 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1412 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1414 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1415 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1416 g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1417 parameter[GFX_ARG_2ND_OFFSET] : g->height);
1418 else /* frames are ordered horizontally */
1419 g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1420 parameter[GFX_ARG_2ND_OFFSET] : g->width);
1422 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1423 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1424 g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1425 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1426 g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1428 /* optionally, the second movement tile can be specified as start tile */
1429 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1430 g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1432 /* automatically determine correct number of frames, if not defined */
1433 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1434 g->anim_frames = parameter[GFX_ARG_FRAMES];
1435 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1436 g->anim_frames = anim_frames_per_row;
1437 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1438 g->anim_frames = anim_frames_per_col;
1442 if (g->anim_frames == 0) /* frames must be at least 1 */
1445 g->anim_frames_per_line =
1446 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1447 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1449 g->anim_delay = parameter[GFX_ARG_DELAY];
1450 if (g->anim_delay == 0) /* delay must be at least 1 */
1453 g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1455 if (g->anim_frames == 1)
1456 g->anim_mode = ANIM_NONE;
1459 /* automatically determine correct start frame, if not defined */
1460 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1461 g->anim_start_frame = 0;
1462 else if (g->anim_mode & ANIM_REVERSE)
1463 g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1465 g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1467 /* animation synchronized with global frame counter, not move position */
1468 g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1470 /* optional element for cloning crumble graphics */
1471 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1472 g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1474 /* optional element for cloning digging graphics */
1475 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1476 g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1478 /* optional border size for "crumbling" diggable graphics */
1479 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1480 g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1482 /* this is only used for player "boring" and "sleeping" actions */
1483 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1484 g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1485 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1486 g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1487 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1488 g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1489 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1490 g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1492 /* this is only used for toon animations */
1493 g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1494 g->step_delay = parameter[GFX_ARG_STEP_DELAY];
1496 /* this is only used for drawing font characters */
1497 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1498 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1500 /* this is only used for drawing envelope graphics */
1501 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1503 /* optional graphic for cloning all graphics settings */
1504 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1505 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1507 /* optional settings for drawing title screens and title messages */
1508 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1509 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1510 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1511 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1512 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1513 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1514 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1515 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1516 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1517 g->align = parameter[GFX_ARG_ALIGN];
1518 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1519 g->valign = parameter[GFX_ARG_VALIGN];
1520 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1521 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1523 if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
1524 g->class = parameter[GFX_ARG_CLASS];
1525 if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
1526 g->style = parameter[GFX_ARG_STYLE];
1528 /* this is only used for drawing menu buttons and text */
1529 g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
1530 g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
1531 g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
1532 g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
1535 static void set_graphic_parameters(int graphic)
1538 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1539 char **parameter_raw = image->parameter;
1540 Bitmap *src_bitmap = getBitmapFromImageID(graphic);
1541 int parameter[NUM_GFX_ARGS];
1544 /* if fallback to default artwork is done, also use the default parameters */
1545 if (image->fallback_to_default)
1546 parameter_raw = image->default_parameter;
1548 /* get integer values from string parameters */
1549 for (i = 0; i < NUM_GFX_ARGS; i++)
1550 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1551 image_config_suffix[i].token,
1552 image_config_suffix[i].type);
1554 set_graphic_parameters_ext(graphic, parameter, src_bitmap);
1558 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1559 char **parameter_raw = image->parameter;
1560 Bitmap *src_bitmap = getBitmapFromImageID(graphic);
1561 int parameter[NUM_GFX_ARGS];
1562 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1563 int anim_frames_per_line = 1;
1566 /* if fallback to default artwork is done, also use the default parameters */
1567 if (image->fallback_to_default)
1568 parameter_raw = image->default_parameter;
1570 /* get integer values from string parameters */
1571 for (i = 0; i < NUM_GFX_ARGS; i++)
1572 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1573 image_config_suffix[i].token,
1574 image_config_suffix[i].type);
1576 graphic_info[graphic].bitmap = src_bitmap;
1578 /* always start with reliable default values */
1579 graphic_info[graphic].src_image_width = 0;
1580 graphic_info[graphic].src_image_height = 0;
1581 graphic_info[graphic].src_x = 0;
1582 graphic_info[graphic].src_y = 0;
1583 graphic_info[graphic].width = TILEX; /* default for element graphics */
1584 graphic_info[graphic].height = TILEY; /* default for element graphics */
1585 graphic_info[graphic].offset_x = 0; /* one or both of these values ... */
1586 graphic_info[graphic].offset_y = 0; /* ... will be corrected later */
1587 graphic_info[graphic].offset2_x = 0; /* one or both of these values ... */
1588 graphic_info[graphic].offset2_y = 0; /* ... will be corrected later */
1589 graphic_info[graphic].swap_double_tiles = -1; /* auto-detect tile swapping */
1590 graphic_info[graphic].crumbled_like = -1; /* do not use clone element */
1591 graphic_info[graphic].diggable_like = -1; /* do not use clone element */
1592 graphic_info[graphic].border_size = TILEX / 8; /* "CRUMBLED" border size */
1593 graphic_info[graphic].scale_up_factor = 1; /* default: no scaling up */
1594 graphic_info[graphic].clone_from = -1; /* do not use clone graphic */
1595 graphic_info[graphic].anim_delay_fixed = 0;
1596 graphic_info[graphic].anim_delay_random = 0;
1597 graphic_info[graphic].post_delay_fixed = 0;
1598 graphic_info[graphic].post_delay_random = 0;
1599 graphic_info[graphic].fade_mode = FADE_MODE_DEFAULT;
1600 graphic_info[graphic].fade_delay = -1;
1601 graphic_info[graphic].post_delay = -1;
1602 graphic_info[graphic].auto_delay = -1;
1603 graphic_info[graphic].align = ALIGN_CENTER; /* default for title screens */
1604 graphic_info[graphic].valign = VALIGN_MIDDLE; /* default for title screens */
1605 graphic_info[graphic].sort_priority = 0; /* default for title screens */
1608 /* optional zoom factor for scaling up the image to a larger size */
1609 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1610 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1611 if (graphic_info[graphic].scale_up_factor < 1)
1612 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
1616 if (graphic_info[graphic].use_image_size)
1618 /* set new default bitmap size (with scaling, but without small images) */
1619 graphic_info[graphic].width = get_scaled_graphic_width(graphic);
1620 graphic_info[graphic].height = get_scaled_graphic_height(graphic);
1624 /* optional x and y tile position of animation frame sequence */
1625 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1626 graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
1627 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1628 graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
1630 /* optional x and y pixel position of animation frame sequence */
1631 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1632 graphic_info[graphic].src_x = parameter[GFX_ARG_X];
1633 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1634 graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
1636 /* optional width and height of each animation frame */
1637 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1638 graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
1639 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1640 graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
1643 /* optional zoom factor for scaling up the image to a larger size */
1644 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1645 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1646 if (graphic_info[graphic].scale_up_factor < 1)
1647 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
1652 /* get final bitmap size (with scaling, but without small images) */
1653 int src_image_width = get_scaled_graphic_width(graphic);
1654 int src_image_height = get_scaled_graphic_height(graphic);
1656 anim_frames_per_row = src_image_width / graphic_info[graphic].width;
1657 anim_frames_per_col = src_image_height / graphic_info[graphic].height;
1659 graphic_info[graphic].src_image_width = src_image_width;
1660 graphic_info[graphic].src_image_height = src_image_height;
1663 /* correct x or y offset dependent of vertical or horizontal frame order */
1664 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1666 graphic_info[graphic].offset_y =
1667 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1668 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
1669 anim_frames_per_line = anim_frames_per_col;
1671 else /* frames are ordered horizontally */
1673 graphic_info[graphic].offset_x =
1674 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1675 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
1676 anim_frames_per_line = anim_frames_per_row;
1679 /* optionally, the x and y offset of frames can be specified directly */
1680 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1681 graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
1682 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1683 graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
1685 /* optionally, moving animations may have separate start and end graphics */
1686 graphic_info[graphic].double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1688 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1689 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1691 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1692 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1693 graphic_info[graphic].offset2_y =
1694 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1695 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].height);
1696 else /* frames are ordered horizontally */
1697 graphic_info[graphic].offset2_x =
1698 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1699 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].width);
1701 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1702 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1703 graphic_info[graphic].offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1704 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1705 graphic_info[graphic].offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1707 /* optionally, the second movement tile can be specified as start tile */
1708 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1709 graphic_info[graphic].swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1711 /* automatically determine correct number of frames, if not defined */
1712 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1713 graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
1714 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1715 graphic_info[graphic].anim_frames = anim_frames_per_row;
1716 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1717 graphic_info[graphic].anim_frames = anim_frames_per_col;
1719 graphic_info[graphic].anim_frames = 1;
1721 if (graphic_info[graphic].anim_frames == 0) /* frames must be at least 1 */
1722 graphic_info[graphic].anim_frames = 1;
1724 graphic_info[graphic].anim_frames_per_line =
1725 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1726 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1728 graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
1729 if (graphic_info[graphic].anim_delay == 0) /* delay must be at least 1 */
1730 graphic_info[graphic].anim_delay = 1;
1732 graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
1734 if (graphic_info[graphic].anim_frames == 1)
1735 graphic_info[graphic].anim_mode = ANIM_NONE;
1738 /* automatically determine correct start frame, if not defined */
1739 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1740 graphic_info[graphic].anim_start_frame = 0;
1741 else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
1742 graphic_info[graphic].anim_start_frame =
1743 graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1745 graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
1747 /* animation synchronized with global frame counter, not move position */
1748 graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1750 /* optional element for cloning crumble graphics */
1751 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1752 graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1754 /* optional element for cloning digging graphics */
1755 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1756 graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1758 /* optional border size for "crumbling" diggable graphics */
1759 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1760 graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
1762 /* this is only used for player "boring" and "sleeping" actions */
1763 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1764 graphic_info[graphic].anim_delay_fixed =
1765 parameter[GFX_ARG_ANIM_DELAY_FIXED];
1766 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1767 graphic_info[graphic].anim_delay_random =
1768 parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1769 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1770 graphic_info[graphic].post_delay_fixed =
1771 parameter[GFX_ARG_POST_DELAY_FIXED];
1772 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1773 graphic_info[graphic].post_delay_random =
1774 parameter[GFX_ARG_POST_DELAY_RANDOM];
1776 /* this is only used for toon animations */
1777 graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
1778 graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY];
1780 /* this is only used for drawing font characters */
1781 graphic_info[graphic].draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1782 graphic_info[graphic].draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1784 /* this is only used for drawing envelope graphics */
1785 graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1787 /* optional graphic for cloning all graphics settings */
1788 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1789 graphic_info[graphic].clone_from = parameter[GFX_ARG_CLONE_FROM];
1791 /* optional settings for drawing title screens and title messages */
1792 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1793 graphic_info[graphic].fade_mode = parameter[GFX_ARG_FADE_MODE];
1794 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1795 graphic_info[graphic].fade_delay = parameter[GFX_ARG_FADE_DELAY];
1796 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1797 graphic_info[graphic].post_delay = parameter[GFX_ARG_POST_DELAY];
1798 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1799 graphic_info[graphic].auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1800 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1801 graphic_info[graphic].align = parameter[GFX_ARG_ALIGN];
1802 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1803 graphic_info[graphic].valign = parameter[GFX_ARG_VALIGN];
1804 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1805 graphic_info[graphic].sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1808 UPDATE_BUSY_STATE();
1811 static void set_cloned_graphic_parameters(int graphic)
1813 int fallback_graphic = IMG_CHAR_EXCLAM;
1814 int max_num_images = getImageListSize();
1815 int clone_graphic = graphic_info[graphic].clone_from;
1816 int num_references_followed = 1;
1818 while (graphic_info[clone_graphic].clone_from != -1 &&
1819 num_references_followed < max_num_images)
1821 clone_graphic = graphic_info[clone_graphic].clone_from;
1823 num_references_followed++;
1826 if (num_references_followed >= max_num_images)
1828 Error(ERR_INFO_LINE, "-");
1829 Error(ERR_INFO, "warning: error found in config file:");
1830 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1831 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1832 Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1833 Error(ERR_INFO, "custom graphic rejected for this element/action");
1835 if (graphic == fallback_graphic)
1836 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1838 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1839 Error(ERR_INFO_LINE, "-");
1841 graphic_info[graphic] = graphic_info[fallback_graphic];
1845 graphic_info[graphic] = graphic_info[clone_graphic];
1846 graphic_info[graphic].clone_from = clone_graphic;
1850 static void InitGraphicInfo()
1852 int fallback_graphic = IMG_CHAR_EXCLAM;
1853 int num_images = getImageListSize();
1856 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1857 static boolean clipmasks_initialized = FALSE;
1859 XGCValues clip_gc_values;
1860 unsigned int clip_gc_valuemask;
1861 GC copy_clipmask_gc = None;
1864 /* use image size as default values for width and height for these images */
1865 static int full_size_graphics[] =
1870 IMG_BACKGROUND_ENVELOPE_1,
1871 IMG_BACKGROUND_ENVELOPE_2,
1872 IMG_BACKGROUND_ENVELOPE_3,
1873 IMG_BACKGROUND_ENVELOPE_4,
1876 IMG_BACKGROUND_TITLE_INITIAL,
1877 IMG_BACKGROUND_TITLE,
1878 IMG_BACKGROUND_MAIN,
1879 IMG_BACKGROUND_LEVELS,
1880 IMG_BACKGROUND_LEVELNR,
1881 IMG_BACKGROUND_SCORES,
1882 IMG_BACKGROUND_EDITOR,
1883 IMG_BACKGROUND_INFO,
1884 IMG_BACKGROUND_INFO_ELEMENTS,
1885 IMG_BACKGROUND_INFO_MUSIC,
1886 IMG_BACKGROUND_INFO_CREDITS,
1887 IMG_BACKGROUND_INFO_PROGRAM,
1888 IMG_BACKGROUND_INFO_LEVELSET,
1889 IMG_BACKGROUND_SETUP,
1890 IMG_BACKGROUND_DOOR,
1891 IMG_BACKGROUND_TAPE,
1892 IMG_BACKGROUND_PANEL,
1894 IMG_TITLESCREEN_INITIAL_1,
1895 IMG_TITLESCREEN_INITIAL_2,
1896 IMG_TITLESCREEN_INITIAL_3,
1897 IMG_TITLESCREEN_INITIAL_4,
1898 IMG_TITLESCREEN_INITIAL_5,
1908 checked_free(graphic_info);
1910 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1913 /* initialize "use_image_size" flag with default value */
1914 for (i = 0; i < num_images; i++)
1915 graphic_info[i].use_image_size = FALSE;
1917 /* initialize "use_image_size" flag from static configuration above */
1918 for (i = 0; full_size_graphics[i] != -1; i++)
1919 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1922 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1923 if (clipmasks_initialized)
1925 for (i = 0; i < num_images; i++)
1927 if (graphic_info[i].clip_mask)
1928 XFreePixmap(display, graphic_info[i].clip_mask);
1929 if (graphic_info[i].clip_gc)
1930 XFreeGC(display, graphic_info[i].clip_gc);
1932 graphic_info[i].clip_mask = None;
1933 graphic_info[i].clip_gc = None;
1938 /* first set all graphic paramaters ... */
1939 for (i = 0; i < num_images; i++)
1940 set_graphic_parameters(i);
1942 /* ... then copy these parameters for cloned graphics */
1943 for (i = 0; i < num_images; i++)
1944 if (graphic_info[i].clone_from != -1)
1945 set_cloned_graphic_parameters(i);
1947 for (i = 0; i < num_images; i++)
1952 int first_frame, last_frame;
1953 int src_bitmap_width, src_bitmap_height;
1955 /* now check if no animation frames are outside of the loaded image */
1957 if (graphic_info[i].bitmap == NULL)
1958 continue; /* skip check for optional images that are undefined */
1960 /* get image size (this can differ from the standard element tile size!) */
1961 width = graphic_info[i].width;
1962 height = graphic_info[i].height;
1964 /* get final bitmap size (with scaling, but without small images) */
1965 src_bitmap_width = graphic_info[i].src_image_width;
1966 src_bitmap_height = graphic_info[i].src_image_height;
1968 /* check if first animation frame is inside specified bitmap */
1971 getFixedGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1974 /* this avoids calculating wrong start position for out-of-bounds frame */
1975 src_x = graphic_info[i].src_x;
1976 src_y = graphic_info[i].src_y;
1979 if (src_x < 0 || src_y < 0 ||
1980 src_x + width > src_bitmap_width ||
1981 src_y + height > src_bitmap_height)
1983 Error(ERR_INFO_LINE, "-");
1984 Error(ERR_INFO, "warning: error found in config file:");
1985 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1986 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1987 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1989 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1990 src_x, src_y, src_bitmap_width, src_bitmap_height);
1991 Error(ERR_INFO, "custom graphic rejected for this element/action");
1993 if (i == fallback_graphic)
1994 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1996 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1997 Error(ERR_INFO_LINE, "-");
1999 graphic_info[i] = graphic_info[fallback_graphic];
2002 /* check if last animation frame is inside specified bitmap */
2004 last_frame = graphic_info[i].anim_frames - 1;
2005 getFixedGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
2007 if (src_x < 0 || src_y < 0 ||
2008 src_x + width > src_bitmap_width ||
2009 src_y + height > src_bitmap_height)
2011 Error(ERR_INFO_LINE, "-");
2012 Error(ERR_INFO, "warning: error found in config file:");
2013 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
2014 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
2015 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
2017 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
2018 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
2019 Error(ERR_INFO, "::: %d, %d", width, height);
2020 Error(ERR_INFO, "custom graphic rejected for this element/action");
2022 if (i == fallback_graphic)
2023 Error(ERR_EXIT, "fatal error: no fallback graphic available");
2025 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
2026 Error(ERR_INFO_LINE, "-");
2028 graphic_info[i] = graphic_info[fallback_graphic];
2031 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
2032 /* currently we only need a tile clip mask from the first frame */
2033 getFixedGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
2035 if (copy_clipmask_gc == None)
2037 clip_gc_values.graphics_exposures = False;
2038 clip_gc_valuemask = GCGraphicsExposures;
2039 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
2040 clip_gc_valuemask, &clip_gc_values);
2043 graphic_info[i].clip_mask =
2044 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
2046 src_pixmap = src_bitmap->clip_mask;
2047 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
2048 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
2050 clip_gc_values.graphics_exposures = False;
2051 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
2052 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
2054 graphic_info[i].clip_gc =
2055 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
2059 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
2060 if (copy_clipmask_gc)
2061 XFreeGC(display, copy_clipmask_gc);
2063 clipmasks_initialized = TRUE;
2067 static void InitGraphicCompatibilityInfo()
2069 struct FileInfo *fi_global_door =
2070 getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
2071 int num_images = getImageListSize();
2074 /* the following compatibility handling is needed for the following case:
2075 versions up to 3.3.0.0 used one large bitmap "global.door" for various
2076 graphics mainly used for door and panel graphics, like editor, tape and
2077 in-game buttons with hard-coded bitmap positions and button sizes; as
2078 these graphics now have individual definitions, redefining "global.door"
2079 to change all these graphics at once like before does not work anymore
2080 (because all those individual definitions still have their default values);
2081 to solve this, remap all those individual definitions that are not
2082 redefined to the new bitmap of "global.door" if it was redefined */
2084 /* special compatibility handling if image "global.door" was redefined */
2085 if (fi_global_door->redefined)
2087 for (i = 0; i < num_images; i++)
2089 struct FileInfo *fi = getImageListEntryFromImageID(i);
2091 /* process only those images that still use the default settings */
2094 /* process all images which default to same image as "global.door" */
2095 if (strEqual(fi->default_filename, fi_global_door->default_filename))
2097 // printf("::: special treatment needed for token '%s'\n", fi->token);
2099 graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2106 for (i = 0; i < num_images; i++)
2108 struct FileInfo *fi = getImageListEntryFromImageID(i);
2110 if (i == IMG_GLOBAL_DOOR)
2112 printf("::: %s, %s, %d\n",
2113 fi->default_filename,
2121 static void InitElementSoundInfo()
2123 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
2124 int num_property_mappings = getSoundListPropertyMappingSize();
2127 /* set values to -1 to identify later as "uninitialized" values */
2128 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2129 for (act = 0; act < NUM_ACTIONS; act++)
2130 element_info[i].sound[act] = -1;
2132 /* initialize element/sound mapping from static configuration */
2133 for (i = 0; element_to_sound[i].element > -1; i++)
2135 int element = element_to_sound[i].element;
2136 int action = element_to_sound[i].action;
2137 int sound = element_to_sound[i].sound;
2138 boolean is_class = element_to_sound[i].is_class;
2141 action = ACTION_DEFAULT;
2144 element_info[element].sound[action] = sound;
2146 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2147 if (strEqual(element_info[j].class_name,
2148 element_info[element].class_name))
2149 element_info[j].sound[action] = sound;
2152 /* initialize element class/sound mapping from dynamic configuration */
2153 for (i = 0; i < num_property_mappings; i++)
2155 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
2156 int action = property_mapping[i].ext1_index;
2157 int sound = property_mapping[i].artwork_index;
2159 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
2163 action = ACTION_DEFAULT;
2165 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2166 if (strEqual(element_info[j].class_name,
2167 element_info[element_class].class_name))
2168 element_info[j].sound[action] = sound;
2171 /* initialize element/sound mapping from dynamic configuration */
2172 for (i = 0; i < num_property_mappings; i++)
2174 int element = property_mapping[i].base_index;
2175 int action = property_mapping[i].ext1_index;
2176 int sound = property_mapping[i].artwork_index;
2178 if (element >= MAX_NUM_ELEMENTS)
2182 action = ACTION_DEFAULT;
2184 element_info[element].sound[action] = sound;
2187 /* now set all '-1' values to element specific default values */
2188 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2190 for (act = 0; act < NUM_ACTIONS; act++)
2192 /* generic default action sound (defined by "[default]" directive) */
2193 int default_action_sound = element_info[EL_DEFAULT].sound[act];
2195 /* look for special default action sound (classic game specific) */
2196 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
2197 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
2198 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
2199 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
2200 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
2201 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
2203 /* !!! there's no such thing as a "default action sound" !!! */
2205 /* look for element specific default sound (independent from action) */
2206 if (element_info[i].sound[ACTION_DEFAULT] != -1)
2207 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
2211 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
2212 /* !!! make this better !!! */
2213 if (i == EL_EMPTY_SPACE)
2214 default_action_sound = element_info[EL_DEFAULT].sound[act];
2217 /* no sound for this specific action -- use default action sound */
2218 if (element_info[i].sound[act] == -1)
2219 element_info[i].sound[act] = default_action_sound;
2223 /* copy sound settings to some elements that are only stored in level file
2224 in native R'n'D levels, but are used by game engine in native EM levels */
2225 for (i = 0; copy_properties[i][0] != -1; i++)
2226 for (j = 1; j <= 4; j++)
2227 for (act = 0; act < NUM_ACTIONS; act++)
2228 element_info[copy_properties[i][j]].sound[act] =
2229 element_info[copy_properties[i][0]].sound[act];
2232 static void InitGameModeSoundInfo()
2236 /* set values to -1 to identify later as "uninitialized" values */
2237 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2240 /* initialize gamemode/sound mapping from static configuration */
2241 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
2243 int gamemode = gamemode_to_sound[i].gamemode;
2244 int sound = gamemode_to_sound[i].sound;
2247 gamemode = GAME_MODE_DEFAULT;
2249 menu.sound[gamemode] = sound;
2252 /* now set all '-1' values to levelset specific default values */
2253 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2254 if (menu.sound[i] == -1)
2255 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
2258 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2259 if (menu.sound[i] != -1)
2260 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
2264 static void set_sound_parameters(int sound, char **parameter_raw)
2266 int parameter[NUM_SND_ARGS];
2269 /* get integer values from string parameters */
2270 for (i = 0; i < NUM_SND_ARGS; i++)
2272 get_parameter_value(parameter_raw[i],
2273 sound_config_suffix[i].token,
2274 sound_config_suffix[i].type);
2276 /* explicit loop mode setting in configuration overrides default value */
2277 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2278 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
2280 /* sound volume to change the original volume when loading the sound file */
2281 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
2283 /* sound priority to give certain sounds a higher or lower priority */
2284 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
2287 static void InitSoundInfo()
2289 int *sound_effect_properties;
2290 int num_sounds = getSoundListSize();
2293 checked_free(sound_info);
2295 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
2296 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
2298 /* initialize sound effect for all elements to "no sound" */
2299 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2300 for (j = 0; j < NUM_ACTIONS; j++)
2301 element_info[i].sound[j] = SND_UNDEFINED;
2303 for (i = 0; i < num_sounds; i++)
2305 struct FileInfo *sound = getSoundListEntry(i);
2306 int len_effect_text = strlen(sound->token);
2308 sound_effect_properties[i] = ACTION_OTHER;
2309 sound_info[i].loop = FALSE; /* default: play sound only once */
2312 printf("::: sound %d: '%s'\n", i, sound->token);
2315 /* determine all loop sounds and identify certain sound classes */
2317 for (j = 0; element_action_info[j].suffix; j++)
2319 int len_action_text = strlen(element_action_info[j].suffix);
2321 if (len_action_text < len_effect_text &&
2322 strEqual(&sound->token[len_effect_text - len_action_text],
2323 element_action_info[j].suffix))
2325 sound_effect_properties[i] = element_action_info[j].value;
2326 sound_info[i].loop = element_action_info[j].is_loop_sound;
2332 /* associate elements and some selected sound actions */
2334 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2336 if (element_info[j].class_name)
2338 int len_class_text = strlen(element_info[j].class_name);
2340 if (len_class_text + 1 < len_effect_text &&
2341 strncmp(sound->token,
2342 element_info[j].class_name, len_class_text) == 0 &&
2343 sound->token[len_class_text] == '.')
2345 int sound_action_value = sound_effect_properties[i];
2347 element_info[j].sound[sound_action_value] = i;
2352 set_sound_parameters(i, sound->parameter);
2355 free(sound_effect_properties);
2358 static void InitGameModeMusicInfo()
2360 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
2361 int num_property_mappings = getMusicListPropertyMappingSize();
2362 int default_levelset_music = -1;
2365 /* set values to -1 to identify later as "uninitialized" values */
2366 for (i = 0; i < MAX_LEVELS; i++)
2367 levelset.music[i] = -1;
2368 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2371 /* initialize gamemode/music mapping from static configuration */
2372 for (i = 0; gamemode_to_music[i].music > -1; i++)
2374 int gamemode = gamemode_to_music[i].gamemode;
2375 int music = gamemode_to_music[i].music;
2378 printf("::: gamemode == %d, music == %d\n", gamemode, music);
2382 gamemode = GAME_MODE_DEFAULT;
2384 menu.music[gamemode] = music;
2387 /* initialize gamemode/music mapping from dynamic configuration */
2388 for (i = 0; i < num_property_mappings; i++)
2390 int prefix = property_mapping[i].base_index;
2391 int gamemode = property_mapping[i].ext1_index;
2392 int level = property_mapping[i].ext2_index;
2393 int music = property_mapping[i].artwork_index;
2396 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
2397 prefix, gamemode, level, music);
2400 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
2404 gamemode = GAME_MODE_DEFAULT;
2406 /* level specific music only allowed for in-game music */
2407 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
2408 gamemode = GAME_MODE_PLAYING;
2413 default_levelset_music = music;
2416 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
2417 levelset.music[level] = music;
2418 if (gamemode != GAME_MODE_PLAYING)
2419 menu.music[gamemode] = music;
2422 /* now set all '-1' values to menu specific default values */
2423 /* (undefined values of "levelset.music[]" might stay at "-1" to
2424 allow dynamic selection of music files from music directory!) */
2425 for (i = 0; i < MAX_LEVELS; i++)
2426 if (levelset.music[i] == -1)
2427 levelset.music[i] = default_levelset_music;
2428 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2429 if (menu.music[i] == -1)
2430 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
2433 for (i = 0; i < MAX_LEVELS; i++)
2434 if (levelset.music[i] != -1)
2435 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
2436 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2437 if (menu.music[i] != -1)
2438 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
2442 static void set_music_parameters(int music, char **parameter_raw)
2444 int parameter[NUM_MUS_ARGS];
2447 /* get integer values from string parameters */
2448 for (i = 0; i < NUM_MUS_ARGS; i++)
2450 get_parameter_value(parameter_raw[i],
2451 music_config_suffix[i].token,
2452 music_config_suffix[i].type);
2454 /* explicit loop mode setting in configuration overrides default value */
2455 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2456 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
2459 static void InitMusicInfo()
2461 int num_music = getMusicListSize();
2464 checked_free(music_info);
2466 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
2468 for (i = 0; i < num_music; i++)
2470 struct FileInfo *music = getMusicListEntry(i);
2471 int len_music_text = strlen(music->token);
2473 music_info[i].loop = TRUE; /* default: play music in loop mode */
2475 /* determine all loop music */
2477 for (j = 0; music_prefix_info[j].prefix; j++)
2479 int len_prefix_text = strlen(music_prefix_info[j].prefix);
2481 if (len_prefix_text < len_music_text &&
2482 strncmp(music->token,
2483 music_prefix_info[j].prefix, len_prefix_text) == 0)
2485 music_info[i].loop = music_prefix_info[j].is_loop_music;
2491 set_music_parameters(i, music->parameter);
2495 static void ReinitializeGraphics()
2497 print_timestamp_init("ReinitializeGraphics");
2499 InitGraphicInfo(); /* graphic properties mapping */
2500 print_timestamp_time("InitGraphicInfo");
2501 InitElementGraphicInfo(); /* element game graphic mapping */
2502 print_timestamp_time("InitElementGraphicInfo");
2503 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
2504 print_timestamp_time("InitElementSpecialGraphicInfo");
2506 InitElementSmallImages(); /* scale elements to all needed sizes */
2507 print_timestamp_time("InitElementSmallImages");
2508 InitScaledImages(); /* scale all other images, if needed */
2509 print_timestamp_time("InitScaledImages");
2510 InitFontGraphicInfo(); /* initialize text drawing functions */
2511 print_timestamp_time("InitFontGraphicInfo");
2513 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
2514 print_timestamp_time("InitGraphicInfo_EM");
2516 InitGraphicCompatibilityInfo();
2517 print_timestamp_time("InitGraphicCompatibilityInfo");
2519 SetMainBackgroundImage(IMG_BACKGROUND);
2520 print_timestamp_time("SetMainBackgroundImage");
2521 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2522 print_timestamp_time("SetDoorBackgroundImage");
2525 print_timestamp_time("InitGadgets");
2527 print_timestamp_time("InitToons");
2529 print_timestamp_done("ReinitializeGraphics");
2532 static void ReinitializeSounds()
2534 InitSoundInfo(); /* sound properties mapping */
2535 InitElementSoundInfo(); /* element game sound mapping */
2536 InitGameModeSoundInfo(); /* game mode sound mapping */
2538 InitPlayLevelSound(); /* internal game sound settings */
2541 static void ReinitializeMusic()
2543 InitMusicInfo(); /* music properties mapping */
2544 InitGameModeMusicInfo(); /* game mode music mapping */
2547 static int get_special_property_bit(int element, int property_bit_nr)
2549 struct PropertyBitInfo
2555 static struct PropertyBitInfo pb_can_move_into_acid[] =
2557 /* the player may be able fall into acid when gravity is activated */
2562 { EL_SP_MURPHY, 0 },
2563 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2565 /* all elements that can move may be able to also move into acid */
2568 { EL_BUG_RIGHT, 1 },
2571 { EL_SPACESHIP, 2 },
2572 { EL_SPACESHIP_LEFT, 2 },
2573 { EL_SPACESHIP_RIGHT, 2 },
2574 { EL_SPACESHIP_UP, 2 },
2575 { EL_SPACESHIP_DOWN, 2 },
2576 { EL_BD_BUTTERFLY, 3 },
2577 { EL_BD_BUTTERFLY_LEFT, 3 },
2578 { EL_BD_BUTTERFLY_RIGHT, 3 },
2579 { EL_BD_BUTTERFLY_UP, 3 },
2580 { EL_BD_BUTTERFLY_DOWN, 3 },
2581 { EL_BD_FIREFLY, 4 },
2582 { EL_BD_FIREFLY_LEFT, 4 },
2583 { EL_BD_FIREFLY_RIGHT, 4 },
2584 { EL_BD_FIREFLY_UP, 4 },
2585 { EL_BD_FIREFLY_DOWN, 4 },
2587 { EL_YAMYAM_LEFT, 5 },
2588 { EL_YAMYAM_RIGHT, 5 },
2589 { EL_YAMYAM_UP, 5 },
2590 { EL_YAMYAM_DOWN, 5 },
2591 { EL_DARK_YAMYAM, 6 },
2594 { EL_PACMAN_LEFT, 8 },
2595 { EL_PACMAN_RIGHT, 8 },
2596 { EL_PACMAN_UP, 8 },
2597 { EL_PACMAN_DOWN, 8 },
2599 { EL_MOLE_LEFT, 9 },
2600 { EL_MOLE_RIGHT, 9 },
2602 { EL_MOLE_DOWN, 9 },
2606 { EL_SATELLITE, 13 },
2607 { EL_SP_SNIKSNAK, 14 },
2608 { EL_SP_ELECTRON, 15 },
2611 { EL_EMC_ANDROID, 18 },
2616 static struct PropertyBitInfo pb_dont_collide_with[] =
2618 { EL_SP_SNIKSNAK, 0 },
2619 { EL_SP_ELECTRON, 1 },
2627 struct PropertyBitInfo *pb_info;
2630 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2631 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2636 struct PropertyBitInfo *pb_info = NULL;
2639 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2640 if (pb_definition[i].bit_nr == property_bit_nr)
2641 pb_info = pb_definition[i].pb_info;
2643 if (pb_info == NULL)
2646 for (i = 0; pb_info[i].element != -1; i++)
2647 if (pb_info[i].element == element)
2648 return pb_info[i].bit_nr;
2653 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2654 boolean property_value)
2656 int bit_nr = get_special_property_bit(element, property_bit_nr);
2661 *bitfield |= (1 << bit_nr);
2663 *bitfield &= ~(1 << bit_nr);
2667 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2669 int bit_nr = get_special_property_bit(element, property_bit_nr);
2672 return ((*bitfield & (1 << bit_nr)) != 0);
2677 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2679 static int group_nr;
2680 static struct ElementGroupInfo *group;
2681 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2684 if (actual_group == NULL) /* not yet initialized */
2687 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
2689 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2690 group_element - EL_GROUP_START + 1);
2692 /* replace element which caused too deep recursion by question mark */
2693 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2698 if (recursion_depth == 0) /* initialization */
2700 group = actual_group;
2701 group_nr = GROUP_NR(group_element);
2703 group->num_elements_resolved = 0;
2704 group->choice_pos = 0;
2706 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2707 element_info[i].in_group[group_nr] = FALSE;
2710 for (i = 0; i < actual_group->num_elements; i++)
2712 int element = actual_group->element[i];
2714 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2717 if (IS_GROUP_ELEMENT(element))
2718 ResolveGroupElementExt(element, recursion_depth + 1);
2721 group->element_resolved[group->num_elements_resolved++] = element;
2722 element_info[element].in_group[group_nr] = TRUE;
2727 void ResolveGroupElement(int group_element)
2729 ResolveGroupElementExt(group_element, 0);
2732 void InitElementPropertiesStatic()
2734 static boolean clipboard_elements_initialized = FALSE;
2736 static int ep_diggable[] =
2741 EL_SP_BUGGY_BASE_ACTIVATING,
2744 EL_INVISIBLE_SAND_ACTIVE,
2747 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2748 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2753 EL_SP_BUGGY_BASE_ACTIVE,
2760 static int ep_collectible_only[] =
2782 EL_DYNABOMB_INCREASE_NUMBER,
2783 EL_DYNABOMB_INCREASE_SIZE,
2784 EL_DYNABOMB_INCREASE_POWER,
2802 /* !!! handle separately !!! */
2803 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2809 static int ep_dont_run_into[] =
2811 /* same elements as in 'ep_dont_touch' */
2817 /* same elements as in 'ep_dont_collide_with' */
2829 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2834 EL_SP_BUGGY_BASE_ACTIVE,
2841 static int ep_dont_collide_with[] =
2843 /* same elements as in 'ep_dont_touch' */
2860 static int ep_dont_touch[] =
2870 static int ep_indestructible[] =
2874 EL_ACID_POOL_TOPLEFT,
2875 EL_ACID_POOL_TOPRIGHT,
2876 EL_ACID_POOL_BOTTOMLEFT,
2877 EL_ACID_POOL_BOTTOM,
2878 EL_ACID_POOL_BOTTOMRIGHT,
2879 EL_SP_HARDWARE_GRAY,
2880 EL_SP_HARDWARE_GREEN,
2881 EL_SP_HARDWARE_BLUE,
2883 EL_SP_HARDWARE_YELLOW,
2884 EL_SP_HARDWARE_BASE_1,
2885 EL_SP_HARDWARE_BASE_2,
2886 EL_SP_HARDWARE_BASE_3,
2887 EL_SP_HARDWARE_BASE_4,
2888 EL_SP_HARDWARE_BASE_5,
2889 EL_SP_HARDWARE_BASE_6,
2890 EL_INVISIBLE_STEELWALL,
2891 EL_INVISIBLE_STEELWALL_ACTIVE,
2892 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2893 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2894 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2895 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2896 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2897 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2898 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2899 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2900 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2901 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2902 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2903 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2905 EL_LIGHT_SWITCH_ACTIVE,
2906 EL_SIGN_EXCLAMATION,
2907 EL_SIGN_RADIOACTIVITY,
2914 EL_SIGN_ENTRY_FORBIDDEN,
2915 EL_SIGN_EMERGENCY_EXIT,
2923 EL_STEEL_EXIT_CLOSED,
2925 EL_STEEL_EXIT_OPENING,
2926 EL_STEEL_EXIT_CLOSING,
2927 EL_EM_STEEL_EXIT_CLOSED,
2928 EL_EM_STEEL_EXIT_OPEN,
2929 EL_EM_STEEL_EXIT_OPENING,
2930 EL_EM_STEEL_EXIT_CLOSING,
2931 EL_DC_STEELWALL_1_LEFT,
2932 EL_DC_STEELWALL_1_RIGHT,
2933 EL_DC_STEELWALL_1_TOP,
2934 EL_DC_STEELWALL_1_BOTTOM,
2935 EL_DC_STEELWALL_1_HORIZONTAL,
2936 EL_DC_STEELWALL_1_VERTICAL,
2937 EL_DC_STEELWALL_1_TOPLEFT,
2938 EL_DC_STEELWALL_1_TOPRIGHT,
2939 EL_DC_STEELWALL_1_BOTTOMLEFT,
2940 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2941 EL_DC_STEELWALL_1_TOPLEFT_2,
2942 EL_DC_STEELWALL_1_TOPRIGHT_2,
2943 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2944 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2945 EL_DC_STEELWALL_2_LEFT,
2946 EL_DC_STEELWALL_2_RIGHT,
2947 EL_DC_STEELWALL_2_TOP,
2948 EL_DC_STEELWALL_2_BOTTOM,
2949 EL_DC_STEELWALL_2_HORIZONTAL,
2950 EL_DC_STEELWALL_2_VERTICAL,
2951 EL_DC_STEELWALL_2_MIDDLE,
2952 EL_DC_STEELWALL_2_SINGLE,
2953 EL_STEELWALL_SLIPPERY,
2967 EL_GATE_1_GRAY_ACTIVE,
2968 EL_GATE_2_GRAY_ACTIVE,
2969 EL_GATE_3_GRAY_ACTIVE,
2970 EL_GATE_4_GRAY_ACTIVE,
2979 EL_EM_GATE_1_GRAY_ACTIVE,
2980 EL_EM_GATE_2_GRAY_ACTIVE,
2981 EL_EM_GATE_3_GRAY_ACTIVE,
2982 EL_EM_GATE_4_GRAY_ACTIVE,
2991 EL_EMC_GATE_5_GRAY_ACTIVE,
2992 EL_EMC_GATE_6_GRAY_ACTIVE,
2993 EL_EMC_GATE_7_GRAY_ACTIVE,
2994 EL_EMC_GATE_8_GRAY_ACTIVE,
2996 EL_DC_GATE_WHITE_GRAY,
2997 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2998 EL_DC_GATE_FAKE_GRAY,
3000 EL_SWITCHGATE_OPENING,
3001 EL_SWITCHGATE_CLOSED,
3002 EL_SWITCHGATE_CLOSING,
3004 EL_DC_SWITCHGATE_SWITCH_UP,
3005 EL_DC_SWITCHGATE_SWITCH_DOWN,
3008 EL_TIMEGATE_OPENING,
3010 EL_TIMEGATE_CLOSING,
3012 EL_DC_TIMEGATE_SWITCH,
3013 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3018 EL_TUBE_VERTICAL_LEFT,
3019 EL_TUBE_VERTICAL_RIGHT,
3020 EL_TUBE_HORIZONTAL_UP,
3021 EL_TUBE_HORIZONTAL_DOWN,
3026 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
3027 EL_EXPANDABLE_STEELWALL_VERTICAL,
3028 EL_EXPANDABLE_STEELWALL_ANY,
3033 static int ep_slippery[] =
3047 EL_ROBOT_WHEEL_ACTIVE,
3053 EL_ACID_POOL_TOPLEFT,
3054 EL_ACID_POOL_TOPRIGHT,
3064 EL_STEELWALL_SLIPPERY,
3067 EL_EMC_WALL_SLIPPERY_1,
3068 EL_EMC_WALL_SLIPPERY_2,
3069 EL_EMC_WALL_SLIPPERY_3,
3070 EL_EMC_WALL_SLIPPERY_4,
3072 EL_EMC_MAGIC_BALL_ACTIVE,
3077 static int ep_can_change[] =
3082 static int ep_can_move[] =
3084 /* same elements as in 'pb_can_move_into_acid' */
3107 static int ep_can_fall[] =
3121 EL_QUICKSAND_FAST_FULL,
3123 EL_BD_MAGIC_WALL_FULL,
3124 EL_DC_MAGIC_WALL_FULL,
3138 static int ep_can_smash_player[] =
3164 static int ep_can_smash_enemies[] =
3173 static int ep_can_smash_everything[] =
3182 static int ep_explodes_by_fire[] =
3184 /* same elements as in 'ep_explodes_impact' */
3189 /* same elements as in 'ep_explodes_smashed' */
3199 EL_EM_DYNAMITE_ACTIVE,
3200 EL_DYNABOMB_PLAYER_1_ACTIVE,
3201 EL_DYNABOMB_PLAYER_2_ACTIVE,
3202 EL_DYNABOMB_PLAYER_3_ACTIVE,
3203 EL_DYNABOMB_PLAYER_4_ACTIVE,
3204 EL_DYNABOMB_INCREASE_NUMBER,
3205 EL_DYNABOMB_INCREASE_SIZE,
3206 EL_DYNABOMB_INCREASE_POWER,
3207 EL_SP_DISK_RED_ACTIVE,
3221 static int ep_explodes_smashed[] =
3223 /* same elements as in 'ep_explodes_impact' */
3237 static int ep_explodes_impact[] =
3246 static int ep_walkable_over[] =
3250 EL_SOKOBAN_FIELD_EMPTY,
3259 EL_EM_STEEL_EXIT_OPEN,
3261 EL_EM_STEEL_EXIT_OPENING,
3271 EL_GATE_1_GRAY_ACTIVE,
3272 EL_GATE_2_GRAY_ACTIVE,
3273 EL_GATE_3_GRAY_ACTIVE,
3274 EL_GATE_4_GRAY_ACTIVE,
3282 static int ep_walkable_inside[] =
3287 EL_TUBE_VERTICAL_LEFT,
3288 EL_TUBE_VERTICAL_RIGHT,
3289 EL_TUBE_HORIZONTAL_UP,
3290 EL_TUBE_HORIZONTAL_DOWN,
3299 static int ep_walkable_under[] =
3304 static int ep_passable_over[] =
3314 EL_EM_GATE_1_GRAY_ACTIVE,
3315 EL_EM_GATE_2_GRAY_ACTIVE,
3316 EL_EM_GATE_3_GRAY_ACTIVE,
3317 EL_EM_GATE_4_GRAY_ACTIVE,
3326 EL_EMC_GATE_5_GRAY_ACTIVE,
3327 EL_EMC_GATE_6_GRAY_ACTIVE,
3328 EL_EMC_GATE_7_GRAY_ACTIVE,
3329 EL_EMC_GATE_8_GRAY_ACTIVE,
3331 EL_DC_GATE_WHITE_GRAY,
3332 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3339 static int ep_passable_inside[] =
3345 EL_SP_PORT_HORIZONTAL,
3346 EL_SP_PORT_VERTICAL,
3348 EL_SP_GRAVITY_PORT_LEFT,
3349 EL_SP_GRAVITY_PORT_RIGHT,
3350 EL_SP_GRAVITY_PORT_UP,
3351 EL_SP_GRAVITY_PORT_DOWN,
3352 EL_SP_GRAVITY_ON_PORT_LEFT,
3353 EL_SP_GRAVITY_ON_PORT_RIGHT,
3354 EL_SP_GRAVITY_ON_PORT_UP,
3355 EL_SP_GRAVITY_ON_PORT_DOWN,
3356 EL_SP_GRAVITY_OFF_PORT_LEFT,
3357 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3358 EL_SP_GRAVITY_OFF_PORT_UP,
3359 EL_SP_GRAVITY_OFF_PORT_DOWN,
3364 static int ep_passable_under[] =
3369 static int ep_droppable[] =
3374 static int ep_explodes_1x1_old[] =
3379 static int ep_pushable[] =
3391 EL_SOKOBAN_FIELD_FULL,
3400 static int ep_explodes_cross_old[] =
3405 static int ep_protected[] =
3407 /* same elements as in 'ep_walkable_inside' */
3411 EL_TUBE_VERTICAL_LEFT,
3412 EL_TUBE_VERTICAL_RIGHT,
3413 EL_TUBE_HORIZONTAL_UP,
3414 EL_TUBE_HORIZONTAL_DOWN,
3420 /* same elements as in 'ep_passable_over' */
3429 EL_EM_GATE_1_GRAY_ACTIVE,
3430 EL_EM_GATE_2_GRAY_ACTIVE,
3431 EL_EM_GATE_3_GRAY_ACTIVE,
3432 EL_EM_GATE_4_GRAY_ACTIVE,
3441 EL_EMC_GATE_5_GRAY_ACTIVE,
3442 EL_EMC_GATE_6_GRAY_ACTIVE,
3443 EL_EMC_GATE_7_GRAY_ACTIVE,
3444 EL_EMC_GATE_8_GRAY_ACTIVE,
3446 EL_DC_GATE_WHITE_GRAY,
3447 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3451 /* same elements as in 'ep_passable_inside' */
3456 EL_SP_PORT_HORIZONTAL,
3457 EL_SP_PORT_VERTICAL,
3459 EL_SP_GRAVITY_PORT_LEFT,
3460 EL_SP_GRAVITY_PORT_RIGHT,
3461 EL_SP_GRAVITY_PORT_UP,
3462 EL_SP_GRAVITY_PORT_DOWN,
3463 EL_SP_GRAVITY_ON_PORT_LEFT,
3464 EL_SP_GRAVITY_ON_PORT_RIGHT,
3465 EL_SP_GRAVITY_ON_PORT_UP,
3466 EL_SP_GRAVITY_ON_PORT_DOWN,
3467 EL_SP_GRAVITY_OFF_PORT_LEFT,
3468 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3469 EL_SP_GRAVITY_OFF_PORT_UP,
3470 EL_SP_GRAVITY_OFF_PORT_DOWN,
3475 static int ep_throwable[] =
3480 static int ep_can_explode[] =
3482 /* same elements as in 'ep_explodes_impact' */
3487 /* same elements as in 'ep_explodes_smashed' */
3493 /* elements that can explode by explosion or by dragonfire */
3497 EL_EM_DYNAMITE_ACTIVE,
3498 EL_DYNABOMB_PLAYER_1_ACTIVE,
3499 EL_DYNABOMB_PLAYER_2_ACTIVE,
3500 EL_DYNABOMB_PLAYER_3_ACTIVE,
3501 EL_DYNABOMB_PLAYER_4_ACTIVE,
3502 EL_DYNABOMB_INCREASE_NUMBER,
3503 EL_DYNABOMB_INCREASE_SIZE,
3504 EL_DYNABOMB_INCREASE_POWER,
3505 EL_SP_DISK_RED_ACTIVE,
3513 /* elements that can explode only by explosion */
3519 static int ep_gravity_reachable[] =
3525 EL_INVISIBLE_SAND_ACTIVE,
3530 EL_SP_PORT_HORIZONTAL,
3531 EL_SP_PORT_VERTICAL,
3533 EL_SP_GRAVITY_PORT_LEFT,
3534 EL_SP_GRAVITY_PORT_RIGHT,
3535 EL_SP_GRAVITY_PORT_UP,
3536 EL_SP_GRAVITY_PORT_DOWN,
3537 EL_SP_GRAVITY_ON_PORT_LEFT,
3538 EL_SP_GRAVITY_ON_PORT_RIGHT,
3539 EL_SP_GRAVITY_ON_PORT_UP,
3540 EL_SP_GRAVITY_ON_PORT_DOWN,
3541 EL_SP_GRAVITY_OFF_PORT_LEFT,
3542 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3543 EL_SP_GRAVITY_OFF_PORT_UP,
3544 EL_SP_GRAVITY_OFF_PORT_DOWN,
3550 static int ep_player[] =
3557 EL_SOKOBAN_FIELD_PLAYER,
3563 static int ep_can_pass_magic_wall[] =
3577 static int ep_can_pass_dc_magic_wall[] =
3593 static int ep_switchable[] =
3597 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3598 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3599 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3600 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3601 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3602 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3603 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3604 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3605 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3606 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3607 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3608 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3609 EL_SWITCHGATE_SWITCH_UP,
3610 EL_SWITCHGATE_SWITCH_DOWN,
3611 EL_DC_SWITCHGATE_SWITCH_UP,
3612 EL_DC_SWITCHGATE_SWITCH_DOWN,
3614 EL_LIGHT_SWITCH_ACTIVE,
3616 EL_DC_TIMEGATE_SWITCH,
3617 EL_BALLOON_SWITCH_LEFT,
3618 EL_BALLOON_SWITCH_RIGHT,
3619 EL_BALLOON_SWITCH_UP,
3620 EL_BALLOON_SWITCH_DOWN,
3621 EL_BALLOON_SWITCH_ANY,
3622 EL_BALLOON_SWITCH_NONE,
3625 EL_EMC_MAGIC_BALL_SWITCH,
3626 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3631 static int ep_bd_element[] =
3665 static int ep_sp_element[] =
3667 /* should always be valid */
3670 /* standard classic Supaplex elements */
3677 EL_SP_HARDWARE_GRAY,
3685 EL_SP_GRAVITY_PORT_RIGHT,
3686 EL_SP_GRAVITY_PORT_DOWN,
3687 EL_SP_GRAVITY_PORT_LEFT,
3688 EL_SP_GRAVITY_PORT_UP,
3693 EL_SP_PORT_VERTICAL,
3694 EL_SP_PORT_HORIZONTAL,
3700 EL_SP_HARDWARE_BASE_1,
3701 EL_SP_HARDWARE_GREEN,
3702 EL_SP_HARDWARE_BLUE,
3704 EL_SP_HARDWARE_YELLOW,
3705 EL_SP_HARDWARE_BASE_2,
3706 EL_SP_HARDWARE_BASE_3,
3707 EL_SP_HARDWARE_BASE_4,
3708 EL_SP_HARDWARE_BASE_5,
3709 EL_SP_HARDWARE_BASE_6,
3713 /* additional elements that appeared in newer Supaplex levels */
3716 /* additional gravity port elements (not switching, but setting gravity) */
3717 EL_SP_GRAVITY_ON_PORT_LEFT,
3718 EL_SP_GRAVITY_ON_PORT_RIGHT,
3719 EL_SP_GRAVITY_ON_PORT_UP,
3720 EL_SP_GRAVITY_ON_PORT_DOWN,
3721 EL_SP_GRAVITY_OFF_PORT_LEFT,
3722 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3723 EL_SP_GRAVITY_OFF_PORT_UP,
3724 EL_SP_GRAVITY_OFF_PORT_DOWN,
3726 /* more than one Murphy in a level results in an inactive clone */
3729 /* runtime Supaplex elements */
3730 EL_SP_DISK_RED_ACTIVE,
3731 EL_SP_TERMINAL_ACTIVE,
3732 EL_SP_BUGGY_BASE_ACTIVATING,
3733 EL_SP_BUGGY_BASE_ACTIVE,
3740 static int ep_sb_element[] =
3745 EL_SOKOBAN_FIELD_EMPTY,
3746 EL_SOKOBAN_FIELD_FULL,
3747 EL_SOKOBAN_FIELD_PLAYER,
3752 EL_INVISIBLE_STEELWALL,
3757 static int ep_gem[] =
3769 static int ep_food_dark_yamyam[] =
3797 static int ep_food_penguin[] =
3811 static int ep_food_pig[] =
3823 static int ep_historic_wall[] =
3834 EL_GATE_1_GRAY_ACTIVE,
3835 EL_GATE_2_GRAY_ACTIVE,
3836 EL_GATE_3_GRAY_ACTIVE,
3837 EL_GATE_4_GRAY_ACTIVE,
3846 EL_EM_GATE_1_GRAY_ACTIVE,
3847 EL_EM_GATE_2_GRAY_ACTIVE,
3848 EL_EM_GATE_3_GRAY_ACTIVE,
3849 EL_EM_GATE_4_GRAY_ACTIVE,
3856 EL_EXPANDABLE_WALL_HORIZONTAL,
3857 EL_EXPANDABLE_WALL_VERTICAL,
3858 EL_EXPANDABLE_WALL_ANY,
3859 EL_EXPANDABLE_WALL_GROWING,
3860 EL_BD_EXPANDABLE_WALL,
3867 EL_SP_HARDWARE_GRAY,
3868 EL_SP_HARDWARE_GREEN,
3869 EL_SP_HARDWARE_BLUE,
3871 EL_SP_HARDWARE_YELLOW,
3872 EL_SP_HARDWARE_BASE_1,
3873 EL_SP_HARDWARE_BASE_2,
3874 EL_SP_HARDWARE_BASE_3,
3875 EL_SP_HARDWARE_BASE_4,
3876 EL_SP_HARDWARE_BASE_5,
3877 EL_SP_HARDWARE_BASE_6,
3879 EL_SP_TERMINAL_ACTIVE,
3882 EL_INVISIBLE_STEELWALL,
3883 EL_INVISIBLE_STEELWALL_ACTIVE,
3885 EL_INVISIBLE_WALL_ACTIVE,
3886 EL_STEELWALL_SLIPPERY,
3903 static int ep_historic_solid[] =
3907 EL_EXPANDABLE_WALL_HORIZONTAL,
3908 EL_EXPANDABLE_WALL_VERTICAL,
3909 EL_EXPANDABLE_WALL_ANY,
3910 EL_BD_EXPANDABLE_WALL,
3923 EL_QUICKSAND_FILLING,
3924 EL_QUICKSAND_EMPTYING,
3926 EL_MAGIC_WALL_ACTIVE,
3927 EL_MAGIC_WALL_EMPTYING,
3928 EL_MAGIC_WALL_FILLING,
3932 EL_BD_MAGIC_WALL_ACTIVE,
3933 EL_BD_MAGIC_WALL_EMPTYING,
3934 EL_BD_MAGIC_WALL_FULL,
3935 EL_BD_MAGIC_WALL_FILLING,
3936 EL_BD_MAGIC_WALL_DEAD,
3945 EL_SP_TERMINAL_ACTIVE,
3949 EL_INVISIBLE_WALL_ACTIVE,
3950 EL_SWITCHGATE_SWITCH_UP,
3951 EL_SWITCHGATE_SWITCH_DOWN,
3952 EL_DC_SWITCHGATE_SWITCH_UP,
3953 EL_DC_SWITCHGATE_SWITCH_DOWN,
3955 EL_TIMEGATE_SWITCH_ACTIVE,
3956 EL_DC_TIMEGATE_SWITCH,
3957 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3969 /* the following elements are a direct copy of "indestructible" elements,
3970 except "EL_ACID", which is "indestructible", but not "solid"! */
3975 EL_ACID_POOL_TOPLEFT,
3976 EL_ACID_POOL_TOPRIGHT,
3977 EL_ACID_POOL_BOTTOMLEFT,
3978 EL_ACID_POOL_BOTTOM,
3979 EL_ACID_POOL_BOTTOMRIGHT,
3980 EL_SP_HARDWARE_GRAY,
3981 EL_SP_HARDWARE_GREEN,
3982 EL_SP_HARDWARE_BLUE,
3984 EL_SP_HARDWARE_YELLOW,
3985 EL_SP_HARDWARE_BASE_1,
3986 EL_SP_HARDWARE_BASE_2,
3987 EL_SP_HARDWARE_BASE_3,
3988 EL_SP_HARDWARE_BASE_4,
3989 EL_SP_HARDWARE_BASE_5,
3990 EL_SP_HARDWARE_BASE_6,
3991 EL_INVISIBLE_STEELWALL,
3992 EL_INVISIBLE_STEELWALL_ACTIVE,
3993 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3994 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3995 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3996 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3997 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3998 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3999 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4000 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4001 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4002 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4003 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4004 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4006 EL_LIGHT_SWITCH_ACTIVE,
4007 EL_SIGN_EXCLAMATION,
4008 EL_SIGN_RADIOACTIVITY,
4015 EL_SIGN_ENTRY_FORBIDDEN,
4016 EL_SIGN_EMERGENCY_EXIT,
4024 EL_STEEL_EXIT_CLOSED,
4026 EL_DC_STEELWALL_1_LEFT,
4027 EL_DC_STEELWALL_1_RIGHT,
4028 EL_DC_STEELWALL_1_TOP,
4029 EL_DC_STEELWALL_1_BOTTOM,
4030 EL_DC_STEELWALL_1_HORIZONTAL,
4031 EL_DC_STEELWALL_1_VERTICAL,
4032 EL_DC_STEELWALL_1_TOPLEFT,
4033 EL_DC_STEELWALL_1_TOPRIGHT,
4034 EL_DC_STEELWALL_1_BOTTOMLEFT,
4035 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4036 EL_DC_STEELWALL_1_TOPLEFT_2,
4037 EL_DC_STEELWALL_1_TOPRIGHT_2,
4038 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4039 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4040 EL_DC_STEELWALL_2_LEFT,
4041 EL_DC_STEELWALL_2_RIGHT,
4042 EL_DC_STEELWALL_2_TOP,
4043 EL_DC_STEELWALL_2_BOTTOM,
4044 EL_DC_STEELWALL_2_HORIZONTAL,
4045 EL_DC_STEELWALL_2_VERTICAL,
4046 EL_DC_STEELWALL_2_MIDDLE,
4047 EL_DC_STEELWALL_2_SINGLE,
4048 EL_STEELWALL_SLIPPERY,
4062 EL_GATE_1_GRAY_ACTIVE,
4063 EL_GATE_2_GRAY_ACTIVE,
4064 EL_GATE_3_GRAY_ACTIVE,
4065 EL_GATE_4_GRAY_ACTIVE,
4074 EL_EM_GATE_1_GRAY_ACTIVE,
4075 EL_EM_GATE_2_GRAY_ACTIVE,
4076 EL_EM_GATE_3_GRAY_ACTIVE,
4077 EL_EM_GATE_4_GRAY_ACTIVE,
4079 EL_SWITCHGATE_OPENING,
4080 EL_SWITCHGATE_CLOSED,
4081 EL_SWITCHGATE_CLOSING,
4083 EL_TIMEGATE_OPENING,
4085 EL_TIMEGATE_CLOSING,
4089 EL_TUBE_VERTICAL_LEFT,
4090 EL_TUBE_VERTICAL_RIGHT,
4091 EL_TUBE_HORIZONTAL_UP,
4092 EL_TUBE_HORIZONTAL_DOWN,
4101 static int ep_classic_enemy[] =
4118 static int ep_belt[] =
4120 EL_CONVEYOR_BELT_1_LEFT,
4121 EL_CONVEYOR_BELT_1_MIDDLE,
4122 EL_CONVEYOR_BELT_1_RIGHT,
4123 EL_CONVEYOR_BELT_2_LEFT,
4124 EL_CONVEYOR_BELT_2_MIDDLE,
4125 EL_CONVEYOR_BELT_2_RIGHT,
4126 EL_CONVEYOR_BELT_3_LEFT,
4127 EL_CONVEYOR_BELT_3_MIDDLE,
4128 EL_CONVEYOR_BELT_3_RIGHT,
4129 EL_CONVEYOR_BELT_4_LEFT,
4130 EL_CONVEYOR_BELT_4_MIDDLE,
4131 EL_CONVEYOR_BELT_4_RIGHT,
4136 static int ep_belt_active[] =
4138 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
4139 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
4140 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
4141 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
4142 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
4143 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
4144 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
4145 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
4146 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
4147 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
4148 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
4149 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
4154 static int ep_belt_switch[] =
4156 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4157 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4158 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4159 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4160 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4161 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4162 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4163 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4164 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4165 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4166 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4167 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4172 static int ep_tube[] =
4179 EL_TUBE_HORIZONTAL_UP,
4180 EL_TUBE_HORIZONTAL_DOWN,
4182 EL_TUBE_VERTICAL_LEFT,
4183 EL_TUBE_VERTICAL_RIGHT,
4189 static int ep_acid_pool[] =
4191 EL_ACID_POOL_TOPLEFT,
4192 EL_ACID_POOL_TOPRIGHT,
4193 EL_ACID_POOL_BOTTOMLEFT,
4194 EL_ACID_POOL_BOTTOM,
4195 EL_ACID_POOL_BOTTOMRIGHT,
4200 static int ep_keygate[] =
4210 EL_GATE_1_GRAY_ACTIVE,
4211 EL_GATE_2_GRAY_ACTIVE,
4212 EL_GATE_3_GRAY_ACTIVE,
4213 EL_GATE_4_GRAY_ACTIVE,
4222 EL_EM_GATE_1_GRAY_ACTIVE,
4223 EL_EM_GATE_2_GRAY_ACTIVE,
4224 EL_EM_GATE_3_GRAY_ACTIVE,
4225 EL_EM_GATE_4_GRAY_ACTIVE,
4234 EL_EMC_GATE_5_GRAY_ACTIVE,
4235 EL_EMC_GATE_6_GRAY_ACTIVE,
4236 EL_EMC_GATE_7_GRAY_ACTIVE,
4237 EL_EMC_GATE_8_GRAY_ACTIVE,
4239 EL_DC_GATE_WHITE_GRAY,
4240 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4245 static int ep_amoeboid[] =
4257 static int ep_amoebalive[] =
4268 static int ep_has_editor_content[] =
4274 EL_SOKOBAN_FIELD_PLAYER,
4291 static int ep_can_turn_each_move[] =
4293 /* !!! do something with this one !!! */
4297 static int ep_can_grow[] =
4311 static int ep_active_bomb[] =
4314 EL_EM_DYNAMITE_ACTIVE,
4315 EL_DYNABOMB_PLAYER_1_ACTIVE,
4316 EL_DYNABOMB_PLAYER_2_ACTIVE,
4317 EL_DYNABOMB_PLAYER_3_ACTIVE,
4318 EL_DYNABOMB_PLAYER_4_ACTIVE,
4319 EL_SP_DISK_RED_ACTIVE,
4324 static int ep_inactive[] =
4334 EL_QUICKSAND_FAST_EMPTY,
4357 EL_GATE_1_GRAY_ACTIVE,
4358 EL_GATE_2_GRAY_ACTIVE,
4359 EL_GATE_3_GRAY_ACTIVE,
4360 EL_GATE_4_GRAY_ACTIVE,
4369 EL_EM_GATE_1_GRAY_ACTIVE,
4370 EL_EM_GATE_2_GRAY_ACTIVE,
4371 EL_EM_GATE_3_GRAY_ACTIVE,
4372 EL_EM_GATE_4_GRAY_ACTIVE,
4381 EL_EMC_GATE_5_GRAY_ACTIVE,
4382 EL_EMC_GATE_6_GRAY_ACTIVE,
4383 EL_EMC_GATE_7_GRAY_ACTIVE,
4384 EL_EMC_GATE_8_GRAY_ACTIVE,
4386 EL_DC_GATE_WHITE_GRAY,
4387 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4388 EL_DC_GATE_FAKE_GRAY,
4391 EL_INVISIBLE_STEELWALL,
4399 EL_WALL_EMERALD_YELLOW,
4400 EL_DYNABOMB_INCREASE_NUMBER,
4401 EL_DYNABOMB_INCREASE_SIZE,
4402 EL_DYNABOMB_INCREASE_POWER,
4406 EL_SOKOBAN_FIELD_EMPTY,
4407 EL_SOKOBAN_FIELD_FULL,
4408 EL_WALL_EMERALD_RED,
4409 EL_WALL_EMERALD_PURPLE,
4410 EL_ACID_POOL_TOPLEFT,
4411 EL_ACID_POOL_TOPRIGHT,
4412 EL_ACID_POOL_BOTTOMLEFT,
4413 EL_ACID_POOL_BOTTOM,
4414 EL_ACID_POOL_BOTTOMRIGHT,
4418 EL_BD_MAGIC_WALL_DEAD,
4420 EL_DC_MAGIC_WALL_DEAD,
4421 EL_AMOEBA_TO_DIAMOND,
4429 EL_SP_GRAVITY_PORT_RIGHT,
4430 EL_SP_GRAVITY_PORT_DOWN,
4431 EL_SP_GRAVITY_PORT_LEFT,
4432 EL_SP_GRAVITY_PORT_UP,
4433 EL_SP_PORT_HORIZONTAL,
4434 EL_SP_PORT_VERTICAL,
4445 EL_SP_HARDWARE_GRAY,
4446 EL_SP_HARDWARE_GREEN,
4447 EL_SP_HARDWARE_BLUE,
4449 EL_SP_HARDWARE_YELLOW,
4450 EL_SP_HARDWARE_BASE_1,
4451 EL_SP_HARDWARE_BASE_2,
4452 EL_SP_HARDWARE_BASE_3,
4453 EL_SP_HARDWARE_BASE_4,
4454 EL_SP_HARDWARE_BASE_5,
4455 EL_SP_HARDWARE_BASE_6,
4456 EL_SP_GRAVITY_ON_PORT_LEFT,
4457 EL_SP_GRAVITY_ON_PORT_RIGHT,
4458 EL_SP_GRAVITY_ON_PORT_UP,
4459 EL_SP_GRAVITY_ON_PORT_DOWN,
4460 EL_SP_GRAVITY_OFF_PORT_LEFT,
4461 EL_SP_GRAVITY_OFF_PORT_RIGHT,
4462 EL_SP_GRAVITY_OFF_PORT_UP,
4463 EL_SP_GRAVITY_OFF_PORT_DOWN,
4464 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4465 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4466 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4467 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4468 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4469 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4470 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4471 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4472 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4473 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4474 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4475 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4476 EL_SIGN_EXCLAMATION,
4477 EL_SIGN_RADIOACTIVITY,
4484 EL_SIGN_ENTRY_FORBIDDEN,
4485 EL_SIGN_EMERGENCY_EXIT,
4493 EL_DC_STEELWALL_1_LEFT,
4494 EL_DC_STEELWALL_1_RIGHT,
4495 EL_DC_STEELWALL_1_TOP,
4496 EL_DC_STEELWALL_1_BOTTOM,
4497 EL_DC_STEELWALL_1_HORIZONTAL,
4498 EL_DC_STEELWALL_1_VERTICAL,
4499 EL_DC_STEELWALL_1_TOPLEFT,
4500 EL_DC_STEELWALL_1_TOPRIGHT,
4501 EL_DC_STEELWALL_1_BOTTOMLEFT,
4502 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4503 EL_DC_STEELWALL_1_TOPLEFT_2,
4504 EL_DC_STEELWALL_1_TOPRIGHT_2,
4505 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4506 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4507 EL_DC_STEELWALL_2_LEFT,
4508 EL_DC_STEELWALL_2_RIGHT,
4509 EL_DC_STEELWALL_2_TOP,
4510 EL_DC_STEELWALL_2_BOTTOM,
4511 EL_DC_STEELWALL_2_HORIZONTAL,
4512 EL_DC_STEELWALL_2_VERTICAL,
4513 EL_DC_STEELWALL_2_MIDDLE,
4514 EL_DC_STEELWALL_2_SINGLE,
4515 EL_STEELWALL_SLIPPERY,
4520 EL_EMC_WALL_SLIPPERY_1,
4521 EL_EMC_WALL_SLIPPERY_2,
4522 EL_EMC_WALL_SLIPPERY_3,
4523 EL_EMC_WALL_SLIPPERY_4,
4544 static int ep_em_slippery_wall[] =
4549 static int ep_gfx_crumbled[] =
4560 static int ep_editor_cascade_active[] =
4562 EL_INTERNAL_CASCADE_BD_ACTIVE,
4563 EL_INTERNAL_CASCADE_EM_ACTIVE,
4564 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4565 EL_INTERNAL_CASCADE_RND_ACTIVE,
4566 EL_INTERNAL_CASCADE_SB_ACTIVE,
4567 EL_INTERNAL_CASCADE_SP_ACTIVE,
4568 EL_INTERNAL_CASCADE_DC_ACTIVE,
4569 EL_INTERNAL_CASCADE_DX_ACTIVE,
4570 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4571 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4572 EL_INTERNAL_CASCADE_CE_ACTIVE,
4573 EL_INTERNAL_CASCADE_GE_ACTIVE,
4574 EL_INTERNAL_CASCADE_REF_ACTIVE,
4575 EL_INTERNAL_CASCADE_USER_ACTIVE,
4576 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4581 static int ep_editor_cascade_inactive[] =
4583 EL_INTERNAL_CASCADE_BD,
4584 EL_INTERNAL_CASCADE_EM,
4585 EL_INTERNAL_CASCADE_EMC,
4586 EL_INTERNAL_CASCADE_RND,
4587 EL_INTERNAL_CASCADE_SB,
4588 EL_INTERNAL_CASCADE_SP,
4589 EL_INTERNAL_CASCADE_DC,
4590 EL_INTERNAL_CASCADE_DX,
4591 EL_INTERNAL_CASCADE_CHARS,
4592 EL_INTERNAL_CASCADE_STEEL_CHARS,
4593 EL_INTERNAL_CASCADE_CE,
4594 EL_INTERNAL_CASCADE_GE,
4595 EL_INTERNAL_CASCADE_REF,
4596 EL_INTERNAL_CASCADE_USER,
4597 EL_INTERNAL_CASCADE_DYNAMIC,
4602 static int ep_obsolete[] =
4606 EL_EM_KEY_1_FILE_OBSOLETE,
4607 EL_EM_KEY_2_FILE_OBSOLETE,
4608 EL_EM_KEY_3_FILE_OBSOLETE,
4609 EL_EM_KEY_4_FILE_OBSOLETE,
4610 EL_ENVELOPE_OBSOLETE,
4619 } element_properties[] =
4621 { ep_diggable, EP_DIGGABLE },
4622 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4623 { ep_dont_run_into, EP_DONT_RUN_INTO },
4624 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4625 { ep_dont_touch, EP_DONT_TOUCH },
4626 { ep_indestructible, EP_INDESTRUCTIBLE },
4627 { ep_slippery, EP_SLIPPERY },
4628 { ep_can_change, EP_CAN_CHANGE },
4629 { ep_can_move, EP_CAN_MOVE },
4630 { ep_can_fall, EP_CAN_FALL },
4631 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4632 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4633 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4634 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4635 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4636 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4637 { ep_walkable_over, EP_WALKABLE_OVER },
4638 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4639 { ep_walkable_under, EP_WALKABLE_UNDER },
4640 { ep_passable_over, EP_PASSABLE_OVER },
4641 { ep_passable_inside, EP_PASSABLE_INSIDE },
4642 { ep_passable_under, EP_PASSABLE_UNDER },
4643 { ep_droppable, EP_DROPPABLE },
4644 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4645 { ep_pushable, EP_PUSHABLE },
4646 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4647 { ep_protected, EP_PROTECTED },
4648 { ep_throwable, EP_THROWABLE },
4649 { ep_can_explode, EP_CAN_EXPLODE },
4650 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4652 { ep_player, EP_PLAYER },
4653 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4654 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4655 { ep_switchable, EP_SWITCHABLE },
4656 { ep_bd_element, EP_BD_ELEMENT },
4657 { ep_sp_element, EP_SP_ELEMENT },
4658 { ep_sb_element, EP_SB_ELEMENT },
4660 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4661 { ep_food_penguin, EP_FOOD_PENGUIN },
4662 { ep_food_pig, EP_FOOD_PIG },
4663 { ep_historic_wall, EP_HISTORIC_WALL },
4664 { ep_historic_solid, EP_HISTORIC_SOLID },
4665 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4666 { ep_belt, EP_BELT },
4667 { ep_belt_active, EP_BELT_ACTIVE },
4668 { ep_belt_switch, EP_BELT_SWITCH },
4669 { ep_tube, EP_TUBE },
4670 { ep_acid_pool, EP_ACID_POOL },
4671 { ep_keygate, EP_KEYGATE },
4672 { ep_amoeboid, EP_AMOEBOID },
4673 { ep_amoebalive, EP_AMOEBALIVE },
4674 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4675 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4676 { ep_can_grow, EP_CAN_GROW },
4677 { ep_active_bomb, EP_ACTIVE_BOMB },
4678 { ep_inactive, EP_INACTIVE },
4680 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4682 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4684 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4685 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4687 { ep_obsolete, EP_OBSOLETE },
4694 /* always start with reliable default values (element has no properties) */
4695 /* (but never initialize clipboard elements after the very first time) */
4696 /* (to be able to use clipboard elements between several levels) */
4697 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4698 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4699 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4700 SET_PROPERTY(i, j, FALSE);
4702 /* set all base element properties from above array definitions */
4703 for (i = 0; element_properties[i].elements != NULL; i++)
4704 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4705 SET_PROPERTY((element_properties[i].elements)[j],
4706 element_properties[i].property, TRUE);
4708 /* copy properties to some elements that are only stored in level file */
4709 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4710 for (j = 0; copy_properties[j][0] != -1; j++)
4711 if (HAS_PROPERTY(copy_properties[j][0], i))
4712 for (k = 1; k <= 4; k++)
4713 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4715 /* set static element properties that are not listed in array definitions */
4716 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4717 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4719 clipboard_elements_initialized = TRUE;
4722 void InitElementPropertiesEngine(int engine_version)
4724 static int no_wall_properties[] =
4727 EP_COLLECTIBLE_ONLY,
4729 EP_DONT_COLLIDE_WITH,
4732 EP_CAN_SMASH_PLAYER,
4733 EP_CAN_SMASH_ENEMIES,
4734 EP_CAN_SMASH_EVERYTHING,
4739 EP_FOOD_DARK_YAMYAM,
4755 /* important: after initialization in InitElementPropertiesStatic(), the
4756 elements are not again initialized to a default value; therefore all
4757 changes have to make sure that they leave the element with a defined
4758 property (which means that conditional property changes must be set to
4759 a reliable default value before) */
4761 /* resolve group elements */
4762 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4763 ResolveGroupElement(EL_GROUP_START + i);
4765 /* set all special, combined or engine dependent element properties */
4766 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4768 /* do not change (already initialized) clipboard elements here */
4769 if (IS_CLIPBOARD_ELEMENT(i))
4772 /* ---------- INACTIVE ------------------------------------------------- */
4773 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4774 i <= EL_CHAR_END) ||
4775 (i >= EL_STEEL_CHAR_START &&
4776 i <= EL_STEEL_CHAR_END)));
4778 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4779 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4780 IS_WALKABLE_INSIDE(i) ||
4781 IS_WALKABLE_UNDER(i)));
4783 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4784 IS_PASSABLE_INSIDE(i) ||
4785 IS_PASSABLE_UNDER(i)));
4787 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4788 IS_PASSABLE_OVER(i)));
4790 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4791 IS_PASSABLE_INSIDE(i)));
4793 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4794 IS_PASSABLE_UNDER(i)));
4796 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4799 /* ---------- COLLECTIBLE ---------------------------------------------- */
4800 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4804 /* ---------- SNAPPABLE ------------------------------------------------ */
4805 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4806 IS_COLLECTIBLE(i) ||
4810 /* ---------- WALL ----------------------------------------------------- */
4811 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4813 for (j = 0; no_wall_properties[j] != -1; j++)
4814 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4815 i >= EL_FIRST_RUNTIME_UNREAL)
4816 SET_PROPERTY(i, EP_WALL, FALSE);
4818 if (IS_HISTORIC_WALL(i))
4819 SET_PROPERTY(i, EP_WALL, TRUE);
4821 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4822 if (engine_version < VERSION_IDENT(2,2,0,0))
4823 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4825 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4827 !IS_COLLECTIBLE(i)));
4829 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4830 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4831 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4833 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4834 IS_INDESTRUCTIBLE(i)));
4836 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4838 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4839 else if (engine_version < VERSION_IDENT(2,2,0,0))
4840 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4842 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4846 if (IS_CUSTOM_ELEMENT(i))
4848 /* these are additional properties which are initially false when set */
4850 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4852 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4853 if (DONT_COLLIDE_WITH(i))
4854 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4856 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4857 if (CAN_SMASH_EVERYTHING(i))
4858 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4859 if (CAN_SMASH_ENEMIES(i))
4860 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4863 /* ---------- CAN_SMASH ------------------------------------------------ */
4864 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4865 CAN_SMASH_ENEMIES(i) ||
4866 CAN_SMASH_EVERYTHING(i)));
4868 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4869 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4870 EXPLODES_BY_FIRE(i)));
4872 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4873 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4874 EXPLODES_SMASHED(i)));
4876 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4877 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4878 EXPLODES_IMPACT(i)));
4880 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4881 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4883 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4884 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4885 i == EL_BLACK_ORB));
4887 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4888 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4890 IS_CUSTOM_ELEMENT(i)));
4892 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4893 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4894 i == EL_SP_ELECTRON));
4896 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4897 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4898 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4899 getMoveIntoAcidProperty(&level, i));
4901 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4902 if (MAYBE_DONT_COLLIDE_WITH(i))
4903 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4904 getDontCollideWithProperty(&level, i));
4906 /* ---------- SP_PORT -------------------------------------------------- */
4907 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4908 IS_PASSABLE_INSIDE(i)));
4910 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4911 for (j = 0; j < level.num_android_clone_elements; j++)
4912 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4914 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4916 /* ---------- CAN_CHANGE ----------------------------------------------- */
4917 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4918 for (j = 0; j < element_info[i].num_change_pages; j++)
4919 if (element_info[i].change_page[j].can_change)
4920 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4922 /* ---------- HAS_ACTION ----------------------------------------------- */
4923 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4924 for (j = 0; j < element_info[i].num_change_pages; j++)
4925 if (element_info[i].change_page[j].has_action)
4926 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4928 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4929 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4932 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4934 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4935 element_info[i].crumbled[ACTION_DEFAULT] !=
4936 element_info[i].graphic[ACTION_DEFAULT]);
4938 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
4939 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4940 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
4943 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4944 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4945 IS_EDITOR_CASCADE_INACTIVE(i)));
4948 /* dynamically adjust element properties according to game engine version */
4950 static int ep_em_slippery_wall[] =
4955 EL_EXPANDABLE_WALL_HORIZONTAL,
4956 EL_EXPANDABLE_WALL_VERTICAL,
4957 EL_EXPANDABLE_WALL_ANY,
4958 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4959 EL_EXPANDABLE_STEELWALL_VERTICAL,
4960 EL_EXPANDABLE_STEELWALL_ANY,
4961 EL_EXPANDABLE_STEELWALL_GROWING,
4965 static int ep_em_explodes_by_fire[] =
4968 EL_EM_DYNAMITE_ACTIVE,
4973 /* special EM style gems behaviour */
4974 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4975 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4976 level.em_slippery_gems);
4978 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4979 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4980 (level.em_slippery_gems &&
4981 engine_version > VERSION_IDENT(2,0,1,0)));
4983 /* special EM style explosion behaviour regarding chain reactions */
4984 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4985 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4986 level.em_explodes_by_fire);
4989 /* this is needed because some graphics depend on element properties */
4990 if (game_status == GAME_MODE_PLAYING)
4991 InitElementGraphicInfo();
4994 void InitElementPropertiesAfterLoading(int engine_version)
4998 /* set some other uninitialized values of custom elements in older levels */
4999 if (engine_version < VERSION_IDENT(3,1,0,0))
5001 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
5003 int element = EL_CUSTOM_START + i;
5005 element_info[element].access_direction = MV_ALL_DIRECTIONS;
5007 element_info[element].explosion_delay = 17;
5008 element_info[element].ignition_delay = 8;
5013 void InitElementPropertiesGfxElement()
5017 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5019 struct ElementInfo *ei = &element_info[i];
5021 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
5025 static void InitGlobal()
5030 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
5032 /* check if element_name_info entry defined for each element in "main.h" */
5033 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
5034 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
5036 element_info[i].token_name = element_name_info[i].token_name;
5037 element_info[i].class_name = element_name_info[i].class_name;
5038 element_info[i].editor_description= element_name_info[i].editor_description;
5041 printf("%04d: %s\n", i, element_name_info[i].token_name);
5045 /* create hash from image config list */
5046 image_config_hash = newSetupFileHash();
5047 for (i = 0; image_config[i].token != NULL; i++)
5048 setHashEntry(image_config_hash,
5049 image_config[i].token,
5050 image_config[i].value);
5052 /* create hash from element token list */
5053 element_token_hash = newSetupFileHash();
5054 for (i = 0; element_name_info[i].token_name != NULL; i++)
5055 setHashEntry(element_token_hash,
5056 element_name_info[i].token_name,
5059 /* create hash from graphic token list */
5060 graphic_token_hash = newSetupFileHash();
5061 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
5062 if (strSuffix(image_config[i].value, ".pcx") ||
5063 strSuffix(image_config[i].value, ".wav") ||
5064 strEqual(image_config[i].value, UNDEFINED_FILENAME))
5065 setHashEntry(graphic_token_hash,
5066 image_config[i].token,
5067 int2str(graphic++, 0));
5069 /* create hash from font token list */
5070 font_token_hash = newSetupFileHash();
5071 for (i = 0; font_info[i].token_name != NULL; i++)
5072 setHashEntry(font_token_hash,
5073 font_info[i].token_name,
5076 /* always start with reliable default values (all elements) */
5077 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5078 ActiveElement[i] = i;
5080 /* now add all entries that have an active state (active elements) */
5081 for (i = 0; element_with_active_state[i].element != -1; i++)
5083 int element = element_with_active_state[i].element;
5084 int element_active = element_with_active_state[i].element_active;
5086 ActiveElement[element] = element_active;
5089 /* always start with reliable default values (all buttons) */
5090 for (i = 0; i < NUM_IMAGE_FILES; i++)
5091 ActiveButton[i] = i;
5093 /* now add all entries that have an active state (active buttons) */
5094 for (i = 0; button_with_active_state[i].button != -1; i++)
5096 int button = button_with_active_state[i].button;
5097 int button_active = button_with_active_state[i].button_active;
5099 ActiveButton[button] = button_active;
5102 /* always start with reliable default values (all fonts) */
5103 for (i = 0; i < NUM_FONTS; i++)
5106 /* now add all entries that have an active state (active fonts) */
5107 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
5109 int font = font_with_active_state[i].font_nr;
5110 int font_active = font_with_active_state[i].font_nr_active;
5112 ActiveFont[font] = font_active;
5115 global.autoplay_leveldir = NULL;
5116 global.convert_leveldir = NULL;
5117 global.create_images_dir = NULL;
5119 global.frames_per_second = 0;
5120 global.fps_slowdown = FALSE;
5121 global.fps_slowdown_factor = 1;
5123 global.border_status = GAME_MODE_MAIN;
5125 global.fading_status = GAME_MODE_MAIN;
5126 global.fading_type = TYPE_ENTER_MENU;
5129 global.use_envelope_request = FALSE; /* !!! MOVE TO ARTWORK CONFIG !!! */
5132 void Execute_Command(char *command)
5136 if (strEqual(command, "print graphicsinfo.conf"))
5138 printf("# You can configure additional/alternative image files here.\n");
5139 printf("# (The entries below are default and therefore commented out.)\n");
5141 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
5143 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5146 for (i = 0; image_config[i].token != NULL; i++)
5147 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
5148 image_config[i].value));
5152 else if (strEqual(command, "print soundsinfo.conf"))
5154 printf("# You can configure additional/alternative sound files here.\n");
5155 printf("# (The entries below are default and therefore commented out.)\n");
5157 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
5159 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5162 for (i = 0; sound_config[i].token != NULL; i++)
5163 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
5164 sound_config[i].value));
5168 else if (strEqual(command, "print musicinfo.conf"))
5170 printf("# You can configure additional/alternative music files here.\n");
5171 printf("# (The entries below are default and therefore commented out.)\n");
5173 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
5175 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5178 for (i = 0; music_config[i].token != NULL; i++)
5179 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
5180 music_config[i].value));
5184 else if (strEqual(command, "print editorsetup.conf"))
5186 printf("# You can configure your personal editor element list here.\n");
5187 printf("# (The entries below are default and therefore commented out.)\n");
5190 /* this is needed to be able to check element list for cascade elements */
5191 InitElementPropertiesStatic();
5192 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5194 PrintEditorElementList();
5198 else if (strEqual(command, "print helpanim.conf"))
5200 printf("# You can configure different element help animations here.\n");
5201 printf("# (The entries below are default and therefore commented out.)\n");
5204 for (i = 0; helpanim_config[i].token != NULL; i++)
5206 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
5207 helpanim_config[i].value));
5209 if (strEqual(helpanim_config[i].token, "end"))
5215 else if (strEqual(command, "print helptext.conf"))
5217 printf("# You can configure different element help text here.\n");
5218 printf("# (The entries below are default and therefore commented out.)\n");
5221 for (i = 0; helptext_config[i].token != NULL; i++)
5222 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
5223 helptext_config[i].value));
5227 else if (strPrefix(command, "dump level "))
5229 char *filename = &command[11];
5231 if (!fileExists(filename))
5232 Error(ERR_EXIT, "cannot open file '%s'", filename);
5234 LoadLevelFromFilename(&level, filename);
5239 else if (strPrefix(command, "dump tape "))
5241 char *filename = &command[10];
5243 if (!fileExists(filename))
5244 Error(ERR_EXIT, "cannot open file '%s'", filename);
5246 LoadTapeFromFilename(filename);
5251 else if (strPrefix(command, "autoplay "))
5253 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
5255 while (*str_ptr != '\0') /* continue parsing string */
5257 /* cut leading whitespace from string, replace it by string terminator */
5258 while (*str_ptr == ' ' || *str_ptr == '\t')
5261 if (*str_ptr == '\0') /* end of string reached */
5264 if (global.autoplay_leveldir == NULL) /* read level set string */
5266 global.autoplay_leveldir = str_ptr;
5267 global.autoplay_all = TRUE; /* default: play all tapes */
5269 for (i = 0; i < MAX_TAPES_PER_SET; i++)
5270 global.autoplay_level[i] = FALSE;
5272 else /* read level number string */
5274 int level_nr = atoi(str_ptr); /* get level_nr value */
5276 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5277 global.autoplay_level[level_nr] = TRUE;
5279 global.autoplay_all = FALSE;
5282 /* advance string pointer to the next whitespace (or end of string) */
5283 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5287 else if (strPrefix(command, "convert "))
5289 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
5290 char *str_ptr = strchr(str_copy, ' ');
5292 global.convert_leveldir = str_copy;
5293 global.convert_level_nr = -1;
5295 if (str_ptr != NULL) /* level number follows */
5297 *str_ptr++ = '\0'; /* terminate leveldir string */
5298 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
5301 else if (strPrefix(command, "create images "))
5303 #if defined(TARGET_SDL)
5304 global.create_images_dir = getStringCopy(&command[14]);
5306 if (access(global.create_images_dir, W_OK) != 0)
5307 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
5308 global.create_images_dir);
5310 Error(ERR_EXIT, "command only available for SDL target");
5315 #if defined(TARGET_SDL)
5316 else if (strEqual(command, "SDL_ListModes"))
5321 SDL_Init(SDL_INIT_VIDEO);
5323 /* get available fullscreen/hardware modes */
5324 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
5326 /* check if there are any modes available */
5329 printf("No modes available!\n");
5334 /* check if our resolution is restricted */
5335 if (modes == (SDL_Rect **)-1)
5337 printf("All resolutions available.\n");
5341 printf("Available Modes:\n");
5343 for(i = 0; modes[i]; i++)
5344 printf(" %d x %d\n", modes[i]->w, modes[i]->h);
5354 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
5358 static void InitSetup()
5360 LoadSetup(); /* global setup info */
5362 /* set some options from setup file */
5364 if (setup.options.verbose)
5365 options.verbose = TRUE;
5368 static void InitGameInfo()
5370 game.restart_level = FALSE;
5373 static void InitPlayerInfo()
5377 /* choose default local player */
5378 local_player = &stored_player[0];
5380 for (i = 0; i < MAX_PLAYERS; i++)
5381 stored_player[i].connected = FALSE;
5383 local_player->connected = TRUE;
5386 static void InitArtworkInfo()
5391 static char *get_string_in_brackets(char *string)
5393 char *string_in_brackets = checked_malloc(strlen(string) + 3);
5395 sprintf(string_in_brackets, "[%s]", string);
5397 return string_in_brackets;
5400 static char *get_level_id_suffix(int id_nr)
5402 char *id_suffix = checked_malloc(1 + 3 + 1);
5404 if (id_nr < 0 || id_nr > 999)
5407 sprintf(id_suffix, ".%03d", id_nr);
5413 static char *get_element_class_token(int element)
5415 char *element_class_name = element_info[element].class_name;
5416 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
5418 sprintf(element_class_token, "[%s]", element_class_name);
5420 return element_class_token;
5423 static char *get_action_class_token(int action)
5425 char *action_class_name = &element_action_info[action].suffix[1];
5426 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
5428 sprintf(action_class_token, "[%s]", action_class_name);
5430 return action_class_token;
5434 static void InitArtworkConfig()
5436 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
5437 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
5438 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
5439 static char *action_id_suffix[NUM_ACTIONS + 1];
5440 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5441 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5442 static char *level_id_suffix[MAX_LEVELS + 1];
5443 static char *dummy[1] = { NULL };
5444 static char *ignore_generic_tokens[] =
5450 static char **ignore_image_tokens;
5451 static char **ignore_sound_tokens;
5452 static char **ignore_music_tokens;
5453 int num_ignore_generic_tokens;
5454 int num_ignore_image_tokens;
5455 int num_ignore_sound_tokens;
5456 int num_ignore_music_tokens;
5459 /* dynamically determine list of generic tokens to be ignored */
5460 num_ignore_generic_tokens = 0;
5461 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5462 num_ignore_generic_tokens++;
5464 /* dynamically determine list of image tokens to be ignored */
5465 num_ignore_image_tokens = num_ignore_generic_tokens;
5466 for (i = 0; image_config_vars[i].token != NULL; i++)
5467 num_ignore_image_tokens++;
5468 ignore_image_tokens =
5469 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5470 for (i = 0; i < num_ignore_generic_tokens; i++)
5471 ignore_image_tokens[i] = ignore_generic_tokens[i];
5472 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5473 ignore_image_tokens[num_ignore_generic_tokens + i] =
5474 image_config_vars[i].token;
5475 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5477 /* dynamically determine list of sound tokens to be ignored */
5478 num_ignore_sound_tokens = num_ignore_generic_tokens;
5479 ignore_sound_tokens =
5480 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5481 for (i = 0; i < num_ignore_generic_tokens; i++)
5482 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5483 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5485 /* dynamically determine list of music tokens to be ignored */
5486 num_ignore_music_tokens = num_ignore_generic_tokens;
5487 ignore_music_tokens =
5488 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5489 for (i = 0; i < num_ignore_generic_tokens; i++)
5490 ignore_music_tokens[i] = ignore_generic_tokens[i];
5491 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5493 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5494 image_id_prefix[i] = element_info[i].token_name;
5495 for (i = 0; i < NUM_FONTS; i++)
5496 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5497 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
5499 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5500 sound_id_prefix[i] = element_info[i].token_name;
5501 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5502 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5503 get_string_in_brackets(element_info[i].class_name);
5504 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
5506 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5507 music_id_prefix[i] = music_prefix_info[i].prefix;
5508 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
5510 for (i = 0; i < NUM_ACTIONS; i++)
5511 action_id_suffix[i] = element_action_info[i].suffix;
5512 action_id_suffix[NUM_ACTIONS] = NULL;
5514 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5515 direction_id_suffix[i] = element_direction_info[i].suffix;
5516 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5518 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5519 special_id_suffix[i] = special_suffix_info[i].suffix;
5520 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5522 for (i = 0; i < MAX_LEVELS; i++)
5523 level_id_suffix[i] = get_level_id_suffix(i);
5524 level_id_suffix[MAX_LEVELS] = NULL;
5526 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5527 image_id_prefix, action_id_suffix, direction_id_suffix,
5528 special_id_suffix, ignore_image_tokens);
5529 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5530 sound_id_prefix, action_id_suffix, dummy,
5531 special_id_suffix, ignore_sound_tokens);
5532 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5533 music_id_prefix, special_id_suffix, level_id_suffix,
5534 dummy, ignore_music_tokens);
5537 static void InitMixer()
5544 void InitGfxBuffers()
5546 ReCreateBitmap(&bitmap_db_store, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5547 ReCreateBitmap(&bitmap_db_cross, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5548 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE, DEFAULT_DEPTH);
5549 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE, DEFAULT_DEPTH);
5550 ReCreateBitmap(&bitmap_db_door, 3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
5551 ReCreateBitmap(&bitmap_db_toons, FULL_SXSIZE, FULL_SYSIZE, DEFAULT_DEPTH);
5553 /* initialize screen properties */
5554 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5555 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5557 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5558 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5559 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5560 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5561 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5563 InitGfxBuffers_EM();
5564 InitGfxBuffers_SP();
5569 struct GraphicInfo *graphic_info_last = graphic_info;
5570 char *filename_font_initial = NULL;
5571 char *filename_anim_initial = NULL;
5572 Bitmap *bitmap_font_initial = NULL;
5576 /* determine settings for initial font (for displaying startup messages) */
5577 for (i = 0; image_config[i].token != NULL; i++)
5579 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5581 char font_token[128];
5584 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5585 len_font_token = strlen(font_token);
5587 if (strEqual(image_config[i].token, font_token))
5588 filename_font_initial = image_config[i].value;
5589 else if (strlen(image_config[i].token) > len_font_token &&
5590 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5592 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5593 font_initial[j].src_x = atoi(image_config[i].value);
5594 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5595 font_initial[j].src_y = atoi(image_config[i].value);
5596 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5597 font_initial[j].width = atoi(image_config[i].value);
5598 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5599 font_initial[j].height = atoi(image_config[i].value);
5604 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5606 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5607 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5610 if (filename_font_initial == NULL) /* should not happen */
5611 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5616 /* create additional image buffers for double-buffering and cross-fading */
5617 bitmap_db_store = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5618 bitmap_db_cross = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5619 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
5620 bitmap_db_panel = CreateBitmap(DXSIZE, DYSIZE, DEFAULT_DEPTH);
5621 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
5622 bitmap_db_toons = CreateBitmap(FULL_SXSIZE, FULL_SYSIZE, DEFAULT_DEPTH);
5624 /* initialize screen properties */
5625 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5626 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5628 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5629 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5630 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5631 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5634 InitGfxCustomArtworkInfo();
5636 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5638 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5639 font_initial[j].bitmap = bitmap_font_initial;
5641 InitFontGraphicInfo();
5643 font_height = getFontHeight(FC_RED);
5646 DrawInitText(getWindowTitleString(), 20, FC_YELLOW);
5648 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
5650 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
5651 DrawInitText(PROGRAM_WEBSITE_STRING, WIN_YSIZE - 20 - font_height, FC_RED);
5653 DrawInitText("Loading graphics", 120, FC_GREEN);
5657 /* initialize busy animation with default values */
5658 int parameter[NUM_GFX_ARGS];
5659 for (i = 0; i < NUM_GFX_ARGS; i++)
5660 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5661 image_config_suffix[i].token,
5662 image_config_suffix[i].type);
5664 for (i = 0; i < NUM_GFX_ARGS; i++)
5665 printf("::: '%s' => %d\n", image_config_suffix[i].token, parameter[i]);
5669 /* determine settings for busy animation (when displaying startup messages) */
5670 for (i = 0; image_config[i].token != NULL; i++)
5672 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5673 int len_anim_token = strlen(anim_token);
5675 if (strEqual(image_config[i].token, anim_token))
5676 filename_anim_initial = image_config[i].value;
5677 else if (strlen(image_config[i].token) > len_anim_token &&
5678 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5681 for (j = 0; image_config_suffix[j].token != NULL; j++)
5683 if (strEqual(&image_config[i].token[len_anim_token],
5684 image_config_suffix[j].token))
5686 get_graphic_parameter_value(image_config[i].value,
5687 image_config_suffix[j].token,
5688 image_config_suffix[j].type);
5691 if (strEqual(&image_config[i].token[len_anim_token], ".x"))
5692 anim_initial.src_x = atoi(image_config[i].value);
5693 else if (strEqual(&image_config[i].token[len_anim_token], ".y"))
5694 anim_initial.src_y = atoi(image_config[i].value);
5695 else if (strEqual(&image_config[i].token[len_anim_token], ".width"))
5696 anim_initial.width = atoi(image_config[i].value);
5697 else if (strEqual(&image_config[i].token[len_anim_token], ".height"))
5698 anim_initial.height = atoi(image_config[i].value);
5699 else if (strEqual(&image_config[i].token[len_anim_token], ".frames"))
5700 anim_initial.anim_frames = atoi(image_config[i].value);
5701 else if (strEqual(&image_config[i].token[len_anim_token],
5702 ".frames_per_line"))
5703 anim_initial.anim_frames_per_line = atoi(image_config[i].value);
5704 else if (strEqual(&image_config[i].token[len_anim_token], ".delay"))
5705 anim_initial.anim_delay = atoi(image_config[i].value);
5710 #if defined(CREATE_SPECIAL_EDITION_RND_JUE)
5711 filename_anim_initial = "loading.pcx";
5713 parameter[GFX_ARG_X] = 0;
5714 parameter[GFX_ARG_Y] = 0;
5715 parameter[GFX_ARG_WIDTH] = 128;
5716 parameter[GFX_ARG_HEIGHT] = 40;
5717 parameter[GFX_ARG_FRAMES] = 32;
5718 parameter[GFX_ARG_DELAY] = 4;
5719 parameter[GFX_ARG_FRAMES_PER_LINE] = ARG_UNDEFINED_VALUE;
5722 if (filename_anim_initial == NULL) /* should not happen */
5723 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5725 anim_initial.bitmap = LoadCustomImage(filename_anim_initial);
5727 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
5729 set_graphic_parameters_ext(0, parameter, anim_initial.bitmap);
5732 printf("::: INIT_GFX: anim_frames_per_line == %d [%d / %d] [%d, %d]\n",
5733 graphic_info[0].anim_frames_per_line,
5734 get_scaled_graphic_width(0),
5735 graphic_info[0].width,
5736 getOriginalImageWidthFromImageID(0),
5737 graphic_info[0].scale_up_factor);
5740 graphic_info = graphic_info_last;
5742 init.busy.width = anim_initial.width;
5743 init.busy.height = anim_initial.height;
5745 InitMenuDesignSettings_Static();
5746 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5748 /* use copy of busy animation to prevent change while reloading artwork */
5753 void RedrawBackground()
5755 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
5756 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
5758 redraw_mask = REDRAW_ALL;
5761 void InitGfxBackground()
5765 fieldbuffer = bitmap_db_field;
5766 SetDrawtoField(DRAW_BACKBUFFER);
5769 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5773 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
5774 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
5777 for (x = 0; x < MAX_BUF_XSIZE; x++)
5778 for (y = 0; y < MAX_BUF_YSIZE; y++)
5781 redraw_mask = REDRAW_ALL;
5784 static void InitLevelInfo()
5786 LoadLevelInfo(); /* global level info */
5787 LoadLevelSetup_LastSeries(); /* last played series info */
5788 LoadLevelSetup_SeriesInfo(); /* last played level info */
5791 static void InitLevelArtworkInfo()
5793 LoadLevelArtworkInfo();
5796 static void InitImages()
5798 print_timestamp_init("InitImages");
5801 printf("::: leveldir_current->identifier == '%s'\n",
5802 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5803 printf("::: leveldir_current->graphics_path == '%s'\n",
5804 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5805 printf("::: leveldir_current->graphics_set == '%s'\n",
5806 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5807 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5808 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5811 setLevelArtworkDir(artwork.gfx_first);
5814 printf("::: leveldir_current->identifier == '%s'\n",
5815 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5816 printf("::: leveldir_current->graphics_path == '%s'\n",
5817 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5818 printf("::: leveldir_current->graphics_set == '%s'\n",
5819 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5820 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5821 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5825 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5826 leveldir_current->identifier,
5827 artwork.gfx_current_identifier,
5828 artwork.gfx_current->identifier,
5829 leveldir_current->graphics_set,
5830 leveldir_current->graphics_path);
5833 UPDATE_BUSY_STATE();
5835 ReloadCustomImages();
5836 print_timestamp_time("ReloadCustomImages");
5838 UPDATE_BUSY_STATE();
5840 LoadCustomElementDescriptions();
5841 print_timestamp_time("LoadCustomElementDescriptions");
5843 UPDATE_BUSY_STATE();
5845 LoadMenuDesignSettings();
5846 print_timestamp_time("LoadMenuDesignSettings");
5848 UPDATE_BUSY_STATE();
5850 ReinitializeGraphics();
5851 print_timestamp_time("ReinitializeGraphics");
5853 UPDATE_BUSY_STATE();
5855 print_timestamp_done("InitImages");
5858 static void InitSound(char *identifier)
5860 print_timestamp_init("InitSound");
5862 if (identifier == NULL)
5863 identifier = artwork.snd_current->identifier;
5865 /* set artwork path to send it to the sound server process */
5866 setLevelArtworkDir(artwork.snd_first);
5868 InitReloadCustomSounds(identifier);
5869 print_timestamp_time("InitReloadCustomSounds");
5871 ReinitializeSounds();
5872 print_timestamp_time("ReinitializeSounds");
5874 print_timestamp_done("InitSound");
5877 static void InitMusic(char *identifier)
5879 print_timestamp_init("InitMusic");
5881 if (identifier == NULL)
5882 identifier = artwork.mus_current->identifier;
5884 /* set artwork path to send it to the sound server process */
5885 setLevelArtworkDir(artwork.mus_first);
5887 InitReloadCustomMusic(identifier);
5888 print_timestamp_time("InitReloadCustomMusic");
5890 ReinitializeMusic();
5891 print_timestamp_time("ReinitializeMusic");
5893 print_timestamp_done("InitMusic");
5896 void InitNetworkServer()
5898 #if defined(NETWORK_AVALIABLE)
5902 if (!options.network)
5905 #if defined(NETWORK_AVALIABLE)
5906 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5908 if (!ConnectToServer(options.server_host, options.server_port))
5909 Error(ERR_EXIT, "cannot connect to network game server");
5911 SendToServer_PlayerName(setup.player_name);
5912 SendToServer_ProtocolVersion();
5915 SendToServer_NrWanted(nr_wanted);
5919 static boolean CheckArtworkConfigForCustomElements(char *filename)
5921 SetupFileHash *setup_file_hash;
5922 boolean redefined_ce_found = FALSE;
5924 /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */
5926 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5928 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5930 char *token = HASH_ITERATION_TOKEN(itr);
5932 if (strPrefix(token, "custom_"))
5934 redefined_ce_found = TRUE;
5939 END_HASH_ITERATION(setup_file_hash, itr)
5941 freeSetupFileHash(setup_file_hash);
5944 return redefined_ce_found;
5947 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5949 char *filename_base, *filename_local;
5950 boolean redefined_ce_found = FALSE;
5952 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5955 printf("::: leveldir_current->identifier == '%s'\n",
5956 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5957 printf("::: leveldir_current->graphics_path == '%s'\n",
5958 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5959 printf("::: leveldir_current->graphics_set == '%s'\n",
5960 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5961 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5962 leveldir_current == NULL ? "[NULL]" :
5963 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5966 /* first look for special artwork configured in level series config */
5967 filename_base = getCustomArtworkLevelConfigFilename(type);
5970 printf("::: filename_base == '%s'\n", filename_base);
5973 if (fileExists(filename_base))
5974 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5976 filename_local = getCustomArtworkConfigFilename(type);
5979 printf("::: filename_local == '%s'\n", filename_local);
5982 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5983 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5986 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5989 return redefined_ce_found;
5992 static void InitOverrideArtwork()
5994 boolean redefined_ce_found = FALSE;
5996 /* to check if this level set redefines any CEs, do not use overriding */
5997 gfx.override_level_graphics = FALSE;
5998 gfx.override_level_sounds = FALSE;
5999 gfx.override_level_music = FALSE;
6001 /* now check if this level set has definitions for custom elements */
6002 if (setup.override_level_graphics == AUTO ||
6003 setup.override_level_sounds == AUTO ||
6004 setup.override_level_music == AUTO)
6005 redefined_ce_found =
6006 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
6007 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
6008 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
6011 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
6014 if (redefined_ce_found)
6016 /* this level set has CE definitions: change "AUTO" to "FALSE" */
6017 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
6018 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
6019 gfx.override_level_music = (setup.override_level_music == TRUE);
6023 /* this level set has no CE definitions: change "AUTO" to "TRUE" */
6024 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
6025 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
6026 gfx.override_level_music = (setup.override_level_music != FALSE);
6030 printf("::: => %d, %d, %d\n",
6031 gfx.override_level_graphics,
6032 gfx.override_level_sounds,
6033 gfx.override_level_music);
6037 static char *getNewArtworkIdentifier(int type)
6039 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
6040 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
6041 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
6042 static boolean initialized[3] = { FALSE, FALSE, FALSE };
6043 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
6045 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
6047 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
6049 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
6050 char *leveldir_identifier = leveldir_current->identifier;
6052 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
6053 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
6055 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
6057 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
6058 char *artwork_current_identifier;
6059 char *artwork_new_identifier = NULL; /* default: nothing has changed */
6061 /* leveldir_current may be invalid (level group, parent link) */
6062 if (!validLevelSeries(leveldir_current))
6065 /* 1st step: determine artwork set to be activated in descending order:
6066 --------------------------------------------------------------------
6067 1. setup artwork (when configured to override everything else)
6068 2. artwork set configured in "levelinfo.conf" of current level set
6069 (artwork in level directory will have priority when loading later)
6070 3. artwork in level directory (stored in artwork sub-directory)
6071 4. setup artwork (currently configured in setup menu) */
6073 if (setup_override_artwork)
6074 artwork_current_identifier = setup_artwork_set;
6075 else if (leveldir_artwork_set != NULL)
6076 artwork_current_identifier = leveldir_artwork_set;
6077 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
6078 artwork_current_identifier = leveldir_identifier;
6080 artwork_current_identifier = setup_artwork_set;
6083 /* 2nd step: check if it is really needed to reload artwork set
6084 ------------------------------------------------------------ */
6087 if (type == ARTWORK_TYPE_GRAPHICS)
6088 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
6089 artwork_new_identifier,
6090 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
6091 artwork_current_identifier,
6092 leveldir_current->graphics_set,
6093 leveldir_current->identifier);
6096 /* ---------- reload if level set and also artwork set has changed ------- */
6097 if (leveldir_current_identifier[type] != leveldir_identifier &&
6098 (last_has_level_artwork_set[type] || has_level_artwork_set))
6099 artwork_new_identifier = artwork_current_identifier;
6101 leveldir_current_identifier[type] = leveldir_identifier;
6102 last_has_level_artwork_set[type] = has_level_artwork_set;
6105 if (type == ARTWORK_TYPE_GRAPHICS)
6106 printf("::: 1: '%s'\n", artwork_new_identifier);
6109 /* ---------- reload if "override artwork" setting has changed ----------- */
6110 if (last_override_level_artwork[type] != setup_override_artwork)
6111 artwork_new_identifier = artwork_current_identifier;
6113 last_override_level_artwork[type] = setup_override_artwork;
6116 if (type == ARTWORK_TYPE_GRAPHICS)
6117 printf("::: 2: '%s'\n", artwork_new_identifier);
6120 /* ---------- reload if current artwork identifier has changed ----------- */
6121 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
6122 artwork_current_identifier))
6123 artwork_new_identifier = artwork_current_identifier;
6125 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
6128 if (type == ARTWORK_TYPE_GRAPHICS)
6129 printf("::: 3: '%s'\n", artwork_new_identifier);
6132 /* ---------- do not reload directly after starting ---------------------- */
6133 if (!initialized[type])
6134 artwork_new_identifier = NULL;
6136 initialized[type] = TRUE;
6139 if (type == ARTWORK_TYPE_GRAPHICS)
6140 printf("::: 4: '%s'\n", artwork_new_identifier);
6144 if (type == ARTWORK_TYPE_GRAPHICS)
6145 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
6146 artwork.gfx_current_identifier, artwork_current_identifier,
6147 artwork.gfx_current->identifier, leveldir_current->graphics_set,
6148 artwork_new_identifier);
6151 return artwork_new_identifier;
6154 void ReloadCustomArtwork(int force_reload)
6156 int last_game_status = game_status; /* save current game status */
6157 char *gfx_new_identifier;
6158 char *snd_new_identifier;
6159 char *mus_new_identifier;
6160 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
6161 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
6162 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
6163 boolean reload_needed;
6165 InitOverrideArtwork();
6167 force_reload_gfx |= AdjustGraphicsForEMC();
6169 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
6170 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
6171 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
6173 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
6174 snd_new_identifier != NULL || force_reload_snd ||
6175 mus_new_identifier != NULL || force_reload_mus);
6180 print_timestamp_init("ReloadCustomArtwork");
6182 game_status = GAME_MODE_LOADING;
6184 FadeOut(REDRAW_ALL);
6187 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6189 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
6191 print_timestamp_time("ClearRectangle");
6194 printf("::: fading in ... %d\n", fading.fade_mode);
6198 printf("::: done\n");
6201 if (gfx_new_identifier != NULL || force_reload_gfx)
6204 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
6205 artwork.gfx_current_identifier,
6207 artwork.gfx_current->identifier,
6208 leveldir_current->graphics_set);
6212 print_timestamp_time("InitImages");
6215 if (snd_new_identifier != NULL || force_reload_snd)
6217 InitSound(snd_new_identifier);
6218 print_timestamp_time("InitSound");
6221 if (mus_new_identifier != NULL || force_reload_mus)
6223 InitMusic(mus_new_identifier);
6224 print_timestamp_time("InitMusic");
6227 game_status = last_game_status; /* restore current game status */
6229 init_last = init; /* switch to new busy animation */
6232 printf("::: ----------------DELAY 1 ...\n");
6237 printf("::: FadeOut @ ReloadCustomArtwork ...\n");
6239 FadeOut(REDRAW_ALL);
6241 printf("::: FadeOut @ ReloadCustomArtwork done\n");
6246 /* force redraw of (open or closed) door graphics */
6247 SetDoorState(DOOR_OPEN_ALL);
6248 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
6253 FadeSetEnterScreen();
6254 FadeSkipNextFadeOut();
6255 // FadeSetDisabled();
6260 fading = fading_none;
6265 redraw_mask = REDRAW_ALL;
6268 print_timestamp_done("ReloadCustomArtwork");
6271 void KeyboardAutoRepeatOffUnlessAutoplay()
6273 if (global.autoplay_leveldir == NULL)
6274 KeyboardAutoRepeatOff();
6278 /* ========================================================================= */
6280 /* ========================================================================= */
6284 print_timestamp_init("OpenAll");
6286 game_status = GAME_MODE_LOADING;
6292 InitGlobal(); /* initialize some global variables */
6294 print_timestamp_time("[init global stuff]");
6296 if (options.execute_command)
6297 Execute_Command(options.execute_command);
6299 if (options.serveronly)
6301 #if defined(PLATFORM_UNIX)
6302 NetworkServer(options.server_port, options.serveronly);
6304 Error(ERR_WARN, "networking only supported in Unix version");
6307 exit(0); /* never reached, server loops forever */
6312 print_timestamp_time("[init setup/config stuff (1)]");
6315 print_timestamp_time("[init setup/config stuff (2)]");
6317 print_timestamp_time("[init setup/config stuff (3)]");
6318 InitArtworkInfo(); /* needed before loading gfx, sound & music */
6319 print_timestamp_time("[init setup/config stuff (4)]");
6320 InitArtworkConfig(); /* needed before forking sound child process */
6321 print_timestamp_time("[init setup/config stuff (5)]");
6323 print_timestamp_time("[init setup/config stuff (6)]");
6329 InitRND(NEW_RANDOMIZE);
6330 InitSimpleRandom(NEW_RANDOMIZE);
6334 print_timestamp_time("[init setup/config stuff]");
6337 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
6339 InitEventFilter(FilterMouseMotionEvents);
6341 print_timestamp_time("[init video stuff]");
6343 InitElementPropertiesStatic();
6344 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
6345 InitElementPropertiesGfxElement();
6347 print_timestamp_time("[init element properties stuff]");
6351 print_timestamp_time("InitGfx");
6354 print_timestamp_time("InitLevelInfo");
6356 InitLevelArtworkInfo();
6357 print_timestamp_time("InitLevelArtworkInfo");
6359 InitOverrideArtwork(); /* needs to know current level directory */
6360 print_timestamp_time("InitOverrideArtwork");
6362 InitImages(); /* needs to know current level directory */
6363 print_timestamp_time("InitImages");
6365 InitSound(NULL); /* needs to know current level directory */
6366 print_timestamp_time("InitSound");
6368 InitMusic(NULL); /* needs to know current level directory */
6369 print_timestamp_time("InitMusic");
6371 InitGfxBackground();
6381 if (global.autoplay_leveldir)
6386 else if (global.convert_leveldir)
6391 else if (global.create_images_dir)
6393 CreateLevelSketchImages();
6397 game_status = GAME_MODE_MAIN;
6400 FadeSetEnterScreen();
6401 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
6402 FadeSkipNextFadeOut();
6403 // FadeSetDisabled();
6405 fading = fading_none;
6408 print_timestamp_time("[post-artwork]");
6410 print_timestamp_done("OpenAll");
6414 InitNetworkServer();
6417 void CloseAllAndExit(int exit_value)
6422 CloseAudio(); /* called after freeing sounds (needed for SDL) */
6434 #if defined(TARGET_SDL)
6435 if (network_server) /* terminate network server */
6436 SDL_KillThread(server_thread);
6439 CloseVideoDisplay();
6440 ClosePlatformDependentStuff();
6442 if (exit_value != 0)
6444 /* fall back to default level set (current set may have caused an error) */
6445 SaveLevelSetup_LastSeries_Deactivate();
6447 /* tell user where to find error log file which may contain more details */
6448 NotifyUserAboutErrorFile();