1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2006 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
14 #include "libgame/libgame.h"
29 #include "conf_e2g.c" /* include auto-generated data structure definitions */
30 #include "conf_esg.c" /* include auto-generated data structure definitions */
31 #include "conf_e2s.c" /* include auto-generated data structure definitions */
32 #include "conf_fnt.c" /* include auto-generated data structure definitions */
33 #include "conf_g2s.c" /* include auto-generated data structure definitions */
34 #include "conf_g2m.c" /* include auto-generated data structure definitions */
35 #include "conf_act.c" /* include auto-generated data structure definitions */
38 #define CONFIG_TOKEN_FONT_INITIAL "font.initial"
39 #define CONFIG_TOKEN_GLOBAL_BUSY "global.busy"
41 #define DEBUG_PRINT_INIT_TIMESTAMPS TRUE
42 #define DEBUG_PRINT_INIT_TIMESTAMPS_DEPTH 1
45 static struct FontBitmapInfo font_initial[NUM_INITIAL_FONTS];
46 static struct GraphicInfo anim_initial;
48 static int copy_properties[][5] =
52 EL_BUG_LEFT, EL_BUG_RIGHT,
53 EL_BUG_UP, EL_BUG_DOWN
57 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
58 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
62 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
63 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
67 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
68 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
72 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
73 EL_PACMAN_UP, EL_PACMAN_DOWN
77 EL_YAMYAM_LEFT, EL_YAMYAM_RIGHT,
78 EL_YAMYAM_UP, EL_YAMYAM_DOWN
82 EL_MOLE_LEFT, EL_MOLE_RIGHT,
83 EL_MOLE_UP, EL_MOLE_DOWN
92 static void print_timestamp_ext(char *message, char *mode)
95 #if DEBUG_PRINT_INIT_TIMESTAMPS
96 static char *debug_message = NULL;
97 static char *last_message = NULL;
98 static int counter_nr = 0;
99 int max_depth = DEBUG_PRINT_INIT_TIMESTAMPS_DEPTH;
101 checked_free(debug_message);
102 debug_message = getStringCat3(mode, " ", message);
104 if (strEqual(mode, "INIT"))
106 debug_print_timestamp(counter_nr, NULL);
108 if (counter_nr + 1 < max_depth)
109 debug_print_timestamp(counter_nr, debug_message);
113 debug_print_timestamp(counter_nr, NULL);
115 else if (strEqual(mode, "DONE"))
119 if (counter_nr + 1 < max_depth ||
120 (counter_nr == 0 && max_depth == 1))
122 last_message = message;
124 if (counter_nr == 0 && max_depth == 1)
126 checked_free(debug_message);
127 debug_message = getStringCat3("TIME", " ", message);
130 debug_print_timestamp(counter_nr, debug_message);
133 else if (!strEqual(mode, "TIME") ||
134 !strEqual(message, last_message))
136 if (counter_nr < max_depth)
137 debug_print_timestamp(counter_nr, debug_message);
143 static void print_timestamp_init(char *message)
145 print_timestamp_ext(message, "INIT");
148 static void print_timestamp_time(char *message)
150 print_timestamp_ext(message, "TIME");
153 static void print_timestamp_done(char *message)
155 print_timestamp_ext(message, "DONE");
160 struct GraphicInfo *graphic_info_last = graphic_info;
162 static unsigned long action_delay = 0;
163 unsigned long action_delay_value = GameFrameDelay;
164 int sync_frame = FrameCounter;
167 if (game_status != GAME_MODE_LOADING)
170 if (anim_initial.bitmap == NULL || window == NULL)
173 if (!DelayReached(&action_delay, action_delay_value))
178 static unsigned long last_counter = -1;
179 unsigned long current_counter = Counter();
180 unsigned long delay = current_counter - last_counter;
182 if (last_counter != -1 && delay > action_delay_value + 5)
183 printf("::: DrawInitAnim: DELAY TOO LONG: %ld\n", delay);
185 last_counter = current_counter;
189 x = ALIGNED_TEXT_XPOS(&init_last.busy);
190 y = ALIGNED_TEXT_YPOS(&init_last.busy);
192 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
196 static boolean done = FALSE;
199 printf("::: %d, %d, %d, %d => %d, %d [%d, %d] [%d, %d]\n",
200 init.busy.x, init.busy.y,
201 init.busy.align, init.busy.valign,
203 graphic_info[graphic].width,
204 graphic_info[graphic].height,
205 sync_frame, anim_initial.anim_delay);
211 if (sync_frame % anim_initial.anim_delay == 0)
216 int width = graphic_info[graphic].width;
217 int height = graphic_info[graphic].height;
218 int frame = getGraphicAnimationFrame(graphic, sync_frame);
220 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 long 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_SCORES,
1881 IMG_BACKGROUND_EDITOR,
1882 IMG_BACKGROUND_INFO,
1883 IMG_BACKGROUND_INFO_ELEMENTS,
1884 IMG_BACKGROUND_INFO_MUSIC,
1885 IMG_BACKGROUND_INFO_CREDITS,
1886 IMG_BACKGROUND_INFO_PROGRAM,
1887 IMG_BACKGROUND_INFO_LEVELSET,
1888 IMG_BACKGROUND_SETUP,
1889 IMG_BACKGROUND_DOOR,
1890 IMG_BACKGROUND_TAPE,
1891 IMG_BACKGROUND_PANEL,
1893 IMG_TITLESCREEN_INITIAL_1,
1894 IMG_TITLESCREEN_INITIAL_2,
1895 IMG_TITLESCREEN_INITIAL_3,
1896 IMG_TITLESCREEN_INITIAL_4,
1897 IMG_TITLESCREEN_INITIAL_5,
1907 checked_free(graphic_info);
1909 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1912 /* initialize "use_image_size" flag with default value */
1913 for (i = 0; i < num_images; i++)
1914 graphic_info[i].use_image_size = FALSE;
1916 /* initialize "use_image_size" flag from static configuration above */
1917 for (i = 0; full_size_graphics[i] != -1; i++)
1918 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1921 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1922 if (clipmasks_initialized)
1924 for (i = 0; i < num_images; i++)
1926 if (graphic_info[i].clip_mask)
1927 XFreePixmap(display, graphic_info[i].clip_mask);
1928 if (graphic_info[i].clip_gc)
1929 XFreeGC(display, graphic_info[i].clip_gc);
1931 graphic_info[i].clip_mask = None;
1932 graphic_info[i].clip_gc = None;
1937 /* first set all graphic paramaters ... */
1938 for (i = 0; i < num_images; i++)
1939 set_graphic_parameters(i);
1941 /* ... then copy these parameters for cloned graphics */
1942 for (i = 0; i < num_images; i++)
1943 if (graphic_info[i].clone_from != -1)
1944 set_cloned_graphic_parameters(i);
1946 for (i = 0; i < num_images; i++)
1951 int first_frame, last_frame;
1952 int src_bitmap_width, src_bitmap_height;
1954 /* now check if no animation frames are outside of the loaded image */
1956 if (graphic_info[i].bitmap == NULL)
1957 continue; /* skip check for optional images that are undefined */
1959 /* get image size (this can differ from the standard element tile size!) */
1960 width = graphic_info[i].width;
1961 height = graphic_info[i].height;
1963 /* get final bitmap size (with scaling, but without small images) */
1964 src_bitmap_width = graphic_info[i].src_image_width;
1965 src_bitmap_height = graphic_info[i].src_image_height;
1967 /* check if first animation frame is inside specified bitmap */
1970 getFixedGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1973 /* this avoids calculating wrong start position for out-of-bounds frame */
1974 src_x = graphic_info[i].src_x;
1975 src_y = graphic_info[i].src_y;
1978 if (src_x < 0 || src_y < 0 ||
1979 src_x + width > src_bitmap_width ||
1980 src_y + height > src_bitmap_height)
1982 Error(ERR_INFO_LINE, "-");
1983 Error(ERR_INFO, "warning: error found in config file:");
1984 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1985 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1986 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1988 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1989 src_x, src_y, src_bitmap_width, src_bitmap_height);
1990 Error(ERR_INFO, "custom graphic rejected for this element/action");
1992 if (i == fallback_graphic)
1993 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1995 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1996 Error(ERR_INFO_LINE, "-");
1998 graphic_info[i] = graphic_info[fallback_graphic];
2001 /* check if last animation frame is inside specified bitmap */
2003 last_frame = graphic_info[i].anim_frames - 1;
2004 getFixedGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
2006 if (src_x < 0 || src_y < 0 ||
2007 src_x + width > src_bitmap_width ||
2008 src_y + height > src_bitmap_height)
2010 Error(ERR_INFO_LINE, "-");
2011 Error(ERR_INFO, "warning: error found in config file:");
2012 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
2013 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
2014 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
2016 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
2017 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
2018 Error(ERR_INFO, "::: %d, %d", width, height);
2019 Error(ERR_INFO, "custom graphic rejected for this element/action");
2021 if (i == fallback_graphic)
2022 Error(ERR_EXIT, "fatal error: no fallback graphic available");
2024 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
2025 Error(ERR_INFO_LINE, "-");
2027 graphic_info[i] = graphic_info[fallback_graphic];
2030 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
2031 /* currently we only need a tile clip mask from the first frame */
2032 getFixedGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
2034 if (copy_clipmask_gc == None)
2036 clip_gc_values.graphics_exposures = False;
2037 clip_gc_valuemask = GCGraphicsExposures;
2038 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
2039 clip_gc_valuemask, &clip_gc_values);
2042 graphic_info[i].clip_mask =
2043 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
2045 src_pixmap = src_bitmap->clip_mask;
2046 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
2047 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
2049 clip_gc_values.graphics_exposures = False;
2050 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
2051 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
2053 graphic_info[i].clip_gc =
2054 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
2058 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
2059 if (copy_clipmask_gc)
2060 XFreeGC(display, copy_clipmask_gc);
2062 clipmasks_initialized = TRUE;
2066 static void InitGraphicCompatibilityInfo()
2068 struct FileInfo *fi_global_door =
2069 getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
2070 int num_images = getImageListSize();
2073 /* the following compatibility handling is needed for the following case:
2074 versions up to 3.3.0.0 used one large bitmap "global.door" for various
2075 graphics mainly used for door and panel graphics, like editor, tape and
2076 in-game buttons with hard-coded bitmap positions and button sizes; as
2077 these graphics now have individual definitions, redefining "global.door"
2078 to change all these graphics at once like before does not work anymore
2079 (because all those individual definitions still have their default values);
2080 to solve this, remap all those individual definitions that are not
2081 redefined to the new bitmap of "global.door" if it was redefined */
2083 /* special compatibility handling if image "global.door" was redefined */
2084 if (fi_global_door->redefined)
2086 for (i = 0; i < num_images; i++)
2088 struct FileInfo *fi = getImageListEntryFromImageID(i);
2090 /* process only those images that still use the default settings */
2093 /* process all images which default to same image as "global.door" */
2094 if (strEqual(fi->default_filename, fi_global_door->default_filename))
2096 // printf("::: special treatment needed for token '%s'\n", fi->token);
2098 graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2105 for (i = 0; i < num_images; i++)
2107 struct FileInfo *fi = getImageListEntryFromImageID(i);
2109 if (i == IMG_GLOBAL_DOOR)
2111 printf("::: %s, %s, %d\n",
2112 fi->default_filename,
2120 static void InitElementSoundInfo()
2122 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
2123 int num_property_mappings = getSoundListPropertyMappingSize();
2126 /* set values to -1 to identify later as "uninitialized" values */
2127 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2128 for (act = 0; act < NUM_ACTIONS; act++)
2129 element_info[i].sound[act] = -1;
2131 /* initialize element/sound mapping from static configuration */
2132 for (i = 0; element_to_sound[i].element > -1; i++)
2134 int element = element_to_sound[i].element;
2135 int action = element_to_sound[i].action;
2136 int sound = element_to_sound[i].sound;
2137 boolean is_class = element_to_sound[i].is_class;
2140 action = ACTION_DEFAULT;
2143 element_info[element].sound[action] = sound;
2145 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2146 if (strEqual(element_info[j].class_name,
2147 element_info[element].class_name))
2148 element_info[j].sound[action] = sound;
2151 /* initialize element class/sound mapping from dynamic configuration */
2152 for (i = 0; i < num_property_mappings; i++)
2154 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
2155 int action = property_mapping[i].ext1_index;
2156 int sound = property_mapping[i].artwork_index;
2158 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
2162 action = ACTION_DEFAULT;
2164 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2165 if (strEqual(element_info[j].class_name,
2166 element_info[element_class].class_name))
2167 element_info[j].sound[action] = sound;
2170 /* initialize element/sound mapping from dynamic configuration */
2171 for (i = 0; i < num_property_mappings; i++)
2173 int element = property_mapping[i].base_index;
2174 int action = property_mapping[i].ext1_index;
2175 int sound = property_mapping[i].artwork_index;
2177 if (element >= MAX_NUM_ELEMENTS)
2181 action = ACTION_DEFAULT;
2183 element_info[element].sound[action] = sound;
2186 /* now set all '-1' values to element specific default values */
2187 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2189 for (act = 0; act < NUM_ACTIONS; act++)
2191 /* generic default action sound (defined by "[default]" directive) */
2192 int default_action_sound = element_info[EL_DEFAULT].sound[act];
2194 /* look for special default action sound (classic game specific) */
2195 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
2196 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
2197 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
2198 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
2199 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
2200 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
2202 /* !!! there's no such thing as a "default action sound" !!! */
2204 /* look for element specific default sound (independent from action) */
2205 if (element_info[i].sound[ACTION_DEFAULT] != -1)
2206 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
2210 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
2211 /* !!! make this better !!! */
2212 if (i == EL_EMPTY_SPACE)
2213 default_action_sound = element_info[EL_DEFAULT].sound[act];
2216 /* no sound for this specific action -- use default action sound */
2217 if (element_info[i].sound[act] == -1)
2218 element_info[i].sound[act] = default_action_sound;
2222 /* copy sound settings to some elements that are only stored in level file
2223 in native R'n'D levels, but are used by game engine in native EM levels */
2224 for (i = 0; copy_properties[i][0] != -1; i++)
2225 for (j = 1; j <= 4; j++)
2226 for (act = 0; act < NUM_ACTIONS; act++)
2227 element_info[copy_properties[i][j]].sound[act] =
2228 element_info[copy_properties[i][0]].sound[act];
2231 static void InitGameModeSoundInfo()
2235 /* set values to -1 to identify later as "uninitialized" values */
2236 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2239 /* initialize gamemode/sound mapping from static configuration */
2240 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
2242 int gamemode = gamemode_to_sound[i].gamemode;
2243 int sound = gamemode_to_sound[i].sound;
2246 gamemode = GAME_MODE_DEFAULT;
2248 menu.sound[gamemode] = sound;
2251 /* now set all '-1' values to levelset specific default values */
2252 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2253 if (menu.sound[i] == -1)
2254 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
2257 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2258 if (menu.sound[i] != -1)
2259 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
2263 static void set_sound_parameters(int sound, char **parameter_raw)
2265 int parameter[NUM_SND_ARGS];
2268 /* get integer values from string parameters */
2269 for (i = 0; i < NUM_SND_ARGS; i++)
2271 get_parameter_value(parameter_raw[i],
2272 sound_config_suffix[i].token,
2273 sound_config_suffix[i].type);
2275 /* explicit loop mode setting in configuration overrides default value */
2276 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2277 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
2279 /* sound volume to change the original volume when loading the sound file */
2280 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
2282 /* sound priority to give certain sounds a higher or lower priority */
2283 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
2286 static void InitSoundInfo()
2288 int *sound_effect_properties;
2289 int num_sounds = getSoundListSize();
2292 checked_free(sound_info);
2294 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
2295 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
2297 /* initialize sound effect for all elements to "no sound" */
2298 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2299 for (j = 0; j < NUM_ACTIONS; j++)
2300 element_info[i].sound[j] = SND_UNDEFINED;
2302 for (i = 0; i < num_sounds; i++)
2304 struct FileInfo *sound = getSoundListEntry(i);
2305 int len_effect_text = strlen(sound->token);
2307 sound_effect_properties[i] = ACTION_OTHER;
2308 sound_info[i].loop = FALSE; /* default: play sound only once */
2311 printf("::: sound %d: '%s'\n", i, sound->token);
2314 /* determine all loop sounds and identify certain sound classes */
2316 for (j = 0; element_action_info[j].suffix; j++)
2318 int len_action_text = strlen(element_action_info[j].suffix);
2320 if (len_action_text < len_effect_text &&
2321 strEqual(&sound->token[len_effect_text - len_action_text],
2322 element_action_info[j].suffix))
2324 sound_effect_properties[i] = element_action_info[j].value;
2325 sound_info[i].loop = element_action_info[j].is_loop_sound;
2331 /* associate elements and some selected sound actions */
2333 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2335 if (element_info[j].class_name)
2337 int len_class_text = strlen(element_info[j].class_name);
2339 if (len_class_text + 1 < len_effect_text &&
2340 strncmp(sound->token,
2341 element_info[j].class_name, len_class_text) == 0 &&
2342 sound->token[len_class_text] == '.')
2344 int sound_action_value = sound_effect_properties[i];
2346 element_info[j].sound[sound_action_value] = i;
2351 set_sound_parameters(i, sound->parameter);
2354 free(sound_effect_properties);
2357 static void InitGameModeMusicInfo()
2359 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
2360 int num_property_mappings = getMusicListPropertyMappingSize();
2361 int default_levelset_music = -1;
2364 /* set values to -1 to identify later as "uninitialized" values */
2365 for (i = 0; i < MAX_LEVELS; i++)
2366 levelset.music[i] = -1;
2367 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2370 /* initialize gamemode/music mapping from static configuration */
2371 for (i = 0; gamemode_to_music[i].music > -1; i++)
2373 int gamemode = gamemode_to_music[i].gamemode;
2374 int music = gamemode_to_music[i].music;
2377 printf("::: gamemode == %d, music == %d\n", gamemode, music);
2381 gamemode = GAME_MODE_DEFAULT;
2383 menu.music[gamemode] = music;
2386 /* initialize gamemode/music mapping from dynamic configuration */
2387 for (i = 0; i < num_property_mappings; i++)
2389 int prefix = property_mapping[i].base_index;
2390 int gamemode = property_mapping[i].ext1_index;
2391 int level = property_mapping[i].ext2_index;
2392 int music = property_mapping[i].artwork_index;
2395 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
2396 prefix, gamemode, level, music);
2399 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
2403 gamemode = GAME_MODE_DEFAULT;
2405 /* level specific music only allowed for in-game music */
2406 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
2407 gamemode = GAME_MODE_PLAYING;
2412 default_levelset_music = music;
2415 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
2416 levelset.music[level] = music;
2417 if (gamemode != GAME_MODE_PLAYING)
2418 menu.music[gamemode] = music;
2421 /* now set all '-1' values to menu specific default values */
2422 /* (undefined values of "levelset.music[]" might stay at "-1" to
2423 allow dynamic selection of music files from music directory!) */
2424 for (i = 0; i < MAX_LEVELS; i++)
2425 if (levelset.music[i] == -1)
2426 levelset.music[i] = default_levelset_music;
2427 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2428 if (menu.music[i] == -1)
2429 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
2432 for (i = 0; i < MAX_LEVELS; i++)
2433 if (levelset.music[i] != -1)
2434 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
2435 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2436 if (menu.music[i] != -1)
2437 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
2441 static void set_music_parameters(int music, char **parameter_raw)
2443 int parameter[NUM_MUS_ARGS];
2446 /* get integer values from string parameters */
2447 for (i = 0; i < NUM_MUS_ARGS; i++)
2449 get_parameter_value(parameter_raw[i],
2450 music_config_suffix[i].token,
2451 music_config_suffix[i].type);
2453 /* explicit loop mode setting in configuration overrides default value */
2454 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2455 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
2458 static void InitMusicInfo()
2460 int num_music = getMusicListSize();
2463 checked_free(music_info);
2465 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
2467 for (i = 0; i < num_music; i++)
2469 struct FileInfo *music = getMusicListEntry(i);
2470 int len_music_text = strlen(music->token);
2472 music_info[i].loop = TRUE; /* default: play music in loop mode */
2474 /* determine all loop music */
2476 for (j = 0; music_prefix_info[j].prefix; j++)
2478 int len_prefix_text = strlen(music_prefix_info[j].prefix);
2480 if (len_prefix_text < len_music_text &&
2481 strncmp(music->token,
2482 music_prefix_info[j].prefix, len_prefix_text) == 0)
2484 music_info[i].loop = music_prefix_info[j].is_loop_music;
2490 set_music_parameters(i, music->parameter);
2494 static void ReinitializeGraphics()
2496 print_timestamp_init("ReinitializeGraphics");
2498 InitGraphicInfo(); /* graphic properties mapping */
2499 print_timestamp_time("InitGraphicInfo");
2500 InitElementGraphicInfo(); /* element game graphic mapping */
2501 print_timestamp_time("InitElementGraphicInfo");
2502 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
2503 print_timestamp_time("InitElementSpecialGraphicInfo");
2505 InitElementSmallImages(); /* scale elements to all needed sizes */
2506 print_timestamp_time("InitElementSmallImages");
2507 InitScaledImages(); /* scale all other images, if needed */
2508 print_timestamp_time("InitScaledImages");
2509 InitFontGraphicInfo(); /* initialize text drawing functions */
2510 print_timestamp_time("InitFontGraphicInfo");
2512 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
2513 print_timestamp_time("InitGraphicInfo_EM");
2515 InitGraphicCompatibilityInfo();
2516 print_timestamp_time("InitGraphicCompatibilityInfo");
2518 SetMainBackgroundImage(IMG_BACKGROUND);
2519 print_timestamp_time("SetMainBackgroundImage");
2520 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2521 print_timestamp_time("SetDoorBackgroundImage");
2524 print_timestamp_time("InitGadgets");
2526 print_timestamp_time("InitToons");
2528 print_timestamp_done("ReinitializeGraphics");
2531 static void ReinitializeSounds()
2533 InitSoundInfo(); /* sound properties mapping */
2534 InitElementSoundInfo(); /* element game sound mapping */
2535 InitGameModeSoundInfo(); /* game mode sound mapping */
2537 InitPlayLevelSound(); /* internal game sound settings */
2540 static void ReinitializeMusic()
2542 InitMusicInfo(); /* music properties mapping */
2543 InitGameModeMusicInfo(); /* game mode music mapping */
2546 static int get_special_property_bit(int element, int property_bit_nr)
2548 struct PropertyBitInfo
2554 static struct PropertyBitInfo pb_can_move_into_acid[] =
2556 /* the player may be able fall into acid when gravity is activated */
2561 { EL_SP_MURPHY, 0 },
2562 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2564 /* all elements that can move may be able to also move into acid */
2567 { EL_BUG_RIGHT, 1 },
2570 { EL_SPACESHIP, 2 },
2571 { EL_SPACESHIP_LEFT, 2 },
2572 { EL_SPACESHIP_RIGHT, 2 },
2573 { EL_SPACESHIP_UP, 2 },
2574 { EL_SPACESHIP_DOWN, 2 },
2575 { EL_BD_BUTTERFLY, 3 },
2576 { EL_BD_BUTTERFLY_LEFT, 3 },
2577 { EL_BD_BUTTERFLY_RIGHT, 3 },
2578 { EL_BD_BUTTERFLY_UP, 3 },
2579 { EL_BD_BUTTERFLY_DOWN, 3 },
2580 { EL_BD_FIREFLY, 4 },
2581 { EL_BD_FIREFLY_LEFT, 4 },
2582 { EL_BD_FIREFLY_RIGHT, 4 },
2583 { EL_BD_FIREFLY_UP, 4 },
2584 { EL_BD_FIREFLY_DOWN, 4 },
2586 { EL_YAMYAM_LEFT, 5 },
2587 { EL_YAMYAM_RIGHT, 5 },
2588 { EL_YAMYAM_UP, 5 },
2589 { EL_YAMYAM_DOWN, 5 },
2590 { EL_DARK_YAMYAM, 6 },
2593 { EL_PACMAN_LEFT, 8 },
2594 { EL_PACMAN_RIGHT, 8 },
2595 { EL_PACMAN_UP, 8 },
2596 { EL_PACMAN_DOWN, 8 },
2598 { EL_MOLE_LEFT, 9 },
2599 { EL_MOLE_RIGHT, 9 },
2601 { EL_MOLE_DOWN, 9 },
2605 { EL_SATELLITE, 13 },
2606 { EL_SP_SNIKSNAK, 14 },
2607 { EL_SP_ELECTRON, 15 },
2610 { EL_EMC_ANDROID, 18 },
2615 static struct PropertyBitInfo pb_dont_collide_with[] =
2617 { EL_SP_SNIKSNAK, 0 },
2618 { EL_SP_ELECTRON, 1 },
2626 struct PropertyBitInfo *pb_info;
2629 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2630 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2635 struct PropertyBitInfo *pb_info = NULL;
2638 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2639 if (pb_definition[i].bit_nr == property_bit_nr)
2640 pb_info = pb_definition[i].pb_info;
2642 if (pb_info == NULL)
2645 for (i = 0; pb_info[i].element != -1; i++)
2646 if (pb_info[i].element == element)
2647 return pb_info[i].bit_nr;
2652 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2653 boolean property_value)
2655 int bit_nr = get_special_property_bit(element, property_bit_nr);
2660 *bitfield |= (1 << bit_nr);
2662 *bitfield &= ~(1 << bit_nr);
2666 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2668 int bit_nr = get_special_property_bit(element, property_bit_nr);
2671 return ((*bitfield & (1 << bit_nr)) != 0);
2676 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2678 static int group_nr;
2679 static struct ElementGroupInfo *group;
2680 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2683 if (actual_group == NULL) /* not yet initialized */
2686 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
2688 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2689 group_element - EL_GROUP_START + 1);
2691 /* replace element which caused too deep recursion by question mark */
2692 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2697 if (recursion_depth == 0) /* initialization */
2699 group = actual_group;
2700 group_nr = GROUP_NR(group_element);
2702 group->num_elements_resolved = 0;
2703 group->choice_pos = 0;
2705 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2706 element_info[i].in_group[group_nr] = FALSE;
2709 for (i = 0; i < actual_group->num_elements; i++)
2711 int element = actual_group->element[i];
2713 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2716 if (IS_GROUP_ELEMENT(element))
2717 ResolveGroupElementExt(element, recursion_depth + 1);
2720 group->element_resolved[group->num_elements_resolved++] = element;
2721 element_info[element].in_group[group_nr] = TRUE;
2726 void ResolveGroupElement(int group_element)
2728 ResolveGroupElementExt(group_element, 0);
2731 void InitElementPropertiesStatic()
2733 static boolean clipboard_elements_initialized = FALSE;
2735 static int ep_diggable[] =
2740 EL_SP_BUGGY_BASE_ACTIVATING,
2743 EL_INVISIBLE_SAND_ACTIVE,
2746 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2747 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2752 EL_SP_BUGGY_BASE_ACTIVE,
2759 static int ep_collectible_only[] =
2781 EL_DYNABOMB_INCREASE_NUMBER,
2782 EL_DYNABOMB_INCREASE_SIZE,
2783 EL_DYNABOMB_INCREASE_POWER,
2801 /* !!! handle separately !!! */
2802 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2808 static int ep_dont_run_into[] =
2810 /* same elements as in 'ep_dont_touch' */
2816 /* same elements as in 'ep_dont_collide_with' */
2828 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2833 EL_SP_BUGGY_BASE_ACTIVE,
2840 static int ep_dont_collide_with[] =
2842 /* same elements as in 'ep_dont_touch' */
2859 static int ep_dont_touch[] =
2869 static int ep_indestructible[] =
2873 EL_ACID_POOL_TOPLEFT,
2874 EL_ACID_POOL_TOPRIGHT,
2875 EL_ACID_POOL_BOTTOMLEFT,
2876 EL_ACID_POOL_BOTTOM,
2877 EL_ACID_POOL_BOTTOMRIGHT,
2878 EL_SP_HARDWARE_GRAY,
2879 EL_SP_HARDWARE_GREEN,
2880 EL_SP_HARDWARE_BLUE,
2882 EL_SP_HARDWARE_YELLOW,
2883 EL_SP_HARDWARE_BASE_1,
2884 EL_SP_HARDWARE_BASE_2,
2885 EL_SP_HARDWARE_BASE_3,
2886 EL_SP_HARDWARE_BASE_4,
2887 EL_SP_HARDWARE_BASE_5,
2888 EL_SP_HARDWARE_BASE_6,
2889 EL_INVISIBLE_STEELWALL,
2890 EL_INVISIBLE_STEELWALL_ACTIVE,
2891 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2892 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2893 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2894 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2895 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2896 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2897 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2898 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2899 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2900 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2901 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2902 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2904 EL_LIGHT_SWITCH_ACTIVE,
2905 EL_SIGN_EXCLAMATION,
2906 EL_SIGN_RADIOACTIVITY,
2913 EL_SIGN_ENTRY_FORBIDDEN,
2914 EL_SIGN_EMERGENCY_EXIT,
2922 EL_STEEL_EXIT_CLOSED,
2924 EL_STEEL_EXIT_OPENING,
2925 EL_STEEL_EXIT_CLOSING,
2926 EL_EM_STEEL_EXIT_CLOSED,
2927 EL_EM_STEEL_EXIT_OPEN,
2928 EL_EM_STEEL_EXIT_OPENING,
2929 EL_EM_STEEL_EXIT_CLOSING,
2930 EL_DC_STEELWALL_1_LEFT,
2931 EL_DC_STEELWALL_1_RIGHT,
2932 EL_DC_STEELWALL_1_TOP,
2933 EL_DC_STEELWALL_1_BOTTOM,
2934 EL_DC_STEELWALL_1_HORIZONTAL,
2935 EL_DC_STEELWALL_1_VERTICAL,
2936 EL_DC_STEELWALL_1_TOPLEFT,
2937 EL_DC_STEELWALL_1_TOPRIGHT,
2938 EL_DC_STEELWALL_1_BOTTOMLEFT,
2939 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2940 EL_DC_STEELWALL_1_TOPLEFT_2,
2941 EL_DC_STEELWALL_1_TOPRIGHT_2,
2942 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2943 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2944 EL_DC_STEELWALL_2_LEFT,
2945 EL_DC_STEELWALL_2_RIGHT,
2946 EL_DC_STEELWALL_2_TOP,
2947 EL_DC_STEELWALL_2_BOTTOM,
2948 EL_DC_STEELWALL_2_HORIZONTAL,
2949 EL_DC_STEELWALL_2_VERTICAL,
2950 EL_DC_STEELWALL_2_MIDDLE,
2951 EL_DC_STEELWALL_2_SINGLE,
2952 EL_STEELWALL_SLIPPERY,
2966 EL_GATE_1_GRAY_ACTIVE,
2967 EL_GATE_2_GRAY_ACTIVE,
2968 EL_GATE_3_GRAY_ACTIVE,
2969 EL_GATE_4_GRAY_ACTIVE,
2978 EL_EM_GATE_1_GRAY_ACTIVE,
2979 EL_EM_GATE_2_GRAY_ACTIVE,
2980 EL_EM_GATE_3_GRAY_ACTIVE,
2981 EL_EM_GATE_4_GRAY_ACTIVE,
2990 EL_EMC_GATE_5_GRAY_ACTIVE,
2991 EL_EMC_GATE_6_GRAY_ACTIVE,
2992 EL_EMC_GATE_7_GRAY_ACTIVE,
2993 EL_EMC_GATE_8_GRAY_ACTIVE,
2995 EL_DC_GATE_WHITE_GRAY,
2996 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2997 EL_DC_GATE_FAKE_GRAY,
2999 EL_SWITCHGATE_OPENING,
3000 EL_SWITCHGATE_CLOSED,
3001 EL_SWITCHGATE_CLOSING,
3003 EL_DC_SWITCHGATE_SWITCH_UP,
3004 EL_DC_SWITCHGATE_SWITCH_DOWN,
3007 EL_TIMEGATE_OPENING,
3009 EL_TIMEGATE_CLOSING,
3011 EL_DC_TIMEGATE_SWITCH,
3012 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3017 EL_TUBE_VERTICAL_LEFT,
3018 EL_TUBE_VERTICAL_RIGHT,
3019 EL_TUBE_HORIZONTAL_UP,
3020 EL_TUBE_HORIZONTAL_DOWN,
3025 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
3026 EL_EXPANDABLE_STEELWALL_VERTICAL,
3027 EL_EXPANDABLE_STEELWALL_ANY,
3032 static int ep_slippery[] =
3046 EL_ROBOT_WHEEL_ACTIVE,
3052 EL_ACID_POOL_TOPLEFT,
3053 EL_ACID_POOL_TOPRIGHT,
3063 EL_STEELWALL_SLIPPERY,
3066 EL_EMC_WALL_SLIPPERY_1,
3067 EL_EMC_WALL_SLIPPERY_2,
3068 EL_EMC_WALL_SLIPPERY_3,
3069 EL_EMC_WALL_SLIPPERY_4,
3071 EL_EMC_MAGIC_BALL_ACTIVE,
3076 static int ep_can_change[] =
3081 static int ep_can_move[] =
3083 /* same elements as in 'pb_can_move_into_acid' */
3106 static int ep_can_fall[] =
3120 EL_QUICKSAND_FAST_FULL,
3122 EL_BD_MAGIC_WALL_FULL,
3123 EL_DC_MAGIC_WALL_FULL,
3137 static int ep_can_smash_player[] =
3163 static int ep_can_smash_enemies[] =
3172 static int ep_can_smash_everything[] =
3181 static int ep_explodes_by_fire[] =
3183 /* same elements as in 'ep_explodes_impact' */
3188 /* same elements as in 'ep_explodes_smashed' */
3198 EL_EM_DYNAMITE_ACTIVE,
3199 EL_DYNABOMB_PLAYER_1_ACTIVE,
3200 EL_DYNABOMB_PLAYER_2_ACTIVE,
3201 EL_DYNABOMB_PLAYER_3_ACTIVE,
3202 EL_DYNABOMB_PLAYER_4_ACTIVE,
3203 EL_DYNABOMB_INCREASE_NUMBER,
3204 EL_DYNABOMB_INCREASE_SIZE,
3205 EL_DYNABOMB_INCREASE_POWER,
3206 EL_SP_DISK_RED_ACTIVE,
3220 static int ep_explodes_smashed[] =
3222 /* same elements as in 'ep_explodes_impact' */
3236 static int ep_explodes_impact[] =
3245 static int ep_walkable_over[] =
3249 EL_SOKOBAN_FIELD_EMPTY,
3258 EL_EM_STEEL_EXIT_OPEN,
3260 EL_EM_STEEL_EXIT_OPENING,
3270 EL_GATE_1_GRAY_ACTIVE,
3271 EL_GATE_2_GRAY_ACTIVE,
3272 EL_GATE_3_GRAY_ACTIVE,
3273 EL_GATE_4_GRAY_ACTIVE,
3281 static int ep_walkable_inside[] =
3286 EL_TUBE_VERTICAL_LEFT,
3287 EL_TUBE_VERTICAL_RIGHT,
3288 EL_TUBE_HORIZONTAL_UP,
3289 EL_TUBE_HORIZONTAL_DOWN,
3298 static int ep_walkable_under[] =
3303 static int ep_passable_over[] =
3313 EL_EM_GATE_1_GRAY_ACTIVE,
3314 EL_EM_GATE_2_GRAY_ACTIVE,
3315 EL_EM_GATE_3_GRAY_ACTIVE,
3316 EL_EM_GATE_4_GRAY_ACTIVE,
3325 EL_EMC_GATE_5_GRAY_ACTIVE,
3326 EL_EMC_GATE_6_GRAY_ACTIVE,
3327 EL_EMC_GATE_7_GRAY_ACTIVE,
3328 EL_EMC_GATE_8_GRAY_ACTIVE,
3330 EL_DC_GATE_WHITE_GRAY,
3331 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3338 static int ep_passable_inside[] =
3344 EL_SP_PORT_HORIZONTAL,
3345 EL_SP_PORT_VERTICAL,
3347 EL_SP_GRAVITY_PORT_LEFT,
3348 EL_SP_GRAVITY_PORT_RIGHT,
3349 EL_SP_GRAVITY_PORT_UP,
3350 EL_SP_GRAVITY_PORT_DOWN,
3351 EL_SP_GRAVITY_ON_PORT_LEFT,
3352 EL_SP_GRAVITY_ON_PORT_RIGHT,
3353 EL_SP_GRAVITY_ON_PORT_UP,
3354 EL_SP_GRAVITY_ON_PORT_DOWN,
3355 EL_SP_GRAVITY_OFF_PORT_LEFT,
3356 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3357 EL_SP_GRAVITY_OFF_PORT_UP,
3358 EL_SP_GRAVITY_OFF_PORT_DOWN,
3363 static int ep_passable_under[] =
3368 static int ep_droppable[] =
3373 static int ep_explodes_1x1_old[] =
3378 static int ep_pushable[] =
3390 EL_SOKOBAN_FIELD_FULL,
3399 static int ep_explodes_cross_old[] =
3404 static int ep_protected[] =
3406 /* same elements as in 'ep_walkable_inside' */
3410 EL_TUBE_VERTICAL_LEFT,
3411 EL_TUBE_VERTICAL_RIGHT,
3412 EL_TUBE_HORIZONTAL_UP,
3413 EL_TUBE_HORIZONTAL_DOWN,
3419 /* same elements as in 'ep_passable_over' */
3428 EL_EM_GATE_1_GRAY_ACTIVE,
3429 EL_EM_GATE_2_GRAY_ACTIVE,
3430 EL_EM_GATE_3_GRAY_ACTIVE,
3431 EL_EM_GATE_4_GRAY_ACTIVE,
3440 EL_EMC_GATE_5_GRAY_ACTIVE,
3441 EL_EMC_GATE_6_GRAY_ACTIVE,
3442 EL_EMC_GATE_7_GRAY_ACTIVE,
3443 EL_EMC_GATE_8_GRAY_ACTIVE,
3445 EL_DC_GATE_WHITE_GRAY,
3446 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3450 /* same elements as in 'ep_passable_inside' */
3455 EL_SP_PORT_HORIZONTAL,
3456 EL_SP_PORT_VERTICAL,
3458 EL_SP_GRAVITY_PORT_LEFT,
3459 EL_SP_GRAVITY_PORT_RIGHT,
3460 EL_SP_GRAVITY_PORT_UP,
3461 EL_SP_GRAVITY_PORT_DOWN,
3462 EL_SP_GRAVITY_ON_PORT_LEFT,
3463 EL_SP_GRAVITY_ON_PORT_RIGHT,
3464 EL_SP_GRAVITY_ON_PORT_UP,
3465 EL_SP_GRAVITY_ON_PORT_DOWN,
3466 EL_SP_GRAVITY_OFF_PORT_LEFT,
3467 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3468 EL_SP_GRAVITY_OFF_PORT_UP,
3469 EL_SP_GRAVITY_OFF_PORT_DOWN,
3474 static int ep_throwable[] =
3479 static int ep_can_explode[] =
3481 /* same elements as in 'ep_explodes_impact' */
3486 /* same elements as in 'ep_explodes_smashed' */
3492 /* elements that can explode by explosion or by dragonfire */
3496 EL_EM_DYNAMITE_ACTIVE,
3497 EL_DYNABOMB_PLAYER_1_ACTIVE,
3498 EL_DYNABOMB_PLAYER_2_ACTIVE,
3499 EL_DYNABOMB_PLAYER_3_ACTIVE,
3500 EL_DYNABOMB_PLAYER_4_ACTIVE,
3501 EL_DYNABOMB_INCREASE_NUMBER,
3502 EL_DYNABOMB_INCREASE_SIZE,
3503 EL_DYNABOMB_INCREASE_POWER,
3504 EL_SP_DISK_RED_ACTIVE,
3512 /* elements that can explode only by explosion */
3518 static int ep_gravity_reachable[] =
3524 EL_INVISIBLE_SAND_ACTIVE,
3529 EL_SP_PORT_HORIZONTAL,
3530 EL_SP_PORT_VERTICAL,
3532 EL_SP_GRAVITY_PORT_LEFT,
3533 EL_SP_GRAVITY_PORT_RIGHT,
3534 EL_SP_GRAVITY_PORT_UP,
3535 EL_SP_GRAVITY_PORT_DOWN,
3536 EL_SP_GRAVITY_ON_PORT_LEFT,
3537 EL_SP_GRAVITY_ON_PORT_RIGHT,
3538 EL_SP_GRAVITY_ON_PORT_UP,
3539 EL_SP_GRAVITY_ON_PORT_DOWN,
3540 EL_SP_GRAVITY_OFF_PORT_LEFT,
3541 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3542 EL_SP_GRAVITY_OFF_PORT_UP,
3543 EL_SP_GRAVITY_OFF_PORT_DOWN,
3549 static int ep_player[] =
3556 EL_SOKOBAN_FIELD_PLAYER,
3562 static int ep_can_pass_magic_wall[] =
3576 static int ep_can_pass_dc_magic_wall[] =
3592 static int ep_switchable[] =
3596 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3597 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3598 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3599 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3600 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3601 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3602 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3603 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3604 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3605 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3606 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3607 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3608 EL_SWITCHGATE_SWITCH_UP,
3609 EL_SWITCHGATE_SWITCH_DOWN,
3610 EL_DC_SWITCHGATE_SWITCH_UP,
3611 EL_DC_SWITCHGATE_SWITCH_DOWN,
3613 EL_LIGHT_SWITCH_ACTIVE,
3615 EL_DC_TIMEGATE_SWITCH,
3616 EL_BALLOON_SWITCH_LEFT,
3617 EL_BALLOON_SWITCH_RIGHT,
3618 EL_BALLOON_SWITCH_UP,
3619 EL_BALLOON_SWITCH_DOWN,
3620 EL_BALLOON_SWITCH_ANY,
3621 EL_BALLOON_SWITCH_NONE,
3624 EL_EMC_MAGIC_BALL_SWITCH,
3625 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3630 static int ep_bd_element[] =
3664 static int ep_sp_element[] =
3666 /* should always be valid */
3669 /* standard classic Supaplex elements */
3676 EL_SP_HARDWARE_GRAY,
3684 EL_SP_GRAVITY_PORT_RIGHT,
3685 EL_SP_GRAVITY_PORT_DOWN,
3686 EL_SP_GRAVITY_PORT_LEFT,
3687 EL_SP_GRAVITY_PORT_UP,
3692 EL_SP_PORT_VERTICAL,
3693 EL_SP_PORT_HORIZONTAL,
3699 EL_SP_HARDWARE_BASE_1,
3700 EL_SP_HARDWARE_GREEN,
3701 EL_SP_HARDWARE_BLUE,
3703 EL_SP_HARDWARE_YELLOW,
3704 EL_SP_HARDWARE_BASE_2,
3705 EL_SP_HARDWARE_BASE_3,
3706 EL_SP_HARDWARE_BASE_4,
3707 EL_SP_HARDWARE_BASE_5,
3708 EL_SP_HARDWARE_BASE_6,
3712 /* additional elements that appeared in newer Supaplex levels */
3715 /* additional gravity port elements (not switching, but setting gravity) */
3716 EL_SP_GRAVITY_ON_PORT_LEFT,
3717 EL_SP_GRAVITY_ON_PORT_RIGHT,
3718 EL_SP_GRAVITY_ON_PORT_UP,
3719 EL_SP_GRAVITY_ON_PORT_DOWN,
3720 EL_SP_GRAVITY_OFF_PORT_LEFT,
3721 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3722 EL_SP_GRAVITY_OFF_PORT_UP,
3723 EL_SP_GRAVITY_OFF_PORT_DOWN,
3725 /* more than one Murphy in a level results in an inactive clone */
3728 /* runtime Supaplex elements */
3729 EL_SP_DISK_RED_ACTIVE,
3730 EL_SP_TERMINAL_ACTIVE,
3731 EL_SP_BUGGY_BASE_ACTIVATING,
3732 EL_SP_BUGGY_BASE_ACTIVE,
3739 static int ep_sb_element[] =
3744 EL_SOKOBAN_FIELD_EMPTY,
3745 EL_SOKOBAN_FIELD_FULL,
3746 EL_SOKOBAN_FIELD_PLAYER,
3751 EL_INVISIBLE_STEELWALL,
3756 static int ep_gem[] =
3768 static int ep_food_dark_yamyam[] =
3796 static int ep_food_penguin[] =
3810 static int ep_food_pig[] =
3822 static int ep_historic_wall[] =
3833 EL_GATE_1_GRAY_ACTIVE,
3834 EL_GATE_2_GRAY_ACTIVE,
3835 EL_GATE_3_GRAY_ACTIVE,
3836 EL_GATE_4_GRAY_ACTIVE,
3845 EL_EM_GATE_1_GRAY_ACTIVE,
3846 EL_EM_GATE_2_GRAY_ACTIVE,
3847 EL_EM_GATE_3_GRAY_ACTIVE,
3848 EL_EM_GATE_4_GRAY_ACTIVE,
3855 EL_EXPANDABLE_WALL_HORIZONTAL,
3856 EL_EXPANDABLE_WALL_VERTICAL,
3857 EL_EXPANDABLE_WALL_ANY,
3858 EL_EXPANDABLE_WALL_GROWING,
3859 EL_BD_EXPANDABLE_WALL,
3866 EL_SP_HARDWARE_GRAY,
3867 EL_SP_HARDWARE_GREEN,
3868 EL_SP_HARDWARE_BLUE,
3870 EL_SP_HARDWARE_YELLOW,
3871 EL_SP_HARDWARE_BASE_1,
3872 EL_SP_HARDWARE_BASE_2,
3873 EL_SP_HARDWARE_BASE_3,
3874 EL_SP_HARDWARE_BASE_4,
3875 EL_SP_HARDWARE_BASE_5,
3876 EL_SP_HARDWARE_BASE_6,
3878 EL_SP_TERMINAL_ACTIVE,
3881 EL_INVISIBLE_STEELWALL,
3882 EL_INVISIBLE_STEELWALL_ACTIVE,
3884 EL_INVISIBLE_WALL_ACTIVE,
3885 EL_STEELWALL_SLIPPERY,
3902 static int ep_historic_solid[] =
3906 EL_EXPANDABLE_WALL_HORIZONTAL,
3907 EL_EXPANDABLE_WALL_VERTICAL,
3908 EL_EXPANDABLE_WALL_ANY,
3909 EL_BD_EXPANDABLE_WALL,
3922 EL_QUICKSAND_FILLING,
3923 EL_QUICKSAND_EMPTYING,
3925 EL_MAGIC_WALL_ACTIVE,
3926 EL_MAGIC_WALL_EMPTYING,
3927 EL_MAGIC_WALL_FILLING,
3931 EL_BD_MAGIC_WALL_ACTIVE,
3932 EL_BD_MAGIC_WALL_EMPTYING,
3933 EL_BD_MAGIC_WALL_FULL,
3934 EL_BD_MAGIC_WALL_FILLING,
3935 EL_BD_MAGIC_WALL_DEAD,
3944 EL_SP_TERMINAL_ACTIVE,
3948 EL_INVISIBLE_WALL_ACTIVE,
3949 EL_SWITCHGATE_SWITCH_UP,
3950 EL_SWITCHGATE_SWITCH_DOWN,
3951 EL_DC_SWITCHGATE_SWITCH_UP,
3952 EL_DC_SWITCHGATE_SWITCH_DOWN,
3954 EL_TIMEGATE_SWITCH_ACTIVE,
3955 EL_DC_TIMEGATE_SWITCH,
3956 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3968 /* the following elements are a direct copy of "indestructible" elements,
3969 except "EL_ACID", which is "indestructible", but not "solid"! */
3974 EL_ACID_POOL_TOPLEFT,
3975 EL_ACID_POOL_TOPRIGHT,
3976 EL_ACID_POOL_BOTTOMLEFT,
3977 EL_ACID_POOL_BOTTOM,
3978 EL_ACID_POOL_BOTTOMRIGHT,
3979 EL_SP_HARDWARE_GRAY,
3980 EL_SP_HARDWARE_GREEN,
3981 EL_SP_HARDWARE_BLUE,
3983 EL_SP_HARDWARE_YELLOW,
3984 EL_SP_HARDWARE_BASE_1,
3985 EL_SP_HARDWARE_BASE_2,
3986 EL_SP_HARDWARE_BASE_3,
3987 EL_SP_HARDWARE_BASE_4,
3988 EL_SP_HARDWARE_BASE_5,
3989 EL_SP_HARDWARE_BASE_6,
3990 EL_INVISIBLE_STEELWALL,
3991 EL_INVISIBLE_STEELWALL_ACTIVE,
3992 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3993 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3994 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3995 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3996 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3997 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3998 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3999 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4000 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4001 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4002 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4003 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4005 EL_LIGHT_SWITCH_ACTIVE,
4006 EL_SIGN_EXCLAMATION,
4007 EL_SIGN_RADIOACTIVITY,
4014 EL_SIGN_ENTRY_FORBIDDEN,
4015 EL_SIGN_EMERGENCY_EXIT,
4023 EL_STEEL_EXIT_CLOSED,
4025 EL_DC_STEELWALL_1_LEFT,
4026 EL_DC_STEELWALL_1_RIGHT,
4027 EL_DC_STEELWALL_1_TOP,
4028 EL_DC_STEELWALL_1_BOTTOM,
4029 EL_DC_STEELWALL_1_HORIZONTAL,
4030 EL_DC_STEELWALL_1_VERTICAL,
4031 EL_DC_STEELWALL_1_TOPLEFT,
4032 EL_DC_STEELWALL_1_TOPRIGHT,
4033 EL_DC_STEELWALL_1_BOTTOMLEFT,
4034 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4035 EL_DC_STEELWALL_1_TOPLEFT_2,
4036 EL_DC_STEELWALL_1_TOPRIGHT_2,
4037 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4038 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4039 EL_DC_STEELWALL_2_LEFT,
4040 EL_DC_STEELWALL_2_RIGHT,
4041 EL_DC_STEELWALL_2_TOP,
4042 EL_DC_STEELWALL_2_BOTTOM,
4043 EL_DC_STEELWALL_2_HORIZONTAL,
4044 EL_DC_STEELWALL_2_VERTICAL,
4045 EL_DC_STEELWALL_2_MIDDLE,
4046 EL_DC_STEELWALL_2_SINGLE,
4047 EL_STEELWALL_SLIPPERY,
4061 EL_GATE_1_GRAY_ACTIVE,
4062 EL_GATE_2_GRAY_ACTIVE,
4063 EL_GATE_3_GRAY_ACTIVE,
4064 EL_GATE_4_GRAY_ACTIVE,
4073 EL_EM_GATE_1_GRAY_ACTIVE,
4074 EL_EM_GATE_2_GRAY_ACTIVE,
4075 EL_EM_GATE_3_GRAY_ACTIVE,
4076 EL_EM_GATE_4_GRAY_ACTIVE,
4078 EL_SWITCHGATE_OPENING,
4079 EL_SWITCHGATE_CLOSED,
4080 EL_SWITCHGATE_CLOSING,
4082 EL_TIMEGATE_OPENING,
4084 EL_TIMEGATE_CLOSING,
4088 EL_TUBE_VERTICAL_LEFT,
4089 EL_TUBE_VERTICAL_RIGHT,
4090 EL_TUBE_HORIZONTAL_UP,
4091 EL_TUBE_HORIZONTAL_DOWN,
4100 static int ep_classic_enemy[] =
4117 static int ep_belt[] =
4119 EL_CONVEYOR_BELT_1_LEFT,
4120 EL_CONVEYOR_BELT_1_MIDDLE,
4121 EL_CONVEYOR_BELT_1_RIGHT,
4122 EL_CONVEYOR_BELT_2_LEFT,
4123 EL_CONVEYOR_BELT_2_MIDDLE,
4124 EL_CONVEYOR_BELT_2_RIGHT,
4125 EL_CONVEYOR_BELT_3_LEFT,
4126 EL_CONVEYOR_BELT_3_MIDDLE,
4127 EL_CONVEYOR_BELT_3_RIGHT,
4128 EL_CONVEYOR_BELT_4_LEFT,
4129 EL_CONVEYOR_BELT_4_MIDDLE,
4130 EL_CONVEYOR_BELT_4_RIGHT,
4135 static int ep_belt_active[] =
4137 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
4138 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
4139 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
4140 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
4141 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
4142 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
4143 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
4144 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
4145 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
4146 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
4147 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
4148 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
4153 static int ep_belt_switch[] =
4155 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4156 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4157 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4158 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4159 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4160 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4161 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4162 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4163 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4164 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4165 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4166 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4171 static int ep_tube[] =
4178 EL_TUBE_HORIZONTAL_UP,
4179 EL_TUBE_HORIZONTAL_DOWN,
4181 EL_TUBE_VERTICAL_LEFT,
4182 EL_TUBE_VERTICAL_RIGHT,
4188 static int ep_acid_pool[] =
4190 EL_ACID_POOL_TOPLEFT,
4191 EL_ACID_POOL_TOPRIGHT,
4192 EL_ACID_POOL_BOTTOMLEFT,
4193 EL_ACID_POOL_BOTTOM,
4194 EL_ACID_POOL_BOTTOMRIGHT,
4199 static int ep_keygate[] =
4209 EL_GATE_1_GRAY_ACTIVE,
4210 EL_GATE_2_GRAY_ACTIVE,
4211 EL_GATE_3_GRAY_ACTIVE,
4212 EL_GATE_4_GRAY_ACTIVE,
4221 EL_EM_GATE_1_GRAY_ACTIVE,
4222 EL_EM_GATE_2_GRAY_ACTIVE,
4223 EL_EM_GATE_3_GRAY_ACTIVE,
4224 EL_EM_GATE_4_GRAY_ACTIVE,
4233 EL_EMC_GATE_5_GRAY_ACTIVE,
4234 EL_EMC_GATE_6_GRAY_ACTIVE,
4235 EL_EMC_GATE_7_GRAY_ACTIVE,
4236 EL_EMC_GATE_8_GRAY_ACTIVE,
4238 EL_DC_GATE_WHITE_GRAY,
4239 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4244 static int ep_amoeboid[] =
4256 static int ep_amoebalive[] =
4267 static int ep_has_editor_content[] =
4273 EL_SOKOBAN_FIELD_PLAYER,
4290 static int ep_can_turn_each_move[] =
4292 /* !!! do something with this one !!! */
4296 static int ep_can_grow[] =
4310 static int ep_active_bomb[] =
4313 EL_EM_DYNAMITE_ACTIVE,
4314 EL_DYNABOMB_PLAYER_1_ACTIVE,
4315 EL_DYNABOMB_PLAYER_2_ACTIVE,
4316 EL_DYNABOMB_PLAYER_3_ACTIVE,
4317 EL_DYNABOMB_PLAYER_4_ACTIVE,
4318 EL_SP_DISK_RED_ACTIVE,
4323 static int ep_inactive[] =
4333 EL_QUICKSAND_FAST_EMPTY,
4356 EL_GATE_1_GRAY_ACTIVE,
4357 EL_GATE_2_GRAY_ACTIVE,
4358 EL_GATE_3_GRAY_ACTIVE,
4359 EL_GATE_4_GRAY_ACTIVE,
4368 EL_EM_GATE_1_GRAY_ACTIVE,
4369 EL_EM_GATE_2_GRAY_ACTIVE,
4370 EL_EM_GATE_3_GRAY_ACTIVE,
4371 EL_EM_GATE_4_GRAY_ACTIVE,
4380 EL_EMC_GATE_5_GRAY_ACTIVE,
4381 EL_EMC_GATE_6_GRAY_ACTIVE,
4382 EL_EMC_GATE_7_GRAY_ACTIVE,
4383 EL_EMC_GATE_8_GRAY_ACTIVE,
4385 EL_DC_GATE_WHITE_GRAY,
4386 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4387 EL_DC_GATE_FAKE_GRAY,
4390 EL_INVISIBLE_STEELWALL,
4398 EL_WALL_EMERALD_YELLOW,
4399 EL_DYNABOMB_INCREASE_NUMBER,
4400 EL_DYNABOMB_INCREASE_SIZE,
4401 EL_DYNABOMB_INCREASE_POWER,
4405 EL_SOKOBAN_FIELD_EMPTY,
4406 EL_SOKOBAN_FIELD_FULL,
4407 EL_WALL_EMERALD_RED,
4408 EL_WALL_EMERALD_PURPLE,
4409 EL_ACID_POOL_TOPLEFT,
4410 EL_ACID_POOL_TOPRIGHT,
4411 EL_ACID_POOL_BOTTOMLEFT,
4412 EL_ACID_POOL_BOTTOM,
4413 EL_ACID_POOL_BOTTOMRIGHT,
4417 EL_BD_MAGIC_WALL_DEAD,
4419 EL_DC_MAGIC_WALL_DEAD,
4420 EL_AMOEBA_TO_DIAMOND,
4428 EL_SP_GRAVITY_PORT_RIGHT,
4429 EL_SP_GRAVITY_PORT_DOWN,
4430 EL_SP_GRAVITY_PORT_LEFT,
4431 EL_SP_GRAVITY_PORT_UP,
4432 EL_SP_PORT_HORIZONTAL,
4433 EL_SP_PORT_VERTICAL,
4444 EL_SP_HARDWARE_GRAY,
4445 EL_SP_HARDWARE_GREEN,
4446 EL_SP_HARDWARE_BLUE,
4448 EL_SP_HARDWARE_YELLOW,
4449 EL_SP_HARDWARE_BASE_1,
4450 EL_SP_HARDWARE_BASE_2,
4451 EL_SP_HARDWARE_BASE_3,
4452 EL_SP_HARDWARE_BASE_4,
4453 EL_SP_HARDWARE_BASE_5,
4454 EL_SP_HARDWARE_BASE_6,
4455 EL_SP_GRAVITY_ON_PORT_LEFT,
4456 EL_SP_GRAVITY_ON_PORT_RIGHT,
4457 EL_SP_GRAVITY_ON_PORT_UP,
4458 EL_SP_GRAVITY_ON_PORT_DOWN,
4459 EL_SP_GRAVITY_OFF_PORT_LEFT,
4460 EL_SP_GRAVITY_OFF_PORT_RIGHT,
4461 EL_SP_GRAVITY_OFF_PORT_UP,
4462 EL_SP_GRAVITY_OFF_PORT_DOWN,
4463 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4464 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4465 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4466 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4467 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4468 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4469 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4470 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4471 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4472 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4473 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4474 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4475 EL_SIGN_EXCLAMATION,
4476 EL_SIGN_RADIOACTIVITY,
4483 EL_SIGN_ENTRY_FORBIDDEN,
4484 EL_SIGN_EMERGENCY_EXIT,
4492 EL_DC_STEELWALL_1_LEFT,
4493 EL_DC_STEELWALL_1_RIGHT,
4494 EL_DC_STEELWALL_1_TOP,
4495 EL_DC_STEELWALL_1_BOTTOM,
4496 EL_DC_STEELWALL_1_HORIZONTAL,
4497 EL_DC_STEELWALL_1_VERTICAL,
4498 EL_DC_STEELWALL_1_TOPLEFT,
4499 EL_DC_STEELWALL_1_TOPRIGHT,
4500 EL_DC_STEELWALL_1_BOTTOMLEFT,
4501 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4502 EL_DC_STEELWALL_1_TOPLEFT_2,
4503 EL_DC_STEELWALL_1_TOPRIGHT_2,
4504 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4505 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4506 EL_DC_STEELWALL_2_LEFT,
4507 EL_DC_STEELWALL_2_RIGHT,
4508 EL_DC_STEELWALL_2_TOP,
4509 EL_DC_STEELWALL_2_BOTTOM,
4510 EL_DC_STEELWALL_2_HORIZONTAL,
4511 EL_DC_STEELWALL_2_VERTICAL,
4512 EL_DC_STEELWALL_2_MIDDLE,
4513 EL_DC_STEELWALL_2_SINGLE,
4514 EL_STEELWALL_SLIPPERY,
4519 EL_EMC_WALL_SLIPPERY_1,
4520 EL_EMC_WALL_SLIPPERY_2,
4521 EL_EMC_WALL_SLIPPERY_3,
4522 EL_EMC_WALL_SLIPPERY_4,
4543 static int ep_em_slippery_wall[] =
4548 static int ep_gfx_crumbled[] =
4559 static int ep_editor_cascade_active[] =
4561 EL_INTERNAL_CASCADE_BD_ACTIVE,
4562 EL_INTERNAL_CASCADE_EM_ACTIVE,
4563 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4564 EL_INTERNAL_CASCADE_RND_ACTIVE,
4565 EL_INTERNAL_CASCADE_SB_ACTIVE,
4566 EL_INTERNAL_CASCADE_SP_ACTIVE,
4567 EL_INTERNAL_CASCADE_DC_ACTIVE,
4568 EL_INTERNAL_CASCADE_DX_ACTIVE,
4569 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4570 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4571 EL_INTERNAL_CASCADE_CE_ACTIVE,
4572 EL_INTERNAL_CASCADE_GE_ACTIVE,
4573 EL_INTERNAL_CASCADE_REF_ACTIVE,
4574 EL_INTERNAL_CASCADE_USER_ACTIVE,
4575 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4580 static int ep_editor_cascade_inactive[] =
4582 EL_INTERNAL_CASCADE_BD,
4583 EL_INTERNAL_CASCADE_EM,
4584 EL_INTERNAL_CASCADE_EMC,
4585 EL_INTERNAL_CASCADE_RND,
4586 EL_INTERNAL_CASCADE_SB,
4587 EL_INTERNAL_CASCADE_SP,
4588 EL_INTERNAL_CASCADE_DC,
4589 EL_INTERNAL_CASCADE_DX,
4590 EL_INTERNAL_CASCADE_CHARS,
4591 EL_INTERNAL_CASCADE_STEEL_CHARS,
4592 EL_INTERNAL_CASCADE_CE,
4593 EL_INTERNAL_CASCADE_GE,
4594 EL_INTERNAL_CASCADE_REF,
4595 EL_INTERNAL_CASCADE_USER,
4596 EL_INTERNAL_CASCADE_DYNAMIC,
4601 static int ep_obsolete[] =
4605 EL_EM_KEY_1_FILE_OBSOLETE,
4606 EL_EM_KEY_2_FILE_OBSOLETE,
4607 EL_EM_KEY_3_FILE_OBSOLETE,
4608 EL_EM_KEY_4_FILE_OBSOLETE,
4609 EL_ENVELOPE_OBSOLETE,
4618 } element_properties[] =
4620 { ep_diggable, EP_DIGGABLE },
4621 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4622 { ep_dont_run_into, EP_DONT_RUN_INTO },
4623 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4624 { ep_dont_touch, EP_DONT_TOUCH },
4625 { ep_indestructible, EP_INDESTRUCTIBLE },
4626 { ep_slippery, EP_SLIPPERY },
4627 { ep_can_change, EP_CAN_CHANGE },
4628 { ep_can_move, EP_CAN_MOVE },
4629 { ep_can_fall, EP_CAN_FALL },
4630 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4631 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4632 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4633 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4634 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4635 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4636 { ep_walkable_over, EP_WALKABLE_OVER },
4637 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4638 { ep_walkable_under, EP_WALKABLE_UNDER },
4639 { ep_passable_over, EP_PASSABLE_OVER },
4640 { ep_passable_inside, EP_PASSABLE_INSIDE },
4641 { ep_passable_under, EP_PASSABLE_UNDER },
4642 { ep_droppable, EP_DROPPABLE },
4643 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4644 { ep_pushable, EP_PUSHABLE },
4645 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4646 { ep_protected, EP_PROTECTED },
4647 { ep_throwable, EP_THROWABLE },
4648 { ep_can_explode, EP_CAN_EXPLODE },
4649 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4651 { ep_player, EP_PLAYER },
4652 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4653 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4654 { ep_switchable, EP_SWITCHABLE },
4655 { ep_bd_element, EP_BD_ELEMENT },
4656 { ep_sp_element, EP_SP_ELEMENT },
4657 { ep_sb_element, EP_SB_ELEMENT },
4659 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4660 { ep_food_penguin, EP_FOOD_PENGUIN },
4661 { ep_food_pig, EP_FOOD_PIG },
4662 { ep_historic_wall, EP_HISTORIC_WALL },
4663 { ep_historic_solid, EP_HISTORIC_SOLID },
4664 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4665 { ep_belt, EP_BELT },
4666 { ep_belt_active, EP_BELT_ACTIVE },
4667 { ep_belt_switch, EP_BELT_SWITCH },
4668 { ep_tube, EP_TUBE },
4669 { ep_acid_pool, EP_ACID_POOL },
4670 { ep_keygate, EP_KEYGATE },
4671 { ep_amoeboid, EP_AMOEBOID },
4672 { ep_amoebalive, EP_AMOEBALIVE },
4673 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4674 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4675 { ep_can_grow, EP_CAN_GROW },
4676 { ep_active_bomb, EP_ACTIVE_BOMB },
4677 { ep_inactive, EP_INACTIVE },
4679 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4681 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4683 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4684 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4686 { ep_obsolete, EP_OBSOLETE },
4693 /* always start with reliable default values (element has no properties) */
4694 /* (but never initialize clipboard elements after the very first time) */
4695 /* (to be able to use clipboard elements between several levels) */
4696 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4697 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4698 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4699 SET_PROPERTY(i, j, FALSE);
4701 /* set all base element properties from above array definitions */
4702 for (i = 0; element_properties[i].elements != NULL; i++)
4703 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4704 SET_PROPERTY((element_properties[i].elements)[j],
4705 element_properties[i].property, TRUE);
4707 /* copy properties to some elements that are only stored in level file */
4708 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4709 for (j = 0; copy_properties[j][0] != -1; j++)
4710 if (HAS_PROPERTY(copy_properties[j][0], i))
4711 for (k = 1; k <= 4; k++)
4712 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4714 /* set static element properties that are not listed in array definitions */
4715 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4716 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4718 clipboard_elements_initialized = TRUE;
4721 void InitElementPropertiesEngine(int engine_version)
4723 static int no_wall_properties[] =
4726 EP_COLLECTIBLE_ONLY,
4728 EP_DONT_COLLIDE_WITH,
4731 EP_CAN_SMASH_PLAYER,
4732 EP_CAN_SMASH_ENEMIES,
4733 EP_CAN_SMASH_EVERYTHING,
4738 EP_FOOD_DARK_YAMYAM,
4754 /* important: after initialization in InitElementPropertiesStatic(), the
4755 elements are not again initialized to a default value; therefore all
4756 changes have to make sure that they leave the element with a defined
4757 property (which means that conditional property changes must be set to
4758 a reliable default value before) */
4760 /* resolve group elements */
4761 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4762 ResolveGroupElement(EL_GROUP_START + i);
4764 /* set all special, combined or engine dependent element properties */
4765 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4767 /* do not change (already initialized) clipboard elements here */
4768 if (IS_CLIPBOARD_ELEMENT(i))
4771 /* ---------- INACTIVE ------------------------------------------------- */
4772 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4773 i <= EL_CHAR_END) ||
4774 (i >= EL_STEEL_CHAR_START &&
4775 i <= EL_STEEL_CHAR_END)));
4777 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4778 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4779 IS_WALKABLE_INSIDE(i) ||
4780 IS_WALKABLE_UNDER(i)));
4782 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4783 IS_PASSABLE_INSIDE(i) ||
4784 IS_PASSABLE_UNDER(i)));
4786 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4787 IS_PASSABLE_OVER(i)));
4789 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4790 IS_PASSABLE_INSIDE(i)));
4792 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4793 IS_PASSABLE_UNDER(i)));
4795 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4798 /* ---------- COLLECTIBLE ---------------------------------------------- */
4799 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4803 /* ---------- SNAPPABLE ------------------------------------------------ */
4804 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4805 IS_COLLECTIBLE(i) ||
4809 /* ---------- WALL ----------------------------------------------------- */
4810 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4812 for (j = 0; no_wall_properties[j] != -1; j++)
4813 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4814 i >= EL_FIRST_RUNTIME_UNREAL)
4815 SET_PROPERTY(i, EP_WALL, FALSE);
4817 if (IS_HISTORIC_WALL(i))
4818 SET_PROPERTY(i, EP_WALL, TRUE);
4820 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4821 if (engine_version < VERSION_IDENT(2,2,0,0))
4822 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4824 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4826 !IS_COLLECTIBLE(i)));
4828 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4829 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4830 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4832 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4833 IS_INDESTRUCTIBLE(i)));
4835 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4837 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4838 else if (engine_version < VERSION_IDENT(2,2,0,0))
4839 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4841 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4845 if (IS_CUSTOM_ELEMENT(i))
4847 /* these are additional properties which are initially false when set */
4849 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4851 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4852 if (DONT_COLLIDE_WITH(i))
4853 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4855 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4856 if (CAN_SMASH_EVERYTHING(i))
4857 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4858 if (CAN_SMASH_ENEMIES(i))
4859 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4862 /* ---------- CAN_SMASH ------------------------------------------------ */
4863 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4864 CAN_SMASH_ENEMIES(i) ||
4865 CAN_SMASH_EVERYTHING(i)));
4867 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4868 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4869 EXPLODES_BY_FIRE(i)));
4871 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4872 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4873 EXPLODES_SMASHED(i)));
4875 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4876 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4877 EXPLODES_IMPACT(i)));
4879 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4880 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4882 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4883 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4884 i == EL_BLACK_ORB));
4886 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4887 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4889 IS_CUSTOM_ELEMENT(i)));
4891 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4892 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4893 i == EL_SP_ELECTRON));
4895 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4896 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4897 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4898 getMoveIntoAcidProperty(&level, i));
4900 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4901 if (MAYBE_DONT_COLLIDE_WITH(i))
4902 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4903 getDontCollideWithProperty(&level, i));
4905 /* ---------- SP_PORT -------------------------------------------------- */
4906 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4907 IS_PASSABLE_INSIDE(i)));
4909 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4910 for (j = 0; j < level.num_android_clone_elements; j++)
4911 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4913 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4915 /* ---------- CAN_CHANGE ----------------------------------------------- */
4916 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4917 for (j = 0; j < element_info[i].num_change_pages; j++)
4918 if (element_info[i].change_page[j].can_change)
4919 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4921 /* ---------- HAS_ACTION ----------------------------------------------- */
4922 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4923 for (j = 0; j < element_info[i].num_change_pages; j++)
4924 if (element_info[i].change_page[j].has_action)
4925 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4927 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4928 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4931 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4933 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4934 element_info[i].crumbled[ACTION_DEFAULT] !=
4935 element_info[i].graphic[ACTION_DEFAULT]);
4937 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
4938 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4939 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
4942 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4943 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4944 IS_EDITOR_CASCADE_INACTIVE(i)));
4947 /* dynamically adjust element properties according to game engine version */
4949 static int ep_em_slippery_wall[] =
4954 EL_EXPANDABLE_WALL_HORIZONTAL,
4955 EL_EXPANDABLE_WALL_VERTICAL,
4956 EL_EXPANDABLE_WALL_ANY,
4957 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4958 EL_EXPANDABLE_STEELWALL_VERTICAL,
4959 EL_EXPANDABLE_STEELWALL_ANY,
4960 EL_EXPANDABLE_STEELWALL_GROWING,
4964 static int ep_em_explodes_by_fire[] =
4967 EL_EM_DYNAMITE_ACTIVE,
4972 /* special EM style gems behaviour */
4973 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4974 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4975 level.em_slippery_gems);
4977 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4978 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4979 (level.em_slippery_gems &&
4980 engine_version > VERSION_IDENT(2,0,1,0)));
4982 /* special EM style explosion behaviour regarding chain reactions */
4983 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4984 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4985 level.em_explodes_by_fire);
4988 /* this is needed because some graphics depend on element properties */
4989 if (game_status == GAME_MODE_PLAYING)
4990 InitElementGraphicInfo();
4993 void InitElementPropertiesAfterLoading(int engine_version)
4997 /* set some other uninitialized values of custom elements in older levels */
4998 if (engine_version < VERSION_IDENT(3,1,0,0))
5000 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
5002 int element = EL_CUSTOM_START + i;
5004 element_info[element].access_direction = MV_ALL_DIRECTIONS;
5006 element_info[element].explosion_delay = 17;
5007 element_info[element].ignition_delay = 8;
5012 void InitElementPropertiesGfxElement()
5016 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5018 struct ElementInfo *ei = &element_info[i];
5020 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
5024 static void InitGlobal()
5029 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
5031 /* check if element_name_info entry defined for each element in "main.h" */
5032 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
5033 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
5035 element_info[i].token_name = element_name_info[i].token_name;
5036 element_info[i].class_name = element_name_info[i].class_name;
5037 element_info[i].editor_description= element_name_info[i].editor_description;
5040 printf("%04d: %s\n", i, element_name_info[i].token_name);
5044 /* create hash from image config list */
5045 image_config_hash = newSetupFileHash();
5046 for (i = 0; image_config[i].token != NULL; i++)
5047 setHashEntry(image_config_hash,
5048 image_config[i].token,
5049 image_config[i].value);
5051 /* create hash from element token list */
5052 element_token_hash = newSetupFileHash();
5053 for (i = 0; element_name_info[i].token_name != NULL; i++)
5054 setHashEntry(element_token_hash,
5055 element_name_info[i].token_name,
5058 /* create hash from graphic token list */
5059 graphic_token_hash = newSetupFileHash();
5060 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
5061 if (strSuffix(image_config[i].value, ".pcx") ||
5062 strSuffix(image_config[i].value, ".wav") ||
5063 strEqual(image_config[i].value, UNDEFINED_FILENAME))
5064 setHashEntry(graphic_token_hash,
5065 image_config[i].token,
5066 int2str(graphic++, 0));
5068 /* create hash from font token list */
5069 font_token_hash = newSetupFileHash();
5070 for (i = 0; font_info[i].token_name != NULL; i++)
5071 setHashEntry(font_token_hash,
5072 font_info[i].token_name,
5075 /* always start with reliable default values (all elements) */
5076 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5077 ActiveElement[i] = i;
5079 /* now add all entries that have an active state (active elements) */
5080 for (i = 0; element_with_active_state[i].element != -1; i++)
5082 int element = element_with_active_state[i].element;
5083 int element_active = element_with_active_state[i].element_active;
5085 ActiveElement[element] = element_active;
5088 /* always start with reliable default values (all buttons) */
5089 for (i = 0; i < NUM_IMAGE_FILES; i++)
5090 ActiveButton[i] = i;
5092 /* now add all entries that have an active state (active buttons) */
5093 for (i = 0; button_with_active_state[i].button != -1; i++)
5095 int button = button_with_active_state[i].button;
5096 int button_active = button_with_active_state[i].button_active;
5098 ActiveButton[button] = button_active;
5101 /* always start with reliable default values (all fonts) */
5102 for (i = 0; i < NUM_FONTS; i++)
5105 /* now add all entries that have an active state (active fonts) */
5106 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
5108 int font = font_with_active_state[i].font_nr;
5109 int font_active = font_with_active_state[i].font_nr_active;
5111 ActiveFont[font] = font_active;
5114 global.autoplay_leveldir = NULL;
5115 global.convert_leveldir = NULL;
5116 global.create_images_dir = NULL;
5118 global.frames_per_second = 0;
5119 global.fps_slowdown = FALSE;
5120 global.fps_slowdown_factor = 1;
5122 global.border_status = GAME_MODE_MAIN;
5124 global.fading_status = GAME_MODE_MAIN;
5125 global.fading_type = TYPE_ENTER_MENU;
5128 global.use_envelope_request = FALSE; /* !!! MOVE TO ARTWORK CONFIG !!! */
5131 void Execute_Command(char *command)
5135 if (strEqual(command, "print graphicsinfo.conf"))
5137 printf("# You can configure additional/alternative image files here.\n");
5138 printf("# (The entries below are default and therefore commented out.)\n");
5140 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
5142 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5145 for (i = 0; image_config[i].token != NULL; i++)
5146 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
5147 image_config[i].value));
5151 else if (strEqual(command, "print soundsinfo.conf"))
5153 printf("# You can configure additional/alternative sound files here.\n");
5154 printf("# (The entries below are default and therefore commented out.)\n");
5156 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
5158 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5161 for (i = 0; sound_config[i].token != NULL; i++)
5162 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
5163 sound_config[i].value));
5167 else if (strEqual(command, "print musicinfo.conf"))
5169 printf("# You can configure additional/alternative music files here.\n");
5170 printf("# (The entries below are default and therefore commented out.)\n");
5172 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
5174 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5177 for (i = 0; music_config[i].token != NULL; i++)
5178 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
5179 music_config[i].value));
5183 else if (strEqual(command, "print editorsetup.conf"))
5185 printf("# You can configure your personal editor element list here.\n");
5186 printf("# (The entries below are default and therefore commented out.)\n");
5189 /* this is needed to be able to check element list for cascade elements */
5190 InitElementPropertiesStatic();
5191 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5193 PrintEditorElementList();
5197 else if (strEqual(command, "print helpanim.conf"))
5199 printf("# You can configure different element help animations here.\n");
5200 printf("# (The entries below are default and therefore commented out.)\n");
5203 for (i = 0; helpanim_config[i].token != NULL; i++)
5205 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
5206 helpanim_config[i].value));
5208 if (strEqual(helpanim_config[i].token, "end"))
5214 else if (strEqual(command, "print helptext.conf"))
5216 printf("# You can configure different element help text here.\n");
5217 printf("# (The entries below are default and therefore commented out.)\n");
5220 for (i = 0; helptext_config[i].token != NULL; i++)
5221 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
5222 helptext_config[i].value));
5226 else if (strPrefix(command, "dump level "))
5228 char *filename = &command[11];
5230 if (!fileExists(filename))
5231 Error(ERR_EXIT, "cannot open file '%s'", filename);
5233 LoadLevelFromFilename(&level, filename);
5238 else if (strPrefix(command, "dump tape "))
5240 char *filename = &command[10];
5242 if (!fileExists(filename))
5243 Error(ERR_EXIT, "cannot open file '%s'", filename);
5245 LoadTapeFromFilename(filename);
5250 else if (strPrefix(command, "autoplay "))
5252 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
5254 while (*str_ptr != '\0') /* continue parsing string */
5256 /* cut leading whitespace from string, replace it by string terminator */
5257 while (*str_ptr == ' ' || *str_ptr == '\t')
5260 if (*str_ptr == '\0') /* end of string reached */
5263 if (global.autoplay_leveldir == NULL) /* read level set string */
5265 global.autoplay_leveldir = str_ptr;
5266 global.autoplay_all = TRUE; /* default: play all tapes */
5268 for (i = 0; i < MAX_TAPES_PER_SET; i++)
5269 global.autoplay_level[i] = FALSE;
5271 else /* read level number string */
5273 int level_nr = atoi(str_ptr); /* get level_nr value */
5275 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5276 global.autoplay_level[level_nr] = TRUE;
5278 global.autoplay_all = FALSE;
5281 /* advance string pointer to the next whitespace (or end of string) */
5282 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5286 else if (strPrefix(command, "convert "))
5288 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
5289 char *str_ptr = strchr(str_copy, ' ');
5291 global.convert_leveldir = str_copy;
5292 global.convert_level_nr = -1;
5294 if (str_ptr != NULL) /* level number follows */
5296 *str_ptr++ = '\0'; /* terminate leveldir string */
5297 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
5300 else if (strPrefix(command, "create images "))
5302 #if defined(TARGET_SDL)
5303 global.create_images_dir = getStringCopy(&command[14]);
5305 if (access(global.create_images_dir, W_OK) != 0)
5306 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
5307 global.create_images_dir);
5309 Error(ERR_EXIT, "command only available for SDL target");
5314 #if defined(TARGET_SDL)
5315 else if (strEqual(command, "SDL_ListModes"))
5320 SDL_Init(SDL_INIT_VIDEO);
5322 /* get available fullscreen/hardware modes */
5323 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
5325 /* check if there are any modes available */
5328 printf("No modes available!\n");
5333 /* check if our resolution is restricted */
5334 if (modes == (SDL_Rect **)-1)
5336 printf("All resolutions available.\n");
5340 printf("Available Modes:\n");
5342 for(i = 0; modes[i]; i++)
5343 printf(" %d x %d\n", modes[i]->w, modes[i]->h);
5353 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
5357 static void InitSetup()
5359 LoadSetup(); /* global setup info */
5361 /* set some options from setup file */
5363 if (setup.options.verbose)
5364 options.verbose = TRUE;
5367 static void InitGameInfo()
5369 game.restart_level = FALSE;
5372 static void InitPlayerInfo()
5376 /* choose default local player */
5377 local_player = &stored_player[0];
5379 for (i = 0; i < MAX_PLAYERS; i++)
5380 stored_player[i].connected = FALSE;
5382 local_player->connected = TRUE;
5385 static void InitArtworkInfo()
5390 static char *get_string_in_brackets(char *string)
5392 char *string_in_brackets = checked_malloc(strlen(string) + 3);
5394 sprintf(string_in_brackets, "[%s]", string);
5396 return string_in_brackets;
5399 static char *get_level_id_suffix(int id_nr)
5401 char *id_suffix = checked_malloc(1 + 3 + 1);
5403 if (id_nr < 0 || id_nr > 999)
5406 sprintf(id_suffix, ".%03d", id_nr);
5412 static char *get_element_class_token(int element)
5414 char *element_class_name = element_info[element].class_name;
5415 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
5417 sprintf(element_class_token, "[%s]", element_class_name);
5419 return element_class_token;
5422 static char *get_action_class_token(int action)
5424 char *action_class_name = &element_action_info[action].suffix[1];
5425 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
5427 sprintf(action_class_token, "[%s]", action_class_name);
5429 return action_class_token;
5433 static void InitArtworkConfig()
5435 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
5436 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
5437 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
5438 static char *action_id_suffix[NUM_ACTIONS + 1];
5439 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5440 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5441 static char *level_id_suffix[MAX_LEVELS + 1];
5442 static char *dummy[1] = { NULL };
5443 static char *ignore_generic_tokens[] =
5449 static char **ignore_image_tokens;
5450 static char **ignore_sound_tokens;
5451 static char **ignore_music_tokens;
5452 int num_ignore_generic_tokens;
5453 int num_ignore_image_tokens;
5454 int num_ignore_sound_tokens;
5455 int num_ignore_music_tokens;
5458 /* dynamically determine list of generic tokens to be ignored */
5459 num_ignore_generic_tokens = 0;
5460 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5461 num_ignore_generic_tokens++;
5463 /* dynamically determine list of image tokens to be ignored */
5464 num_ignore_image_tokens = num_ignore_generic_tokens;
5465 for (i = 0; image_config_vars[i].token != NULL; i++)
5466 num_ignore_image_tokens++;
5467 ignore_image_tokens =
5468 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5469 for (i = 0; i < num_ignore_generic_tokens; i++)
5470 ignore_image_tokens[i] = ignore_generic_tokens[i];
5471 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5472 ignore_image_tokens[num_ignore_generic_tokens + i] =
5473 image_config_vars[i].token;
5474 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5476 /* dynamically determine list of sound tokens to be ignored */
5477 num_ignore_sound_tokens = num_ignore_generic_tokens;
5478 ignore_sound_tokens =
5479 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5480 for (i = 0; i < num_ignore_generic_tokens; i++)
5481 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5482 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5484 /* dynamically determine list of music tokens to be ignored */
5485 num_ignore_music_tokens = num_ignore_generic_tokens;
5486 ignore_music_tokens =
5487 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5488 for (i = 0; i < num_ignore_generic_tokens; i++)
5489 ignore_music_tokens[i] = ignore_generic_tokens[i];
5490 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5492 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5493 image_id_prefix[i] = element_info[i].token_name;
5494 for (i = 0; i < NUM_FONTS; i++)
5495 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5496 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
5498 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5499 sound_id_prefix[i] = element_info[i].token_name;
5500 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5501 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5502 get_string_in_brackets(element_info[i].class_name);
5503 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
5505 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5506 music_id_prefix[i] = music_prefix_info[i].prefix;
5507 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
5509 for (i = 0; i < NUM_ACTIONS; i++)
5510 action_id_suffix[i] = element_action_info[i].suffix;
5511 action_id_suffix[NUM_ACTIONS] = NULL;
5513 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5514 direction_id_suffix[i] = element_direction_info[i].suffix;
5515 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5517 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5518 special_id_suffix[i] = special_suffix_info[i].suffix;
5519 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5521 for (i = 0; i < MAX_LEVELS; i++)
5522 level_id_suffix[i] = get_level_id_suffix(i);
5523 level_id_suffix[MAX_LEVELS] = NULL;
5525 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5526 image_id_prefix, action_id_suffix, direction_id_suffix,
5527 special_id_suffix, ignore_image_tokens);
5528 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5529 sound_id_prefix, action_id_suffix, dummy,
5530 special_id_suffix, ignore_sound_tokens);
5531 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5532 music_id_prefix, special_id_suffix, level_id_suffix,
5533 dummy, ignore_music_tokens);
5536 static void InitMixer()
5543 void InitGfxBuffers()
5545 ReCreateBitmap(&bitmap_db_store, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5546 ReCreateBitmap(&bitmap_db_cross, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5547 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE, DEFAULT_DEPTH);
5548 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE, DEFAULT_DEPTH);
5549 ReCreateBitmap(&bitmap_db_door, 3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
5550 ReCreateBitmap(&bitmap_db_toons, FULL_SXSIZE, FULL_SYSIZE, DEFAULT_DEPTH);
5552 /* initialize screen properties */
5553 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5554 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5556 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5557 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5558 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5559 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5560 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5562 InitGfxBuffers_EM();
5563 InitGfxBuffers_SP();
5568 struct GraphicInfo *graphic_info_last = graphic_info;
5569 char *filename_font_initial = NULL;
5570 char *filename_anim_initial = NULL;
5571 Bitmap *bitmap_font_initial = NULL;
5575 /* determine settings for initial font (for displaying startup messages) */
5576 for (i = 0; image_config[i].token != NULL; i++)
5578 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5580 char font_token[128];
5583 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5584 len_font_token = strlen(font_token);
5586 if (strEqual(image_config[i].token, font_token))
5587 filename_font_initial = image_config[i].value;
5588 else if (strlen(image_config[i].token) > len_font_token &&
5589 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5591 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5592 font_initial[j].src_x = atoi(image_config[i].value);
5593 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5594 font_initial[j].src_y = atoi(image_config[i].value);
5595 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5596 font_initial[j].width = atoi(image_config[i].value);
5597 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5598 font_initial[j].height = atoi(image_config[i].value);
5603 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5605 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5606 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5609 if (filename_font_initial == NULL) /* should not happen */
5610 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5615 /* create additional image buffers for double-buffering and cross-fading */
5616 bitmap_db_store = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5617 bitmap_db_cross = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5618 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
5619 bitmap_db_panel = CreateBitmap(DXSIZE, DYSIZE, DEFAULT_DEPTH);
5620 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
5621 bitmap_db_toons = CreateBitmap(FULL_SXSIZE, FULL_SYSIZE, DEFAULT_DEPTH);
5623 /* initialize screen properties */
5624 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5625 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5627 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5628 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5629 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5630 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5633 InitGfxCustomArtworkInfo();
5635 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5637 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5638 font_initial[j].bitmap = bitmap_font_initial;
5640 InitFontGraphicInfo();
5642 font_height = getFontHeight(FC_RED);
5645 DrawInitText(getWindowTitleString(), 20, FC_YELLOW);
5647 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
5649 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
5650 DrawInitText(PROGRAM_WEBSITE_STRING, WIN_YSIZE - 20 - font_height, FC_RED);
5652 DrawInitText("Loading graphics", 120, FC_GREEN);
5656 /* initialize busy animation with default values */
5657 int parameter[NUM_GFX_ARGS];
5658 for (i = 0; i < NUM_GFX_ARGS; i++)
5659 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5660 image_config_suffix[i].token,
5661 image_config_suffix[i].type);
5663 for (i = 0; i < NUM_GFX_ARGS; i++)
5664 printf("::: '%s' => %d\n", image_config_suffix[i].token, parameter[i]);
5668 /* determine settings for busy animation (when displaying startup messages) */
5669 for (i = 0; image_config[i].token != NULL; i++)
5671 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5672 int len_anim_token = strlen(anim_token);
5674 if (strEqual(image_config[i].token, anim_token))
5675 filename_anim_initial = image_config[i].value;
5676 else if (strlen(image_config[i].token) > len_anim_token &&
5677 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5680 for (j = 0; image_config_suffix[j].token != NULL; j++)
5682 if (strEqual(&image_config[i].token[len_anim_token],
5683 image_config_suffix[j].token))
5685 get_graphic_parameter_value(image_config[i].value,
5686 image_config_suffix[j].token,
5687 image_config_suffix[j].type);
5690 if (strEqual(&image_config[i].token[len_anim_token], ".x"))
5691 anim_initial.src_x = atoi(image_config[i].value);
5692 else if (strEqual(&image_config[i].token[len_anim_token], ".y"))
5693 anim_initial.src_y = atoi(image_config[i].value);
5694 else if (strEqual(&image_config[i].token[len_anim_token], ".width"))
5695 anim_initial.width = atoi(image_config[i].value);
5696 else if (strEqual(&image_config[i].token[len_anim_token], ".height"))
5697 anim_initial.height = atoi(image_config[i].value);
5698 else if (strEqual(&image_config[i].token[len_anim_token], ".frames"))
5699 anim_initial.anim_frames = atoi(image_config[i].value);
5700 else if (strEqual(&image_config[i].token[len_anim_token],
5701 ".frames_per_line"))
5702 anim_initial.anim_frames_per_line = atoi(image_config[i].value);
5703 else if (strEqual(&image_config[i].token[len_anim_token], ".delay"))
5704 anim_initial.anim_delay = atoi(image_config[i].value);
5709 #if defined(CREATE_SPECIAL_EDITION_RND_JUE)
5710 filename_anim_initial = "loading.pcx";
5712 parameter[GFX_ARG_X] = 0;
5713 parameter[GFX_ARG_Y] = 0;
5714 parameter[GFX_ARG_WIDTH] = 128;
5715 parameter[GFX_ARG_HEIGHT] = 40;
5716 parameter[GFX_ARG_FRAMES] = 32;
5717 parameter[GFX_ARG_DELAY] = 4;
5718 parameter[GFX_ARG_FRAMES_PER_LINE] = ARG_UNDEFINED_VALUE;
5721 if (filename_anim_initial == NULL) /* should not happen */
5722 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5724 anim_initial.bitmap = LoadCustomImage(filename_anim_initial);
5726 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
5728 set_graphic_parameters_ext(0, parameter, anim_initial.bitmap);
5731 printf("::: INIT_GFX: anim_frames_per_line == %d [%d / %d] [%d, %d]\n",
5732 graphic_info[0].anim_frames_per_line,
5733 get_scaled_graphic_width(0),
5734 graphic_info[0].width,
5735 getOriginalImageWidthFromImageID(0),
5736 graphic_info[0].scale_up_factor);
5739 graphic_info = graphic_info_last;
5741 init.busy.width = anim_initial.width;
5742 init.busy.height = anim_initial.height;
5744 InitMenuDesignSettings_Static();
5745 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5747 /* use copy of busy animation to prevent change while reloading artwork */
5752 void RedrawBackground()
5754 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
5755 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
5757 redraw_mask = REDRAW_ALL;
5760 void InitGfxBackground()
5764 fieldbuffer = bitmap_db_field;
5765 SetDrawtoField(DRAW_BACKBUFFER);
5768 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5772 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
5773 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
5776 for (x = 0; x < MAX_BUF_XSIZE; x++)
5777 for (y = 0; y < MAX_BUF_YSIZE; y++)
5780 redraw_mask = REDRAW_ALL;
5783 static void InitLevelInfo()
5785 LoadLevelInfo(); /* global level info */
5786 LoadLevelSetup_LastSeries(); /* last played series info */
5787 LoadLevelSetup_SeriesInfo(); /* last played level info */
5790 static void InitLevelArtworkInfo()
5792 LoadLevelArtworkInfo();
5795 static void InitImages()
5797 print_timestamp_init("InitImages");
5800 printf("::: leveldir_current->identifier == '%s'\n",
5801 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5802 printf("::: leveldir_current->graphics_path == '%s'\n",
5803 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5804 printf("::: leveldir_current->graphics_set == '%s'\n",
5805 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5806 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5807 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5810 setLevelArtworkDir(artwork.gfx_first);
5813 printf("::: leveldir_current->identifier == '%s'\n",
5814 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5815 printf("::: leveldir_current->graphics_path == '%s'\n",
5816 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5817 printf("::: leveldir_current->graphics_set == '%s'\n",
5818 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5819 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5820 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5824 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5825 leveldir_current->identifier,
5826 artwork.gfx_current_identifier,
5827 artwork.gfx_current->identifier,
5828 leveldir_current->graphics_set,
5829 leveldir_current->graphics_path);
5832 UPDATE_BUSY_STATE();
5834 ReloadCustomImages();
5835 print_timestamp_time("ReloadCustomImages");
5837 UPDATE_BUSY_STATE();
5839 LoadCustomElementDescriptions();
5840 print_timestamp_time("LoadCustomElementDescriptions");
5842 UPDATE_BUSY_STATE();
5844 LoadMenuDesignSettings();
5845 print_timestamp_time("LoadMenuDesignSettings");
5847 UPDATE_BUSY_STATE();
5849 ReinitializeGraphics();
5850 print_timestamp_time("ReinitializeGraphics");
5852 UPDATE_BUSY_STATE();
5854 print_timestamp_done("InitImages");
5857 static void InitSound(char *identifier)
5859 print_timestamp_init("InitSound");
5861 if (identifier == NULL)
5862 identifier = artwork.snd_current->identifier;
5864 /* set artwork path to send it to the sound server process */
5865 setLevelArtworkDir(artwork.snd_first);
5867 InitReloadCustomSounds(identifier);
5868 print_timestamp_time("InitReloadCustomSounds");
5870 ReinitializeSounds();
5871 print_timestamp_time("ReinitializeSounds");
5873 print_timestamp_done("InitSound");
5876 static void InitMusic(char *identifier)
5878 print_timestamp_init("InitMusic");
5880 if (identifier == NULL)
5881 identifier = artwork.mus_current->identifier;
5883 /* set artwork path to send it to the sound server process */
5884 setLevelArtworkDir(artwork.mus_first);
5886 InitReloadCustomMusic(identifier);
5887 print_timestamp_time("InitReloadCustomMusic");
5889 ReinitializeMusic();
5890 print_timestamp_time("ReinitializeMusic");
5892 print_timestamp_done("InitMusic");
5895 void InitNetworkServer()
5897 #if defined(NETWORK_AVALIABLE)
5901 if (!options.network)
5904 #if defined(NETWORK_AVALIABLE)
5905 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5907 if (!ConnectToServer(options.server_host, options.server_port))
5908 Error(ERR_EXIT, "cannot connect to network game server");
5910 SendToServer_PlayerName(setup.player_name);
5911 SendToServer_ProtocolVersion();
5914 SendToServer_NrWanted(nr_wanted);
5918 static boolean CheckArtworkConfigForCustomElements(char *filename)
5920 SetupFileHash *setup_file_hash;
5921 boolean redefined_ce_found = FALSE;
5923 /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */
5925 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5927 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5929 char *token = HASH_ITERATION_TOKEN(itr);
5931 if (strPrefix(token, "custom_"))
5933 redefined_ce_found = TRUE;
5938 END_HASH_ITERATION(setup_file_hash, itr)
5940 freeSetupFileHash(setup_file_hash);
5943 return redefined_ce_found;
5946 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5948 char *filename_base, *filename_local;
5949 boolean redefined_ce_found = FALSE;
5951 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5954 printf("::: leveldir_current->identifier == '%s'\n",
5955 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5956 printf("::: leveldir_current->graphics_path == '%s'\n",
5957 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5958 printf("::: leveldir_current->graphics_set == '%s'\n",
5959 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5960 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5961 leveldir_current == NULL ? "[NULL]" :
5962 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5965 /* first look for special artwork configured in level series config */
5966 filename_base = getCustomArtworkLevelConfigFilename(type);
5969 printf("::: filename_base == '%s'\n", filename_base);
5972 if (fileExists(filename_base))
5973 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5975 filename_local = getCustomArtworkConfigFilename(type);
5978 printf("::: filename_local == '%s'\n", filename_local);
5981 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5982 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5985 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5988 return redefined_ce_found;
5991 static void InitOverrideArtwork()
5993 boolean redefined_ce_found = FALSE;
5995 /* to check if this level set redefines any CEs, do not use overriding */
5996 gfx.override_level_graphics = FALSE;
5997 gfx.override_level_sounds = FALSE;
5998 gfx.override_level_music = FALSE;
6000 /* now check if this level set has definitions for custom elements */
6001 if (setup.override_level_graphics == AUTO ||
6002 setup.override_level_sounds == AUTO ||
6003 setup.override_level_music == AUTO)
6004 redefined_ce_found =
6005 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
6006 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
6007 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
6010 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
6013 if (redefined_ce_found)
6015 /* this level set has CE definitions: change "AUTO" to "FALSE" */
6016 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
6017 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
6018 gfx.override_level_music = (setup.override_level_music == TRUE);
6022 /* this level set has no CE definitions: change "AUTO" to "TRUE" */
6023 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
6024 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
6025 gfx.override_level_music = (setup.override_level_music != FALSE);
6029 printf("::: => %d, %d, %d\n",
6030 gfx.override_level_graphics,
6031 gfx.override_level_sounds,
6032 gfx.override_level_music);
6036 static char *getNewArtworkIdentifier(int type)
6038 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
6039 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
6040 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
6041 static boolean initialized[3] = { FALSE, FALSE, FALSE };
6042 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
6044 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
6046 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
6048 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
6049 char *leveldir_identifier = leveldir_current->identifier;
6051 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
6052 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
6054 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
6056 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
6057 char *artwork_current_identifier;
6058 char *artwork_new_identifier = NULL; /* default: nothing has changed */
6060 /* leveldir_current may be invalid (level group, parent link) */
6061 if (!validLevelSeries(leveldir_current))
6064 /* 1st step: determine artwork set to be activated in descending order:
6065 --------------------------------------------------------------------
6066 1. setup artwork (when configured to override everything else)
6067 2. artwork set configured in "levelinfo.conf" of current level set
6068 (artwork in level directory will have priority when loading later)
6069 3. artwork in level directory (stored in artwork sub-directory)
6070 4. setup artwork (currently configured in setup menu) */
6072 if (setup_override_artwork)
6073 artwork_current_identifier = setup_artwork_set;
6074 else if (leveldir_artwork_set != NULL)
6075 artwork_current_identifier = leveldir_artwork_set;
6076 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
6077 artwork_current_identifier = leveldir_identifier;
6079 artwork_current_identifier = setup_artwork_set;
6082 /* 2nd step: check if it is really needed to reload artwork set
6083 ------------------------------------------------------------ */
6086 if (type == ARTWORK_TYPE_GRAPHICS)
6087 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
6088 artwork_new_identifier,
6089 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
6090 artwork_current_identifier,
6091 leveldir_current->graphics_set,
6092 leveldir_current->identifier);
6095 /* ---------- reload if level set and also artwork set has changed ------- */
6096 if (leveldir_current_identifier[type] != leveldir_identifier &&
6097 (last_has_level_artwork_set[type] || has_level_artwork_set))
6098 artwork_new_identifier = artwork_current_identifier;
6100 leveldir_current_identifier[type] = leveldir_identifier;
6101 last_has_level_artwork_set[type] = has_level_artwork_set;
6104 if (type == ARTWORK_TYPE_GRAPHICS)
6105 printf("::: 1: '%s'\n", artwork_new_identifier);
6108 /* ---------- reload if "override artwork" setting has changed ----------- */
6109 if (last_override_level_artwork[type] != setup_override_artwork)
6110 artwork_new_identifier = artwork_current_identifier;
6112 last_override_level_artwork[type] = setup_override_artwork;
6115 if (type == ARTWORK_TYPE_GRAPHICS)
6116 printf("::: 2: '%s'\n", artwork_new_identifier);
6119 /* ---------- reload if current artwork identifier has changed ----------- */
6120 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
6121 artwork_current_identifier))
6122 artwork_new_identifier = artwork_current_identifier;
6124 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
6127 if (type == ARTWORK_TYPE_GRAPHICS)
6128 printf("::: 3: '%s'\n", artwork_new_identifier);
6131 /* ---------- do not reload directly after starting ---------------------- */
6132 if (!initialized[type])
6133 artwork_new_identifier = NULL;
6135 initialized[type] = TRUE;
6138 if (type == ARTWORK_TYPE_GRAPHICS)
6139 printf("::: 4: '%s'\n", artwork_new_identifier);
6143 if (type == ARTWORK_TYPE_GRAPHICS)
6144 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
6145 artwork.gfx_current_identifier, artwork_current_identifier,
6146 artwork.gfx_current->identifier, leveldir_current->graphics_set,
6147 artwork_new_identifier);
6150 return artwork_new_identifier;
6153 void ReloadCustomArtwork(int force_reload)
6155 int last_game_status = game_status; /* save current game status */
6156 char *gfx_new_identifier;
6157 char *snd_new_identifier;
6158 char *mus_new_identifier;
6159 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
6160 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
6161 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
6162 boolean reload_needed;
6164 InitOverrideArtwork();
6166 force_reload_gfx |= AdjustGraphicsForEMC();
6168 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
6169 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
6170 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
6172 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
6173 snd_new_identifier != NULL || force_reload_snd ||
6174 mus_new_identifier != NULL || force_reload_mus);
6179 print_timestamp_init("ReloadCustomArtwork");
6181 game_status = GAME_MODE_LOADING;
6183 FadeOut(REDRAW_ALL);
6186 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6188 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
6190 print_timestamp_time("ClearRectangle");
6193 printf("::: fading in ... %d\n", fading.fade_mode);
6197 printf("::: done\n");
6200 if (gfx_new_identifier != NULL || force_reload_gfx)
6203 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
6204 artwork.gfx_current_identifier,
6206 artwork.gfx_current->identifier,
6207 leveldir_current->graphics_set);
6211 print_timestamp_time("InitImages");
6214 if (snd_new_identifier != NULL || force_reload_snd)
6216 InitSound(snd_new_identifier);
6217 print_timestamp_time("InitSound");
6220 if (mus_new_identifier != NULL || force_reload_mus)
6222 InitMusic(mus_new_identifier);
6223 print_timestamp_time("InitMusic");
6226 game_status = last_game_status; /* restore current game status */
6228 init_last = init; /* switch to new busy animation */
6231 printf("::: ----------------DELAY 1 ...\n");
6236 printf("::: FadeOut @ ReloadCustomArtwork ...\n");
6238 FadeOut(REDRAW_ALL);
6240 printf("::: FadeOut @ ReloadCustomArtwork done\n");
6245 /* force redraw of (open or closed) door graphics */
6246 SetDoorState(DOOR_OPEN_ALL);
6247 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
6252 FadeSetEnterScreen();
6253 FadeSkipNextFadeOut();
6254 // FadeSetDisabled();
6259 fading = fading_none;
6264 redraw_mask = REDRAW_ALL;
6267 print_timestamp_done("ReloadCustomArtwork");
6270 void KeyboardAutoRepeatOffUnlessAutoplay()
6272 if (global.autoplay_leveldir == NULL)
6273 KeyboardAutoRepeatOff();
6277 /* ========================================================================= */
6279 /* ========================================================================= */
6283 print_timestamp_init("OpenAll");
6285 game_status = GAME_MODE_LOADING;
6291 InitGlobal(); /* initialize some global variables */
6293 print_timestamp_time("[init global stuff]");
6295 if (options.execute_command)
6296 Execute_Command(options.execute_command);
6298 if (options.serveronly)
6300 #if defined(PLATFORM_UNIX)
6301 NetworkServer(options.server_port, options.serveronly);
6303 Error(ERR_WARN, "networking only supported in Unix version");
6306 exit(0); /* never reached, server loops forever */
6311 print_timestamp_time("[init setup/config stuff (1)]");
6314 print_timestamp_time("[init setup/config stuff (2)]");
6316 print_timestamp_time("[init setup/config stuff (3)]");
6317 InitArtworkInfo(); /* needed before loading gfx, sound & music */
6318 print_timestamp_time("[init setup/config stuff (4)]");
6319 InitArtworkConfig(); /* needed before forking sound child process */
6320 print_timestamp_time("[init setup/config stuff (5)]");
6322 print_timestamp_time("[init setup/config stuff (6)]");
6328 InitRND(NEW_RANDOMIZE);
6329 InitSimpleRandom(NEW_RANDOMIZE);
6333 print_timestamp_time("[init setup/config stuff]");
6336 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
6338 InitEventFilter(FilterMouseMotionEvents);
6340 print_timestamp_time("[init video stuff]");
6342 InitElementPropertiesStatic();
6343 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
6344 InitElementPropertiesGfxElement();
6346 print_timestamp_time("[init element properties stuff]");
6350 print_timestamp_time("InitGfx");
6353 print_timestamp_time("InitLevelInfo");
6355 InitLevelArtworkInfo();
6356 print_timestamp_time("InitLevelArtworkInfo");
6358 InitOverrideArtwork(); /* needs to know current level directory */
6359 print_timestamp_time("InitOverrideArtwork");
6361 InitImages(); /* needs to know current level directory */
6362 print_timestamp_time("InitImages");
6364 InitSound(NULL); /* needs to know current level directory */
6365 print_timestamp_time("InitSound");
6367 InitMusic(NULL); /* needs to know current level directory */
6368 print_timestamp_time("InitMusic");
6370 InitGfxBackground();
6380 if (global.autoplay_leveldir)
6385 else if (global.convert_leveldir)
6390 else if (global.create_images_dir)
6392 CreateLevelSketchImages();
6396 game_status = GAME_MODE_MAIN;
6399 FadeSetEnterScreen();
6400 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
6401 FadeSkipNextFadeOut();
6402 // FadeSetDisabled();
6404 fading = fading_none;
6407 print_timestamp_time("[post-artwork]");
6409 print_timestamp_done("OpenAll");
6413 InitNetworkServer();
6416 void CloseAllAndExit(int exit_value)
6421 CloseAudio(); /* called after freeing sounds (needed for SDL) */
6433 #if defined(TARGET_SDL)
6434 if (network_server) /* terminate network server */
6435 SDL_KillThread(server_thread);
6438 CloseVideoDisplay();
6439 ClosePlatformDependentStuff();
6441 if (exit_value != 0)
6442 NotifyUserAboutErrorFile();