1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2006 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
14 #include "libgame/libgame.h"
29 #include "conf_e2g.c" /* include auto-generated data structure definitions */
30 #include "conf_esg.c" /* include auto-generated data structure definitions */
31 #include "conf_e2s.c" /* include auto-generated data structure definitions */
32 #include "conf_fnt.c" /* include auto-generated data structure definitions */
33 #include "conf_g2s.c" /* include auto-generated data structure definitions */
34 #include "conf_g2m.c" /* include auto-generated data structure definitions */
35 #include "conf_act.c" /* include auto-generated data structure definitions */
38 #define CONFIG_TOKEN_FONT_INITIAL "font.initial"
39 #define CONFIG_TOKEN_GLOBAL_BUSY "global.busy"
41 #define DEBUG_PRINT_INIT_TIMESTAMPS TRUE
42 #define DEBUG_PRINT_INIT_TIMESTAMPS_DEPTH 1
45 static struct FontBitmapInfo font_initial[NUM_INITIAL_FONTS];
46 static struct GraphicInfo anim_initial;
48 static int copy_properties[][5] =
52 EL_BUG_LEFT, EL_BUG_RIGHT,
53 EL_BUG_UP, EL_BUG_DOWN
57 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
58 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
62 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
63 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
67 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
68 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
72 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
73 EL_PACMAN_UP, EL_PACMAN_DOWN
77 EL_YAMYAM_LEFT, EL_YAMYAM_RIGHT,
78 EL_YAMYAM_UP, EL_YAMYAM_DOWN
82 EL_MOLE_LEFT, EL_MOLE_RIGHT,
83 EL_MOLE_UP, EL_MOLE_DOWN
92 static void print_timestamp_ext(char *message, char *mode)
95 #if DEBUG_PRINT_INIT_TIMESTAMPS
96 static char *debug_message = NULL;
97 static char *last_message = NULL;
98 static int counter_nr = 0;
99 int max_depth = DEBUG_PRINT_INIT_TIMESTAMPS_DEPTH;
101 checked_free(debug_message);
102 debug_message = getStringCat3(mode, " ", message);
104 if (strEqual(mode, "INIT"))
106 debug_print_timestamp(counter_nr, NULL);
108 if (counter_nr + 1 < max_depth)
109 debug_print_timestamp(counter_nr, debug_message);
113 debug_print_timestamp(counter_nr, NULL);
115 else if (strEqual(mode, "DONE"))
119 if (counter_nr + 1 < max_depth ||
120 (counter_nr == 0 && max_depth == 1))
122 last_message = message;
124 if (counter_nr == 0 && max_depth == 1)
126 checked_free(debug_message);
127 debug_message = getStringCat3("TIME", " ", message);
130 debug_print_timestamp(counter_nr, debug_message);
133 else if (!strEqual(mode, "TIME") ||
134 !strEqual(message, last_message))
136 if (counter_nr < max_depth)
137 debug_print_timestamp(counter_nr, debug_message);
143 static void print_timestamp_init(char *message)
145 print_timestamp_ext(message, "INIT");
148 static void print_timestamp_time(char *message)
150 print_timestamp_ext(message, "TIME");
153 static void print_timestamp_done(char *message)
155 print_timestamp_ext(message, "DONE");
160 struct GraphicInfo *graphic_info_last = graphic_info;
162 static unsigned long action_delay = 0;
163 unsigned long action_delay_value = GameFrameDelay;
164 int sync_frame = FrameCounter;
167 if (game_status != GAME_MODE_LOADING)
170 if (anim_initial.bitmap == NULL || window == NULL)
173 if (!DelayReached(&action_delay, action_delay_value))
178 static unsigned long last_counter = -1;
179 unsigned long current_counter = Counter();
180 unsigned long delay = current_counter - last_counter;
182 if (last_counter != -1 && delay > action_delay_value + 5)
183 printf("::: DrawInitAnim: DELAY TOO LONG: %ld\n", delay);
185 last_counter = current_counter;
189 x = ALIGNED_TEXT_XPOS(&init_last.busy);
190 y = ALIGNED_TEXT_YPOS(&init_last.busy);
192 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
196 static boolean done = FALSE;
199 printf("::: %d, %d, %d, %d => %d, %d [%d, %d] [%d, %d]\n",
200 init.busy.x, init.busy.y,
201 init.busy.align, init.busy.valign,
203 graphic_info[graphic].width,
204 graphic_info[graphic].height,
205 sync_frame, anim_initial.anim_delay);
211 if (sync_frame % anim_initial.anim_delay == 0)
216 int width = graphic_info[graphic].width;
217 int height = graphic_info[graphic].height;
218 int frame = getGraphicAnimationFrame(graphic, sync_frame);
220 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
221 BlitBitmap(src_bitmap, window, src_x, src_y, width, height, x, y);
223 /* !!! this can only draw TILEX/TILEY size animations !!! */
224 DrawGraphicAnimationExt(window, x, y, graphic, sync_frame, NO_MASKING);
228 graphic_info = graphic_info_last;
235 FreeLevelEditorGadgets();
244 static boolean gadgets_initialized = FALSE;
246 if (gadgets_initialized)
249 CreateLevelEditorGadgets();
253 CreateScreenGadgets();
255 InitGadgetsSoundCallback(PlaySoundActivating, PlaySoundSelecting);
257 gadgets_initialized = TRUE;
260 inline void InitElementSmallImagesScaledUp(int graphic)
263 struct FileInfo *fi = getImageListEntryFromImageID(graphic);
265 printf("::: '%s' -> '%s'\n", fi->token, fi->filename);
268 CreateImageWithSmallImages(graphic, graphic_info[graphic].scale_up_factor);
271 void InitElementSmallImages()
273 static int special_graphics[] =
275 IMG_EDITOR_ELEMENT_BORDER,
276 IMG_EDITOR_ELEMENT_BORDER_INPUT,
277 IMG_EDITOR_CASCADE_LIST,
278 IMG_EDITOR_CASCADE_LIST_ACTIVE,
281 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
282 int num_property_mappings = getImageListPropertyMappingSize();
285 /* initialize normal images from static configuration */
286 for (i = 0; element_to_graphic[i].element > -1; i++)
287 InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
289 /* initialize special images from static configuration */
290 for (i = 0; element_to_special_graphic[i].element > -1; i++)
291 InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
293 /* initialize images from dynamic configuration (may be elements or other) */
294 for (i = 0; i < num_property_mappings; i++)
295 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
297 /* initialize special images from above list (non-element images) */
298 for (i = 0; special_graphics[i] > -1; i++)
299 InitElementSmallImagesScaledUp(special_graphics[i]);
302 void InitScaledImages()
306 /* scale normal images from static configuration, if not already scaled */
307 for (i = 0; i < NUM_IMAGE_FILES; i++)
308 ScaleImage(i, graphic_info[i].scale_up_factor);
312 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
313 void SetBitmaps_EM(Bitmap **em_bitmap)
315 em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
316 em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].bitmap;
321 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
322 void SetBitmaps_SP(Bitmap **sp_bitmap)
324 *sp_bitmap = graphic_info[IMG_SP_OBJECTS].bitmap;
328 static int getFontBitmapID(int font_nr)
332 /* (special case: do not use special font for GAME_MODE_LOADING) */
333 if (game_status >= GAME_MODE_TITLE_INITIAL &&
334 game_status <= GAME_MODE_PSEUDO_PREVIEW)
335 special = game_status;
336 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
337 special = GFX_SPECIAL_ARG_MAIN;
339 else if (game_status == GAME_MODE_PLAYING)
340 special = GFX_SPECIAL_ARG_DOOR;
347 font_info[font_nr].token_name,
348 special_suffix_info[special].suffix);
353 return font_info[font_nr].special_bitmap_id[special];
358 static int getFontFromToken(char *token)
361 char *value = getHashEntry(font_token_hash, token);
368 /* !!! OPTIMIZE THIS BY USING HASH !!! */
369 for (i = 0; i < NUM_FONTS; i++)
370 if (strEqual(token, font_info[i].token_name))
374 /* if font not found, use reliable default value */
375 return FONT_INITIAL_1;
378 void InitFontGraphicInfo()
380 static struct FontBitmapInfo *font_bitmap_info = NULL;
381 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
382 int num_property_mappings = getImageListPropertyMappingSize();
383 int num_font_bitmaps = NUM_FONTS;
386 if (graphic_info == NULL) /* still at startup phase */
388 InitFontInfo(font_initial, NUM_INITIAL_FONTS,
389 getFontBitmapID, getFontFromToken);
394 /* ---------- initialize font graphic definitions ---------- */
396 /* always start with reliable default values (normal font graphics) */
397 for (i = 0; i < NUM_FONTS; i++)
398 font_info[i].graphic = IMG_FONT_INITIAL_1;
400 /* initialize normal font/graphic mapping from static configuration */
401 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
403 int font_nr = font_to_graphic[i].font_nr;
404 int special = font_to_graphic[i].special;
405 int graphic = font_to_graphic[i].graphic;
410 font_info[font_nr].graphic = graphic;
413 /* always start with reliable default values (special font graphics) */
414 for (i = 0; i < NUM_FONTS; i++)
416 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
418 font_info[i].special_graphic[j] = font_info[i].graphic;
419 font_info[i].special_bitmap_id[j] = i;
423 /* initialize special font/graphic mapping from static configuration */
424 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
426 int font_nr = font_to_graphic[i].font_nr;
427 int special = font_to_graphic[i].special;
428 int graphic = font_to_graphic[i].graphic;
429 int base_graphic = font2baseimg(font_nr);
431 if (IS_SPECIAL_GFX_ARG(special))
433 boolean base_redefined =
434 getImageListEntryFromImageID(base_graphic)->redefined;
435 boolean special_redefined =
436 getImageListEntryFromImageID(graphic)->redefined;
437 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
439 /* if the base font ("font.title_1", for example) has been redefined,
440 but not the special font ("font.title_1.LEVELS", for example), do not
441 use an existing (in this case considered obsolete) special font
442 anymore, but use the automatically determined default font */
443 /* special case: cloned special fonts must be explicitly redefined,
444 but are not automatically redefined by redefining base font */
445 if (base_redefined && !special_redefined && !special_cloned)
448 font_info[font_nr].special_graphic[special] = graphic;
449 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
454 /* initialize special font/graphic mapping from dynamic configuration */
455 for (i = 0; i < num_property_mappings; i++)
457 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
458 int special = property_mapping[i].ext3_index;
459 int graphic = property_mapping[i].artwork_index;
464 if (IS_SPECIAL_GFX_ARG(special))
466 font_info[font_nr].special_graphic[special] = graphic;
467 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
472 /* correct special font/graphic mapping for cloned fonts for downwards
473 compatibility of PREVIEW fonts -- this is only needed for implicit
474 redefinition of special font by redefined base font, and only if other
475 fonts are cloned from this special font (like in the "Zelda" level set) */
476 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
478 int font_nr = font_to_graphic[i].font_nr;
479 int special = font_to_graphic[i].special;
480 int graphic = font_to_graphic[i].graphic;
482 if (IS_SPECIAL_GFX_ARG(special))
484 boolean special_redefined =
485 getImageListEntryFromImageID(graphic)->redefined;
486 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
488 if (special_cloned && !special_redefined)
492 for (j = 0; font_to_graphic[j].font_nr > -1; j++)
494 int font_nr2 = font_to_graphic[j].font_nr;
495 int special2 = font_to_graphic[j].special;
496 int graphic2 = font_to_graphic[j].graphic;
498 if (IS_SPECIAL_GFX_ARG(special2) &&
499 graphic2 == graphic_info[graphic].clone_from)
501 font_info[font_nr].special_graphic[special] =
502 font_info[font_nr2].special_graphic[special2];
503 font_info[font_nr].special_bitmap_id[special] =
504 font_info[font_nr2].special_bitmap_id[special2];
511 /* reset non-redefined ".active" font graphics if normal font is redefined */
512 /* (this different treatment is needed because normal and active fonts are
513 independently defined ("active" is not a property of font definitions!) */
514 for (i = 0; i < NUM_FONTS; i++)
516 int font_nr_base = i;
517 int font_nr_active = FONT_ACTIVE(font_nr_base);
519 /* check only those fonts with exist as normal and ".active" variant */
520 if (font_nr_base != font_nr_active)
522 int base_graphic = font_info[font_nr_base].graphic;
523 int active_graphic = font_info[font_nr_active].graphic;
524 boolean base_redefined =
525 getImageListEntryFromImageID(base_graphic)->redefined;
526 boolean active_redefined =
527 getImageListEntryFromImageID(active_graphic)->redefined;
529 /* if the base font ("font.menu_1", for example) has been redefined,
530 but not the active font ("font.menu_1.active", for example), do not
531 use an existing (in this case considered obsolete) active font
532 anymore, but use the automatically determined default font */
533 if (base_redefined && !active_redefined)
534 font_info[font_nr_active].graphic = base_graphic;
536 /* now also check each "special" font (which may be the same as above) */
537 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
539 int base_graphic = font_info[font_nr_base].special_graphic[j];
540 int active_graphic = font_info[font_nr_active].special_graphic[j];
541 boolean base_redefined =
542 getImageListEntryFromImageID(base_graphic)->redefined;
543 boolean active_redefined =
544 getImageListEntryFromImageID(active_graphic)->redefined;
546 /* same as above, but check special graphic definitions, for example:
547 redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN" */
548 if (base_redefined && !active_redefined)
550 font_info[font_nr_active].special_graphic[j] =
551 font_info[font_nr_base].special_graphic[j];
552 font_info[font_nr_active].special_bitmap_id[j] =
553 font_info[font_nr_base].special_bitmap_id[j];
559 /* ---------- initialize font bitmap array ---------- */
561 if (font_bitmap_info != NULL)
562 FreeFontInfo(font_bitmap_info);
565 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
567 /* ---------- initialize font bitmap definitions ---------- */
569 for (i = 0; i < NUM_FONTS; i++)
571 if (i < NUM_INITIAL_FONTS)
573 font_bitmap_info[i] = font_initial[i];
577 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
579 int font_bitmap_id = font_info[i].special_bitmap_id[j];
580 int graphic = font_info[i].special_graphic[j];
582 /* set 'graphic_info' for font entries, if uninitialized (guessed) */
583 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
585 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
586 graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
589 /* copy font relevant information from graphics information */
590 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
591 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
592 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
593 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
594 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
596 font_bitmap_info[font_bitmap_id].draw_xoffset =
597 graphic_info[graphic].draw_xoffset;
598 font_bitmap_info[font_bitmap_id].draw_yoffset =
599 graphic_info[graphic].draw_yoffset;
601 font_bitmap_info[font_bitmap_id].num_chars =
602 graphic_info[graphic].anim_frames;
603 font_bitmap_info[font_bitmap_id].num_chars_per_line =
604 graphic_info[graphic].anim_frames_per_line;
608 InitFontInfo(font_bitmap_info, num_font_bitmaps,
609 getFontBitmapID, getFontFromToken);
612 void InitElementGraphicInfo()
614 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
615 int num_property_mappings = getImageListPropertyMappingSize();
618 if (graphic_info == NULL) /* still at startup phase */
621 /* set values to -1 to identify later as "uninitialized" values */
622 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
624 for (act = 0; act < NUM_ACTIONS; act++)
626 element_info[i].graphic[act] = -1;
627 element_info[i].crumbled[act] = -1;
629 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
631 element_info[i].direction_graphic[act][dir] = -1;
632 element_info[i].direction_crumbled[act][dir] = -1;
639 /* initialize normal element/graphic mapping from static configuration */
640 for (i = 0; element_to_graphic[i].element > -1; i++)
642 int element = element_to_graphic[i].element;
643 int action = element_to_graphic[i].action;
644 int direction = element_to_graphic[i].direction;
645 boolean crumbled = element_to_graphic[i].crumbled;
646 int graphic = element_to_graphic[i].graphic;
647 int base_graphic = el2baseimg(element);
649 if (graphic_info[graphic].bitmap == NULL)
652 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
655 boolean base_redefined =
656 getImageListEntryFromImageID(base_graphic)->redefined;
657 boolean act_dir_redefined =
658 getImageListEntryFromImageID(graphic)->redefined;
660 /* if the base graphic ("emerald", for example) has been redefined,
661 but not the action graphic ("emerald.falling", for example), do not
662 use an existing (in this case considered obsolete) action graphic
663 anymore, but use the automatically determined default graphic */
664 if (base_redefined && !act_dir_redefined)
669 action = ACTION_DEFAULT;
674 element_info[element].direction_crumbled[action][direction] = graphic;
676 element_info[element].crumbled[action] = graphic;
681 element_info[element].direction_graphic[action][direction] = graphic;
683 element_info[element].graphic[action] = graphic;
687 /* initialize normal element/graphic mapping from dynamic configuration */
688 for (i = 0; i < num_property_mappings; i++)
690 int element = property_mapping[i].base_index;
691 int action = property_mapping[i].ext1_index;
692 int direction = property_mapping[i].ext2_index;
693 int special = property_mapping[i].ext3_index;
694 int graphic = property_mapping[i].artwork_index;
695 boolean crumbled = FALSE;
698 if ((element == EL_EM_DYNAMITE ||
699 element == EL_EM_DYNAMITE_ACTIVE) &&
700 action == ACTION_ACTIVE &&
701 (special == GFX_SPECIAL_ARG_EDITOR ||
702 special == GFX_SPECIAL_ARG_PANEL))
703 printf("::: DYNAMIC: %d, %d, %d -> %d\n",
704 element, action, special, graphic);
707 if (special == GFX_SPECIAL_ARG_CRUMBLED)
713 if (graphic_info[graphic].bitmap == NULL)
716 if (element >= MAX_NUM_ELEMENTS || special != -1)
720 action = ACTION_DEFAULT;
725 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
726 element_info[element].direction_crumbled[action][dir] = -1;
729 element_info[element].direction_crumbled[action][direction] = graphic;
731 element_info[element].crumbled[action] = graphic;
736 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
737 element_info[element].direction_graphic[action][dir] = -1;
740 element_info[element].direction_graphic[action][direction] = graphic;
742 element_info[element].graphic[action] = graphic;
746 /* now copy all graphics that are defined to be cloned from other graphics */
747 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
749 int graphic = element_info[i].graphic[ACTION_DEFAULT];
750 int crumbled_like, diggable_like;
755 crumbled_like = graphic_info[graphic].crumbled_like;
756 diggable_like = graphic_info[graphic].diggable_like;
758 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
760 for (act = 0; act < NUM_ACTIONS; act++)
761 element_info[i].crumbled[act] =
762 element_info[crumbled_like].crumbled[act];
763 for (act = 0; act < NUM_ACTIONS; act++)
764 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
765 element_info[i].direction_crumbled[act][dir] =
766 element_info[crumbled_like].direction_crumbled[act][dir];
769 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
771 element_info[i].graphic[ACTION_DIGGING] =
772 element_info[diggable_like].graphic[ACTION_DIGGING];
773 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
774 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
775 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
780 /* set hardcoded definitions for some runtime elements without graphic */
781 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
785 /* set hardcoded definitions for some internal elements without graphic */
786 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
788 if (IS_EDITOR_CASCADE_INACTIVE(i))
789 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
790 else if (IS_EDITOR_CASCADE_ACTIVE(i))
791 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
795 /* now set all undefined/invalid graphics to -1 to set to default after it */
796 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
798 for (act = 0; act < NUM_ACTIONS; act++)
802 graphic = element_info[i].graphic[act];
803 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
804 element_info[i].graphic[act] = -1;
806 graphic = element_info[i].crumbled[act];
807 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
808 element_info[i].crumbled[act] = -1;
810 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
812 graphic = element_info[i].direction_graphic[act][dir];
813 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
814 element_info[i].direction_graphic[act][dir] = -1;
816 graphic = element_info[i].direction_crumbled[act][dir];
817 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
818 element_info[i].direction_crumbled[act][dir] = -1;
825 /* adjust graphics with 2nd tile for movement according to direction
826 (do this before correcting '-1' values to minimize calculations) */
827 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
829 for (act = 0; act < NUM_ACTIONS; act++)
831 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
833 int graphic = element_info[i].direction_graphic[act][dir];
834 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
836 if (act == ACTION_FALLING) /* special case */
837 graphic = element_info[i].graphic[act];
840 graphic_info[graphic].double_movement &&
841 graphic_info[graphic].swap_double_tiles != 0)
843 struct GraphicInfo *g = &graphic_info[graphic];
844 int src_x_front = g->src_x;
845 int src_y_front = g->src_y;
846 int src_x_back = g->src_x + g->offset2_x;
847 int src_y_back = g->src_y + g->offset2_y;
848 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
850 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
851 src_y_front < src_y_back);
852 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
853 boolean swap_movement_tiles_autodetected =
854 (!frames_are_ordered_diagonally &&
855 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
856 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
857 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
858 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
861 /* swap frontside and backside graphic tile coordinates, if needed */
862 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
864 /* get current (wrong) backside tile coordinates */
865 getGraphicSourceExt(graphic, 0, &dummy, &src_x_back, &src_y_back,
868 /* set frontside tile coordinates to backside tile coordinates */
869 g->src_x = src_x_back;
870 g->src_y = src_y_back;
872 /* invert tile offset to point to new backside tile coordinates */
876 /* do not swap front and backside tiles again after correction */
877 g->swap_double_tiles = 0;
886 /* now set all '-1' values to element specific default values */
887 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
889 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
890 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
891 int default_direction_graphic[NUM_DIRECTIONS_FULL];
892 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
894 if (default_graphic == -1)
895 default_graphic = IMG_UNKNOWN;
897 if (default_crumbled == -1)
898 default_crumbled = default_graphic;
900 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
901 if (default_crumbled == -1)
902 default_crumbled = IMG_EMPTY;
905 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
907 default_direction_graphic[dir] =
908 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
909 default_direction_crumbled[dir] =
910 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
912 if (default_direction_graphic[dir] == -1)
913 default_direction_graphic[dir] = default_graphic;
915 if (default_direction_crumbled[dir] == -1)
916 default_direction_crumbled[dir] = default_direction_graphic[dir];
918 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
919 if (default_direction_crumbled[dir] == -1)
920 default_direction_crumbled[dir] = default_crumbled;
924 for (act = 0; act < NUM_ACTIONS; act++)
926 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
927 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
928 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
929 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
930 act == ACTION_TURNING_FROM_RIGHT ||
931 act == ACTION_TURNING_FROM_UP ||
932 act == ACTION_TURNING_FROM_DOWN);
934 /* generic default action graphic (defined by "[default]" directive) */
935 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
936 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
937 int default_remove_graphic = IMG_EMPTY;
939 if (act_remove && default_action_graphic != -1)
940 default_remove_graphic = default_action_graphic;
942 /* look for special default action graphic (classic game specific) */
943 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
944 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
945 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
946 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
947 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
948 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
950 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
951 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
952 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
953 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
954 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
955 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
958 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
959 /* !!! make this better !!! */
960 if (i == EL_EMPTY_SPACE)
962 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
963 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
967 if (default_action_graphic == -1)
968 default_action_graphic = default_graphic;
970 if (default_action_crumbled == -1)
971 default_action_crumbled = default_action_graphic;
973 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
974 if (default_action_crumbled == -1)
975 default_action_crumbled = default_crumbled;
978 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
980 /* use action graphic as the default direction graphic, if undefined */
981 int default_action_direction_graphic = element_info[i].graphic[act];
982 int default_action_direction_crumbled = element_info[i].crumbled[act];
984 /* no graphic for current action -- use default direction graphic */
985 if (default_action_direction_graphic == -1)
986 default_action_direction_graphic =
987 (act_remove ? default_remove_graphic :
989 element_info[i].direction_graphic[ACTION_TURNING][dir] :
990 default_action_graphic != default_graphic ?
991 default_action_graphic :
992 default_direction_graphic[dir]);
994 if (element_info[i].direction_graphic[act][dir] == -1)
995 element_info[i].direction_graphic[act][dir] =
996 default_action_direction_graphic;
999 if (default_action_direction_crumbled == -1)
1000 default_action_direction_crumbled =
1001 element_info[i].direction_graphic[act][dir];
1003 if (default_action_direction_crumbled == -1)
1004 default_action_direction_crumbled =
1005 (act_remove ? default_remove_graphic :
1007 element_info[i].direction_crumbled[ACTION_TURNING][dir] :
1008 default_action_crumbled != default_crumbled ?
1009 default_action_crumbled :
1010 default_direction_crumbled[dir]);
1013 if (element_info[i].direction_crumbled[act][dir] == -1)
1014 element_info[i].direction_crumbled[act][dir] =
1015 default_action_direction_crumbled;
1018 /* no graphic for this specific action -- use default action graphic */
1019 if (element_info[i].graphic[act] == -1)
1020 element_info[i].graphic[act] =
1021 (act_remove ? default_remove_graphic :
1022 act_turning ? element_info[i].graphic[ACTION_TURNING] :
1023 default_action_graphic);
1025 if (element_info[i].crumbled[act] == -1)
1026 element_info[i].crumbled[act] = element_info[i].graphic[act];
1028 if (element_info[i].crumbled[act] == -1)
1029 element_info[i].crumbled[act] =
1030 (act_remove ? default_remove_graphic :
1031 act_turning ? element_info[i].crumbled[ACTION_TURNING] :
1032 default_action_crumbled);
1037 UPDATE_BUSY_STATE();
1040 /* !!! THIS ALSO CLEARS SPECIAL FLAGS (AND IS NOT NEEDED ANYWAY) !!! */
1041 /* set animation mode to "none" for each graphic with only 1 frame */
1042 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1044 for (act = 0; act < NUM_ACTIONS; act++)
1046 int graphic = element_info[i].graphic[act];
1047 int crumbled = element_info[i].crumbled[act];
1049 if (graphic_info[graphic].anim_frames == 1)
1050 graphic_info[graphic].anim_mode = ANIM_NONE;
1051 if (graphic_info[crumbled].anim_frames == 1)
1052 graphic_info[crumbled].anim_mode = ANIM_NONE;
1054 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1056 graphic = element_info[i].direction_graphic[act][dir];
1057 crumbled = element_info[i].direction_crumbled[act][dir];
1059 if (graphic_info[graphic].anim_frames == 1)
1060 graphic_info[graphic].anim_mode = ANIM_NONE;
1061 if (graphic_info[crumbled].anim_frames == 1)
1062 graphic_info[crumbled].anim_mode = ANIM_NONE;
1070 if (options.verbose)
1072 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1073 if (element_info[i].graphic[ACTION_DEFAULT] == IMG_UNKNOWN &&
1075 Error(ERR_INFO, "warning: no graphic for element '%s' (%d)",
1076 element_info[i].token_name, i);
1082 void InitElementSpecialGraphicInfo()
1084 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
1085 int num_property_mappings = getImageListPropertyMappingSize();
1088 /* always start with reliable default values */
1089 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1090 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1091 element_info[i].special_graphic[j] =
1092 element_info[i].graphic[ACTION_DEFAULT];
1094 /* initialize special element/graphic mapping from static configuration */
1095 for (i = 0; element_to_special_graphic[i].element > -1; i++)
1097 int element = element_to_special_graphic[i].element;
1098 int special = element_to_special_graphic[i].special;
1099 int graphic = element_to_special_graphic[i].graphic;
1100 int base_graphic = el2baseimg(element);
1101 boolean base_redefined =
1102 getImageListEntryFromImageID(base_graphic)->redefined;
1103 boolean special_redefined =
1104 getImageListEntryFromImageID(graphic)->redefined;
1107 if ((element == EL_EM_DYNAMITE ||
1108 element == EL_EM_DYNAMITE_ACTIVE) &&
1109 (special == GFX_SPECIAL_ARG_EDITOR ||
1110 special == GFX_SPECIAL_ARG_PANEL))
1111 printf("::: SPECIAL STATIC: %d, %d -> %d\n",
1112 element, special, graphic);
1115 /* if the base graphic ("emerald", for example) has been redefined,
1116 but not the special graphic ("emerald.EDITOR", for example), do not
1117 use an existing (in this case considered obsolete) special graphic
1118 anymore, but use the automatically created (down-scaled) graphic */
1119 if (base_redefined && !special_redefined)
1122 element_info[element].special_graphic[special] = graphic;
1125 /* initialize special element/graphic mapping from dynamic configuration */
1126 for (i = 0; i < num_property_mappings; i++)
1128 int element = property_mapping[i].base_index;
1129 int action = property_mapping[i].ext1_index;
1130 int direction = property_mapping[i].ext2_index;
1131 int special = property_mapping[i].ext3_index;
1132 int graphic = property_mapping[i].artwork_index;
1135 if ((element == EL_EM_DYNAMITE ||
1136 element == EL_EM_DYNAMITE_ACTIVE ||
1137 element == EL_CONVEYOR_BELT_1_MIDDLE ||
1138 element == EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE) &&
1139 (special == GFX_SPECIAL_ARG_EDITOR ||
1140 special == GFX_SPECIAL_ARG_PANEL))
1141 printf("::: SPECIAL DYNAMIC: %d, %d -> %d [%d]\n",
1142 element, special, graphic, property_mapping[i].ext1_index);
1146 if (element == EL_CONVEYOR_BELT_1_MIDDLE &&
1147 action == ACTION_ACTIVE)
1149 element = EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE;
1155 if (element == EL_MAGIC_WALL &&
1156 action == ACTION_ACTIVE)
1158 element = EL_MAGIC_WALL_ACTIVE;
1164 /* for action ".active", replace element with active element, if exists */
1165 if (action == ACTION_ACTIVE && element != ELEMENT_ACTIVE(element))
1167 element = ELEMENT_ACTIVE(element);
1172 if (element >= MAX_NUM_ELEMENTS)
1175 /* do not change special graphic if action or direction was specified */
1176 if (action != -1 || direction != -1)
1179 if (IS_SPECIAL_GFX_ARG(special))
1180 element_info[element].special_graphic[special] = graphic;
1183 /* now set all undefined/invalid graphics to default */
1184 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1185 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1186 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
1187 element_info[i].special_graphic[j] =
1188 element_info[i].graphic[ACTION_DEFAULT];
1191 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
1193 if (type != TYPE_ELEMENT && type != TYPE_GRAPHIC)
1194 return get_parameter_value(value_raw, suffix, type);
1196 if (strEqual(value_raw, ARG_UNDEFINED))
1197 return ARG_UNDEFINED_VALUE;
1200 if (type == TYPE_ELEMENT)
1202 char *value = getHashEntry(element_token_hash, value_raw);
1204 return (value != NULL ? atoi(value) : EL_UNDEFINED);
1206 else if (type == TYPE_GRAPHIC)
1208 char *value = getHashEntry(graphic_token_hash, value_raw);
1210 return (value != NULL ? atoi(value) : IMG_UNDEFINED);
1218 /* !!! THIS IS BUGGY !!! NOT SURE IF YOU GET ELEMENT ID OR GRAPHIC ID !!! */
1219 /* !!! (possible reason why ".clone_from" with elements doesn't work) !!! */
1221 /* !!! OPTIMIZE THIS BY USING HASH !!! */
1222 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1223 if (strEqual(element_info[i].token_name, value_raw))
1226 /* !!! OPTIMIZE THIS BY USING HASH !!! */
1227 for (i = 0; image_config[i].token != NULL; i++)
1229 int len_config_value = strlen(image_config[i].value);
1231 if (!strEqual(&image_config[i].value[len_config_value - 4], ".pcx") &&
1232 !strEqual(&image_config[i].value[len_config_value - 4], ".wav") &&
1233 !strEqual(image_config[i].value, UNDEFINED_FILENAME))
1236 if (strEqual(image_config[i].token, value_raw))
1246 static int get_scaled_graphic_width(int graphic)
1248 int original_width = getOriginalImageWidthFromImageID(graphic);
1249 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1251 return original_width * scale_up_factor;
1254 static int get_scaled_graphic_height(int graphic)
1256 int original_height = getOriginalImageHeightFromImageID(graphic);
1257 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1259 return original_height * scale_up_factor;
1262 static void set_graphic_parameters_ext(int graphic, int *parameter,
1265 struct GraphicInfo *g = &graphic_info[graphic];
1266 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1267 int anim_frames_per_line = 1;
1269 /* always start with reliable default values */
1270 g->src_image_width = 0;
1271 g->src_image_height = 0;
1274 g->width = TILEX; /* default for element graphics */
1275 g->height = TILEY; /* default for element graphics */
1276 g->offset_x = 0; /* one or both of these values ... */
1277 g->offset_y = 0; /* ... will be corrected later */
1278 g->offset2_x = 0; /* one or both of these values ... */
1279 g->offset2_y = 0; /* ... will be corrected later */
1280 g->swap_double_tiles = -1; /* auto-detect tile swapping */
1281 g->crumbled_like = -1; /* do not use clone element */
1282 g->diggable_like = -1; /* do not use clone element */
1283 g->border_size = TILEX / 8; /* "CRUMBLED" border size */
1284 g->scale_up_factor = 1; /* default: no scaling up */
1285 g->clone_from = -1; /* do not use clone graphic */
1286 g->anim_delay_fixed = 0;
1287 g->anim_delay_random = 0;
1288 g->post_delay_fixed = 0;
1289 g->post_delay_random = 0;
1290 g->fade_mode = FADE_MODE_DEFAULT;
1294 g->align = ALIGN_CENTER; /* default for title screens */
1295 g->valign = VALIGN_MIDDLE; /* default for title screens */
1296 g->sort_priority = 0; /* default for title screens */
1298 g->style = STYLE_DEFAULT;
1300 g->bitmap = src_bitmap;
1303 /* optional zoom factor for scaling up the image to a larger size */
1304 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1305 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1306 if (g->scale_up_factor < 1)
1307 g->scale_up_factor = 1; /* no scaling */
1311 if (g->use_image_size)
1313 /* set new default bitmap size (with scaling, but without small images) */
1314 g->width = get_scaled_graphic_width(graphic);
1315 g->height = get_scaled_graphic_height(graphic);
1319 /* optional x and y tile position of animation frame sequence */
1320 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1321 g->src_x = parameter[GFX_ARG_XPOS] * TILEX;
1322 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1323 g->src_y = parameter[GFX_ARG_YPOS] * TILEY;
1325 /* optional x and y pixel position of animation frame sequence */
1326 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1327 g->src_x = parameter[GFX_ARG_X];
1328 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1329 g->src_y = parameter[GFX_ARG_Y];
1331 /* optional width and height of each animation frame */
1332 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1333 g->width = parameter[GFX_ARG_WIDTH];
1334 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1335 g->height = parameter[GFX_ARG_HEIGHT];
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 getGraphicSource(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 getGraphicSource(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, "custom graphic rejected for this element/action");
2020 if (i == fallback_graphic)
2021 Error(ERR_EXIT, "fatal error: no fallback graphic available");
2023 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
2024 Error(ERR_INFO_LINE, "-");
2026 graphic_info[i] = graphic_info[fallback_graphic];
2029 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
2030 /* currently we only need a tile clip mask from the first frame */
2031 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
2033 if (copy_clipmask_gc == None)
2035 clip_gc_values.graphics_exposures = False;
2036 clip_gc_valuemask = GCGraphicsExposures;
2037 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
2038 clip_gc_valuemask, &clip_gc_values);
2041 graphic_info[i].clip_mask =
2042 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
2044 src_pixmap = src_bitmap->clip_mask;
2045 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
2046 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
2048 clip_gc_values.graphics_exposures = False;
2049 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
2050 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
2052 graphic_info[i].clip_gc =
2053 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
2057 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
2058 if (copy_clipmask_gc)
2059 XFreeGC(display, copy_clipmask_gc);
2061 clipmasks_initialized = TRUE;
2065 static void InitGraphicCompatibilityInfo()
2067 struct FileInfo *fi_global_door =
2068 getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
2069 int num_images = getImageListSize();
2072 /* the following compatibility handling is needed for the following case:
2073 versions up to 3.3.0.0 used one large bitmap "global.door" for various
2074 graphics mainly used for door and panel graphics, like editor, tape and
2075 in-game buttons with hard-coded bitmap positions and button sizes; as
2076 these graphics now have individual definitions, redefining "global.door"
2077 to change all these graphics at once like before does not work anymore
2078 (because all those individual definitions still have their default values);
2079 to solve this, remap all those individual definitions that are not
2080 redefined to the new bitmap of "global.door" if it was redefined */
2082 /* special compatibility handling if image "global.door" was redefined */
2083 if (fi_global_door->redefined)
2085 for (i = 0; i < num_images; i++)
2087 struct FileInfo *fi = getImageListEntryFromImageID(i);
2089 /* process only those images that still use the default settings */
2092 /* process all images which default to same image as "global.door" */
2093 if (strEqual(fi->default_filename, fi_global_door->default_filename))
2095 // printf("::: special treatment needed for token '%s'\n", fi->token);
2097 graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2104 for (i = 0; i < num_images; i++)
2106 struct FileInfo *fi = getImageListEntryFromImageID(i);
2108 if (i == IMG_GLOBAL_DOOR)
2110 printf("::: %s, %s, %d\n",
2111 fi->default_filename,
2119 static void InitElementSoundInfo()
2121 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
2122 int num_property_mappings = getSoundListPropertyMappingSize();
2125 /* set values to -1 to identify later as "uninitialized" values */
2126 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2127 for (act = 0; act < NUM_ACTIONS; act++)
2128 element_info[i].sound[act] = -1;
2130 /* initialize element/sound mapping from static configuration */
2131 for (i = 0; element_to_sound[i].element > -1; i++)
2133 int element = element_to_sound[i].element;
2134 int action = element_to_sound[i].action;
2135 int sound = element_to_sound[i].sound;
2136 boolean is_class = element_to_sound[i].is_class;
2139 action = ACTION_DEFAULT;
2142 element_info[element].sound[action] = sound;
2144 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2145 if (strEqual(element_info[j].class_name,
2146 element_info[element].class_name))
2147 element_info[j].sound[action] = sound;
2150 /* initialize element class/sound mapping from dynamic configuration */
2151 for (i = 0; i < num_property_mappings; i++)
2153 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
2154 int action = property_mapping[i].ext1_index;
2155 int sound = property_mapping[i].artwork_index;
2157 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
2161 action = ACTION_DEFAULT;
2163 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2164 if (strEqual(element_info[j].class_name,
2165 element_info[element_class].class_name))
2166 element_info[j].sound[action] = sound;
2169 /* initialize element/sound mapping from dynamic configuration */
2170 for (i = 0; i < num_property_mappings; i++)
2172 int element = property_mapping[i].base_index;
2173 int action = property_mapping[i].ext1_index;
2174 int sound = property_mapping[i].artwork_index;
2176 if (element >= MAX_NUM_ELEMENTS)
2180 action = ACTION_DEFAULT;
2182 element_info[element].sound[action] = sound;
2185 /* now set all '-1' values to element specific default values */
2186 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2188 for (act = 0; act < NUM_ACTIONS; act++)
2190 /* generic default action sound (defined by "[default]" directive) */
2191 int default_action_sound = element_info[EL_DEFAULT].sound[act];
2193 /* look for special default action sound (classic game specific) */
2194 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
2195 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
2196 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
2197 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
2198 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
2199 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
2201 /* !!! there's no such thing as a "default action sound" !!! */
2203 /* look for element specific default sound (independent from action) */
2204 if (element_info[i].sound[ACTION_DEFAULT] != -1)
2205 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
2209 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
2210 /* !!! make this better !!! */
2211 if (i == EL_EMPTY_SPACE)
2212 default_action_sound = element_info[EL_DEFAULT].sound[act];
2215 /* no sound for this specific action -- use default action sound */
2216 if (element_info[i].sound[act] == -1)
2217 element_info[i].sound[act] = default_action_sound;
2221 /* copy sound settings to some elements that are only stored in level file
2222 in native R'n'D levels, but are used by game engine in native EM levels */
2223 for (i = 0; copy_properties[i][0] != -1; i++)
2224 for (j = 1; j <= 4; j++)
2225 for (act = 0; act < NUM_ACTIONS; act++)
2226 element_info[copy_properties[i][j]].sound[act] =
2227 element_info[copy_properties[i][0]].sound[act];
2230 static void InitGameModeSoundInfo()
2234 /* set values to -1 to identify later as "uninitialized" values */
2235 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2238 /* initialize gamemode/sound mapping from static configuration */
2239 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
2241 int gamemode = gamemode_to_sound[i].gamemode;
2242 int sound = gamemode_to_sound[i].sound;
2245 gamemode = GAME_MODE_DEFAULT;
2247 menu.sound[gamemode] = sound;
2250 /* now set all '-1' values to levelset specific default values */
2251 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2252 if (menu.sound[i] == -1)
2253 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
2256 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2257 if (menu.sound[i] != -1)
2258 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
2262 static void set_sound_parameters(int sound, char **parameter_raw)
2264 int parameter[NUM_SND_ARGS];
2267 /* get integer values from string parameters */
2268 for (i = 0; i < NUM_SND_ARGS; i++)
2270 get_parameter_value(parameter_raw[i],
2271 sound_config_suffix[i].token,
2272 sound_config_suffix[i].type);
2274 /* explicit loop mode setting in configuration overrides default value */
2275 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2276 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
2278 /* sound volume to change the original volume when loading the sound file */
2279 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
2281 /* sound priority to give certain sounds a higher or lower priority */
2282 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
2285 static void InitSoundInfo()
2287 int *sound_effect_properties;
2288 int num_sounds = getSoundListSize();
2291 checked_free(sound_info);
2293 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
2294 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
2296 /* initialize sound effect for all elements to "no sound" */
2297 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2298 for (j = 0; j < NUM_ACTIONS; j++)
2299 element_info[i].sound[j] = SND_UNDEFINED;
2301 for (i = 0; i < num_sounds; i++)
2303 struct FileInfo *sound = getSoundListEntry(i);
2304 int len_effect_text = strlen(sound->token);
2306 sound_effect_properties[i] = ACTION_OTHER;
2307 sound_info[i].loop = FALSE; /* default: play sound only once */
2310 printf("::: sound %d: '%s'\n", i, sound->token);
2313 /* determine all loop sounds and identify certain sound classes */
2315 for (j = 0; element_action_info[j].suffix; j++)
2317 int len_action_text = strlen(element_action_info[j].suffix);
2319 if (len_action_text < len_effect_text &&
2320 strEqual(&sound->token[len_effect_text - len_action_text],
2321 element_action_info[j].suffix))
2323 sound_effect_properties[i] = element_action_info[j].value;
2324 sound_info[i].loop = element_action_info[j].is_loop_sound;
2330 /* associate elements and some selected sound actions */
2332 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2334 if (element_info[j].class_name)
2336 int len_class_text = strlen(element_info[j].class_name);
2338 if (len_class_text + 1 < len_effect_text &&
2339 strncmp(sound->token,
2340 element_info[j].class_name, len_class_text) == 0 &&
2341 sound->token[len_class_text] == '.')
2343 int sound_action_value = sound_effect_properties[i];
2345 element_info[j].sound[sound_action_value] = i;
2350 set_sound_parameters(i, sound->parameter);
2353 free(sound_effect_properties);
2356 static void InitGameModeMusicInfo()
2358 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
2359 int num_property_mappings = getMusicListPropertyMappingSize();
2360 int default_levelset_music = -1;
2363 /* set values to -1 to identify later as "uninitialized" values */
2364 for (i = 0; i < MAX_LEVELS; i++)
2365 levelset.music[i] = -1;
2366 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2369 /* initialize gamemode/music mapping from static configuration */
2370 for (i = 0; gamemode_to_music[i].music > -1; i++)
2372 int gamemode = gamemode_to_music[i].gamemode;
2373 int music = gamemode_to_music[i].music;
2376 printf("::: gamemode == %d, music == %d\n", gamemode, music);
2380 gamemode = GAME_MODE_DEFAULT;
2382 menu.music[gamemode] = music;
2385 /* initialize gamemode/music mapping from dynamic configuration */
2386 for (i = 0; i < num_property_mappings; i++)
2388 int prefix = property_mapping[i].base_index;
2389 int gamemode = property_mapping[i].ext1_index;
2390 int level = property_mapping[i].ext2_index;
2391 int music = property_mapping[i].artwork_index;
2394 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
2395 prefix, gamemode, level, music);
2398 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
2402 gamemode = GAME_MODE_DEFAULT;
2404 /* level specific music only allowed for in-game music */
2405 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
2406 gamemode = GAME_MODE_PLAYING;
2411 default_levelset_music = music;
2414 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
2415 levelset.music[level] = music;
2416 if (gamemode != GAME_MODE_PLAYING)
2417 menu.music[gamemode] = music;
2420 /* now set all '-1' values to menu specific default values */
2421 /* (undefined values of "levelset.music[]" might stay at "-1" to
2422 allow dynamic selection of music files from music directory!) */
2423 for (i = 0; i < MAX_LEVELS; i++)
2424 if (levelset.music[i] == -1)
2425 levelset.music[i] = default_levelset_music;
2426 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2427 if (menu.music[i] == -1)
2428 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
2431 for (i = 0; i < MAX_LEVELS; i++)
2432 if (levelset.music[i] != -1)
2433 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
2434 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2435 if (menu.music[i] != -1)
2436 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
2440 static void set_music_parameters(int music, char **parameter_raw)
2442 int parameter[NUM_MUS_ARGS];
2445 /* get integer values from string parameters */
2446 for (i = 0; i < NUM_MUS_ARGS; i++)
2448 get_parameter_value(parameter_raw[i],
2449 music_config_suffix[i].token,
2450 music_config_suffix[i].type);
2452 /* explicit loop mode setting in configuration overrides default value */
2453 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2454 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
2457 static void InitMusicInfo()
2459 int num_music = getMusicListSize();
2462 checked_free(music_info);
2464 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
2466 for (i = 0; i < num_music; i++)
2468 struct FileInfo *music = getMusicListEntry(i);
2469 int len_music_text = strlen(music->token);
2471 music_info[i].loop = TRUE; /* default: play music in loop mode */
2473 /* determine all loop music */
2475 for (j = 0; music_prefix_info[j].prefix; j++)
2477 int len_prefix_text = strlen(music_prefix_info[j].prefix);
2479 if (len_prefix_text < len_music_text &&
2480 strncmp(music->token,
2481 music_prefix_info[j].prefix, len_prefix_text) == 0)
2483 music_info[i].loop = music_prefix_info[j].is_loop_music;
2489 set_music_parameters(i, music->parameter);
2493 static void ReinitializeGraphics()
2495 print_timestamp_init("ReinitializeGraphics");
2497 InitGraphicInfo(); /* graphic properties mapping */
2498 print_timestamp_time("InitGraphicInfo");
2499 InitElementGraphicInfo(); /* element game graphic mapping */
2500 print_timestamp_time("InitElementGraphicInfo");
2501 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
2502 print_timestamp_time("InitElementSpecialGraphicInfo");
2504 InitElementSmallImages(); /* scale elements to all needed sizes */
2505 print_timestamp_time("InitElementSmallImages");
2506 InitScaledImages(); /* scale all other images, if needed */
2507 print_timestamp_time("InitScaledImages");
2508 InitFontGraphicInfo(); /* initialize text drawing functions */
2509 print_timestamp_time("InitFontGraphicInfo");
2511 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
2512 print_timestamp_time("InitGraphicInfo_EM");
2514 InitGraphicCompatibilityInfo();
2515 print_timestamp_time("InitGraphicCompatibilityInfo");
2517 SetMainBackgroundImage(IMG_BACKGROUND);
2518 print_timestamp_time("SetMainBackgroundImage");
2519 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2520 print_timestamp_time("SetDoorBackgroundImage");
2523 print_timestamp_time("InitGadgets");
2525 print_timestamp_time("InitToons");
2527 print_timestamp_done("ReinitializeGraphics");
2530 static void ReinitializeSounds()
2532 InitSoundInfo(); /* sound properties mapping */
2533 InitElementSoundInfo(); /* element game sound mapping */
2534 InitGameModeSoundInfo(); /* game mode sound mapping */
2536 InitPlayLevelSound(); /* internal game sound settings */
2539 static void ReinitializeMusic()
2541 InitMusicInfo(); /* music properties mapping */
2542 InitGameModeMusicInfo(); /* game mode music mapping */
2545 static int get_special_property_bit(int element, int property_bit_nr)
2547 struct PropertyBitInfo
2553 static struct PropertyBitInfo pb_can_move_into_acid[] =
2555 /* the player may be able fall into acid when gravity is activated */
2560 { EL_SP_MURPHY, 0 },
2561 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2563 /* all elements that can move may be able to also move into acid */
2566 { EL_BUG_RIGHT, 1 },
2569 { EL_SPACESHIP, 2 },
2570 { EL_SPACESHIP_LEFT, 2 },
2571 { EL_SPACESHIP_RIGHT, 2 },
2572 { EL_SPACESHIP_UP, 2 },
2573 { EL_SPACESHIP_DOWN, 2 },
2574 { EL_BD_BUTTERFLY, 3 },
2575 { EL_BD_BUTTERFLY_LEFT, 3 },
2576 { EL_BD_BUTTERFLY_RIGHT, 3 },
2577 { EL_BD_BUTTERFLY_UP, 3 },
2578 { EL_BD_BUTTERFLY_DOWN, 3 },
2579 { EL_BD_FIREFLY, 4 },
2580 { EL_BD_FIREFLY_LEFT, 4 },
2581 { EL_BD_FIREFLY_RIGHT, 4 },
2582 { EL_BD_FIREFLY_UP, 4 },
2583 { EL_BD_FIREFLY_DOWN, 4 },
2585 { EL_YAMYAM_LEFT, 5 },
2586 { EL_YAMYAM_RIGHT, 5 },
2587 { EL_YAMYAM_UP, 5 },
2588 { EL_YAMYAM_DOWN, 5 },
2589 { EL_DARK_YAMYAM, 6 },
2592 { EL_PACMAN_LEFT, 8 },
2593 { EL_PACMAN_RIGHT, 8 },
2594 { EL_PACMAN_UP, 8 },
2595 { EL_PACMAN_DOWN, 8 },
2597 { EL_MOLE_LEFT, 9 },
2598 { EL_MOLE_RIGHT, 9 },
2600 { EL_MOLE_DOWN, 9 },
2604 { EL_SATELLITE, 13 },
2605 { EL_SP_SNIKSNAK, 14 },
2606 { EL_SP_ELECTRON, 15 },
2609 { EL_EMC_ANDROID, 18 },
2614 static struct PropertyBitInfo pb_dont_collide_with[] =
2616 { EL_SP_SNIKSNAK, 0 },
2617 { EL_SP_ELECTRON, 1 },
2625 struct PropertyBitInfo *pb_info;
2628 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2629 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2634 struct PropertyBitInfo *pb_info = NULL;
2637 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2638 if (pb_definition[i].bit_nr == property_bit_nr)
2639 pb_info = pb_definition[i].pb_info;
2641 if (pb_info == NULL)
2644 for (i = 0; pb_info[i].element != -1; i++)
2645 if (pb_info[i].element == element)
2646 return pb_info[i].bit_nr;
2651 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2652 boolean property_value)
2654 int bit_nr = get_special_property_bit(element, property_bit_nr);
2659 *bitfield |= (1 << bit_nr);
2661 *bitfield &= ~(1 << bit_nr);
2665 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2667 int bit_nr = get_special_property_bit(element, property_bit_nr);
2670 return ((*bitfield & (1 << bit_nr)) != 0);
2675 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2677 static int group_nr;
2678 static struct ElementGroupInfo *group;
2679 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2682 if (actual_group == NULL) /* not yet initialized */
2685 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
2687 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2688 group_element - EL_GROUP_START + 1);
2690 /* replace element which caused too deep recursion by question mark */
2691 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2696 if (recursion_depth == 0) /* initialization */
2698 group = actual_group;
2699 group_nr = GROUP_NR(group_element);
2701 group->num_elements_resolved = 0;
2702 group->choice_pos = 0;
2704 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2705 element_info[i].in_group[group_nr] = FALSE;
2708 for (i = 0; i < actual_group->num_elements; i++)
2710 int element = actual_group->element[i];
2712 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2715 if (IS_GROUP_ELEMENT(element))
2716 ResolveGroupElementExt(element, recursion_depth + 1);
2719 group->element_resolved[group->num_elements_resolved++] = element;
2720 element_info[element].in_group[group_nr] = TRUE;
2725 void ResolveGroupElement(int group_element)
2727 ResolveGroupElementExt(group_element, 0);
2730 void InitElementPropertiesStatic()
2732 static boolean clipboard_elements_initialized = FALSE;
2734 static int ep_diggable[] =
2739 EL_SP_BUGGY_BASE_ACTIVATING,
2742 EL_INVISIBLE_SAND_ACTIVE,
2745 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2746 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2751 EL_SP_BUGGY_BASE_ACTIVE,
2758 static int ep_collectible_only[] =
2780 EL_DYNABOMB_INCREASE_NUMBER,
2781 EL_DYNABOMB_INCREASE_SIZE,
2782 EL_DYNABOMB_INCREASE_POWER,
2800 /* !!! handle separately !!! */
2801 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2807 static int ep_dont_run_into[] =
2809 /* same elements as in 'ep_dont_touch' */
2815 /* same elements as in 'ep_dont_collide_with' */
2827 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2832 EL_SP_BUGGY_BASE_ACTIVE,
2839 static int ep_dont_collide_with[] =
2841 /* same elements as in 'ep_dont_touch' */
2858 static int ep_dont_touch[] =
2868 static int ep_indestructible[] =
2872 EL_ACID_POOL_TOPLEFT,
2873 EL_ACID_POOL_TOPRIGHT,
2874 EL_ACID_POOL_BOTTOMLEFT,
2875 EL_ACID_POOL_BOTTOM,
2876 EL_ACID_POOL_BOTTOMRIGHT,
2877 EL_SP_HARDWARE_GRAY,
2878 EL_SP_HARDWARE_GREEN,
2879 EL_SP_HARDWARE_BLUE,
2881 EL_SP_HARDWARE_YELLOW,
2882 EL_SP_HARDWARE_BASE_1,
2883 EL_SP_HARDWARE_BASE_2,
2884 EL_SP_HARDWARE_BASE_3,
2885 EL_SP_HARDWARE_BASE_4,
2886 EL_SP_HARDWARE_BASE_5,
2887 EL_SP_HARDWARE_BASE_6,
2888 EL_INVISIBLE_STEELWALL,
2889 EL_INVISIBLE_STEELWALL_ACTIVE,
2890 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2891 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2892 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2893 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2894 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2895 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2896 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2897 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2898 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2899 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2900 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2901 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2903 EL_LIGHT_SWITCH_ACTIVE,
2904 EL_SIGN_EXCLAMATION,
2905 EL_SIGN_RADIOACTIVITY,
2912 EL_SIGN_ENTRY_FORBIDDEN,
2913 EL_SIGN_EMERGENCY_EXIT,
2921 EL_STEEL_EXIT_CLOSED,
2923 EL_STEEL_EXIT_OPENING,
2924 EL_STEEL_EXIT_CLOSING,
2925 EL_EM_STEEL_EXIT_CLOSED,
2926 EL_EM_STEEL_EXIT_OPEN,
2927 EL_EM_STEEL_EXIT_OPENING,
2928 EL_EM_STEEL_EXIT_CLOSING,
2929 EL_DC_STEELWALL_1_LEFT,
2930 EL_DC_STEELWALL_1_RIGHT,
2931 EL_DC_STEELWALL_1_TOP,
2932 EL_DC_STEELWALL_1_BOTTOM,
2933 EL_DC_STEELWALL_1_HORIZONTAL,
2934 EL_DC_STEELWALL_1_VERTICAL,
2935 EL_DC_STEELWALL_1_TOPLEFT,
2936 EL_DC_STEELWALL_1_TOPRIGHT,
2937 EL_DC_STEELWALL_1_BOTTOMLEFT,
2938 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2939 EL_DC_STEELWALL_1_TOPLEFT_2,
2940 EL_DC_STEELWALL_1_TOPRIGHT_2,
2941 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2942 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2943 EL_DC_STEELWALL_2_LEFT,
2944 EL_DC_STEELWALL_2_RIGHT,
2945 EL_DC_STEELWALL_2_TOP,
2946 EL_DC_STEELWALL_2_BOTTOM,
2947 EL_DC_STEELWALL_2_HORIZONTAL,
2948 EL_DC_STEELWALL_2_VERTICAL,
2949 EL_DC_STEELWALL_2_MIDDLE,
2950 EL_DC_STEELWALL_2_SINGLE,
2951 EL_STEELWALL_SLIPPERY,
2965 EL_GATE_1_GRAY_ACTIVE,
2966 EL_GATE_2_GRAY_ACTIVE,
2967 EL_GATE_3_GRAY_ACTIVE,
2968 EL_GATE_4_GRAY_ACTIVE,
2977 EL_EM_GATE_1_GRAY_ACTIVE,
2978 EL_EM_GATE_2_GRAY_ACTIVE,
2979 EL_EM_GATE_3_GRAY_ACTIVE,
2980 EL_EM_GATE_4_GRAY_ACTIVE,
2989 EL_EMC_GATE_5_GRAY_ACTIVE,
2990 EL_EMC_GATE_6_GRAY_ACTIVE,
2991 EL_EMC_GATE_7_GRAY_ACTIVE,
2992 EL_EMC_GATE_8_GRAY_ACTIVE,
2994 EL_DC_GATE_WHITE_GRAY,
2995 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2996 EL_DC_GATE_FAKE_GRAY,
2998 EL_SWITCHGATE_OPENING,
2999 EL_SWITCHGATE_CLOSED,
3000 EL_SWITCHGATE_CLOSING,
3002 EL_DC_SWITCHGATE_SWITCH_UP,
3003 EL_DC_SWITCHGATE_SWITCH_DOWN,
3006 EL_TIMEGATE_OPENING,
3008 EL_TIMEGATE_CLOSING,
3010 EL_DC_TIMEGATE_SWITCH,
3011 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3016 EL_TUBE_VERTICAL_LEFT,
3017 EL_TUBE_VERTICAL_RIGHT,
3018 EL_TUBE_HORIZONTAL_UP,
3019 EL_TUBE_HORIZONTAL_DOWN,
3024 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
3025 EL_EXPANDABLE_STEELWALL_VERTICAL,
3026 EL_EXPANDABLE_STEELWALL_ANY,
3031 static int ep_slippery[] =
3045 EL_ROBOT_WHEEL_ACTIVE,
3051 EL_ACID_POOL_TOPLEFT,
3052 EL_ACID_POOL_TOPRIGHT,
3062 EL_STEELWALL_SLIPPERY,
3065 EL_EMC_WALL_SLIPPERY_1,
3066 EL_EMC_WALL_SLIPPERY_2,
3067 EL_EMC_WALL_SLIPPERY_3,
3068 EL_EMC_WALL_SLIPPERY_4,
3070 EL_EMC_MAGIC_BALL_ACTIVE,
3075 static int ep_can_change[] =
3080 static int ep_can_move[] =
3082 /* same elements as in 'pb_can_move_into_acid' */
3105 static int ep_can_fall[] =
3119 EL_QUICKSAND_FAST_FULL,
3121 EL_BD_MAGIC_WALL_FULL,
3122 EL_DC_MAGIC_WALL_FULL,
3136 static int ep_can_smash_player[] =
3162 static int ep_can_smash_enemies[] =
3171 static int ep_can_smash_everything[] =
3180 static int ep_explodes_by_fire[] =
3182 /* same elements as in 'ep_explodes_impact' */
3187 /* same elements as in 'ep_explodes_smashed' */
3197 EL_EM_DYNAMITE_ACTIVE,
3198 EL_DYNABOMB_PLAYER_1_ACTIVE,
3199 EL_DYNABOMB_PLAYER_2_ACTIVE,
3200 EL_DYNABOMB_PLAYER_3_ACTIVE,
3201 EL_DYNABOMB_PLAYER_4_ACTIVE,
3202 EL_DYNABOMB_INCREASE_NUMBER,
3203 EL_DYNABOMB_INCREASE_SIZE,
3204 EL_DYNABOMB_INCREASE_POWER,
3205 EL_SP_DISK_RED_ACTIVE,
3219 static int ep_explodes_smashed[] =
3221 /* same elements as in 'ep_explodes_impact' */
3235 static int ep_explodes_impact[] =
3244 static int ep_walkable_over[] =
3248 EL_SOKOBAN_FIELD_EMPTY,
3257 EL_EM_STEEL_EXIT_OPEN,
3259 EL_EM_STEEL_EXIT_OPENING,
3269 EL_GATE_1_GRAY_ACTIVE,
3270 EL_GATE_2_GRAY_ACTIVE,
3271 EL_GATE_3_GRAY_ACTIVE,
3272 EL_GATE_4_GRAY_ACTIVE,
3280 static int ep_walkable_inside[] =
3285 EL_TUBE_VERTICAL_LEFT,
3286 EL_TUBE_VERTICAL_RIGHT,
3287 EL_TUBE_HORIZONTAL_UP,
3288 EL_TUBE_HORIZONTAL_DOWN,
3297 static int ep_walkable_under[] =
3302 static int ep_passable_over[] =
3312 EL_EM_GATE_1_GRAY_ACTIVE,
3313 EL_EM_GATE_2_GRAY_ACTIVE,
3314 EL_EM_GATE_3_GRAY_ACTIVE,
3315 EL_EM_GATE_4_GRAY_ACTIVE,
3324 EL_EMC_GATE_5_GRAY_ACTIVE,
3325 EL_EMC_GATE_6_GRAY_ACTIVE,
3326 EL_EMC_GATE_7_GRAY_ACTIVE,
3327 EL_EMC_GATE_8_GRAY_ACTIVE,
3329 EL_DC_GATE_WHITE_GRAY,
3330 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3337 static int ep_passable_inside[] =
3343 EL_SP_PORT_HORIZONTAL,
3344 EL_SP_PORT_VERTICAL,
3346 EL_SP_GRAVITY_PORT_LEFT,
3347 EL_SP_GRAVITY_PORT_RIGHT,
3348 EL_SP_GRAVITY_PORT_UP,
3349 EL_SP_GRAVITY_PORT_DOWN,
3350 EL_SP_GRAVITY_ON_PORT_LEFT,
3351 EL_SP_GRAVITY_ON_PORT_RIGHT,
3352 EL_SP_GRAVITY_ON_PORT_UP,
3353 EL_SP_GRAVITY_ON_PORT_DOWN,
3354 EL_SP_GRAVITY_OFF_PORT_LEFT,
3355 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3356 EL_SP_GRAVITY_OFF_PORT_UP,
3357 EL_SP_GRAVITY_OFF_PORT_DOWN,
3362 static int ep_passable_under[] =
3367 static int ep_droppable[] =
3372 static int ep_explodes_1x1_old[] =
3377 static int ep_pushable[] =
3389 EL_SOKOBAN_FIELD_FULL,
3398 static int ep_explodes_cross_old[] =
3403 static int ep_protected[] =
3405 /* same elements as in 'ep_walkable_inside' */
3409 EL_TUBE_VERTICAL_LEFT,
3410 EL_TUBE_VERTICAL_RIGHT,
3411 EL_TUBE_HORIZONTAL_UP,
3412 EL_TUBE_HORIZONTAL_DOWN,
3418 /* same elements as in 'ep_passable_over' */
3427 EL_EM_GATE_1_GRAY_ACTIVE,
3428 EL_EM_GATE_2_GRAY_ACTIVE,
3429 EL_EM_GATE_3_GRAY_ACTIVE,
3430 EL_EM_GATE_4_GRAY_ACTIVE,
3439 EL_EMC_GATE_5_GRAY_ACTIVE,
3440 EL_EMC_GATE_6_GRAY_ACTIVE,
3441 EL_EMC_GATE_7_GRAY_ACTIVE,
3442 EL_EMC_GATE_8_GRAY_ACTIVE,
3444 EL_DC_GATE_WHITE_GRAY,
3445 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3449 /* same elements as in 'ep_passable_inside' */
3454 EL_SP_PORT_HORIZONTAL,
3455 EL_SP_PORT_VERTICAL,
3457 EL_SP_GRAVITY_PORT_LEFT,
3458 EL_SP_GRAVITY_PORT_RIGHT,
3459 EL_SP_GRAVITY_PORT_UP,
3460 EL_SP_GRAVITY_PORT_DOWN,
3461 EL_SP_GRAVITY_ON_PORT_LEFT,
3462 EL_SP_GRAVITY_ON_PORT_RIGHT,
3463 EL_SP_GRAVITY_ON_PORT_UP,
3464 EL_SP_GRAVITY_ON_PORT_DOWN,
3465 EL_SP_GRAVITY_OFF_PORT_LEFT,
3466 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3467 EL_SP_GRAVITY_OFF_PORT_UP,
3468 EL_SP_GRAVITY_OFF_PORT_DOWN,
3473 static int ep_throwable[] =
3478 static int ep_can_explode[] =
3480 /* same elements as in 'ep_explodes_impact' */
3485 /* same elements as in 'ep_explodes_smashed' */
3491 /* elements that can explode by explosion or by dragonfire */
3495 EL_EM_DYNAMITE_ACTIVE,
3496 EL_DYNABOMB_PLAYER_1_ACTIVE,
3497 EL_DYNABOMB_PLAYER_2_ACTIVE,
3498 EL_DYNABOMB_PLAYER_3_ACTIVE,
3499 EL_DYNABOMB_PLAYER_4_ACTIVE,
3500 EL_DYNABOMB_INCREASE_NUMBER,
3501 EL_DYNABOMB_INCREASE_SIZE,
3502 EL_DYNABOMB_INCREASE_POWER,
3503 EL_SP_DISK_RED_ACTIVE,
3511 /* elements that can explode only by explosion */
3517 static int ep_gravity_reachable[] =
3523 EL_INVISIBLE_SAND_ACTIVE,
3528 EL_SP_PORT_HORIZONTAL,
3529 EL_SP_PORT_VERTICAL,
3531 EL_SP_GRAVITY_PORT_LEFT,
3532 EL_SP_GRAVITY_PORT_RIGHT,
3533 EL_SP_GRAVITY_PORT_UP,
3534 EL_SP_GRAVITY_PORT_DOWN,
3535 EL_SP_GRAVITY_ON_PORT_LEFT,
3536 EL_SP_GRAVITY_ON_PORT_RIGHT,
3537 EL_SP_GRAVITY_ON_PORT_UP,
3538 EL_SP_GRAVITY_ON_PORT_DOWN,
3539 EL_SP_GRAVITY_OFF_PORT_LEFT,
3540 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3541 EL_SP_GRAVITY_OFF_PORT_UP,
3542 EL_SP_GRAVITY_OFF_PORT_DOWN,
3548 static int ep_player[] =
3555 EL_SOKOBAN_FIELD_PLAYER,
3561 static int ep_can_pass_magic_wall[] =
3575 static int ep_can_pass_dc_magic_wall[] =
3591 static int ep_switchable[] =
3595 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3596 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3597 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3598 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3599 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3600 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3601 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3602 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3603 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3604 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3605 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3606 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3607 EL_SWITCHGATE_SWITCH_UP,
3608 EL_SWITCHGATE_SWITCH_DOWN,
3609 EL_DC_SWITCHGATE_SWITCH_UP,
3610 EL_DC_SWITCHGATE_SWITCH_DOWN,
3612 EL_LIGHT_SWITCH_ACTIVE,
3614 EL_DC_TIMEGATE_SWITCH,
3615 EL_BALLOON_SWITCH_LEFT,
3616 EL_BALLOON_SWITCH_RIGHT,
3617 EL_BALLOON_SWITCH_UP,
3618 EL_BALLOON_SWITCH_DOWN,
3619 EL_BALLOON_SWITCH_ANY,
3620 EL_BALLOON_SWITCH_NONE,
3623 EL_EMC_MAGIC_BALL_SWITCH,
3624 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3629 static int ep_bd_element[] =
3663 static int ep_sp_element[] =
3665 /* should always be valid */
3668 /* standard classic Supaplex elements */
3675 EL_SP_HARDWARE_GRAY,
3683 EL_SP_GRAVITY_PORT_RIGHT,
3684 EL_SP_GRAVITY_PORT_DOWN,
3685 EL_SP_GRAVITY_PORT_LEFT,
3686 EL_SP_GRAVITY_PORT_UP,
3691 EL_SP_PORT_VERTICAL,
3692 EL_SP_PORT_HORIZONTAL,
3698 EL_SP_HARDWARE_BASE_1,
3699 EL_SP_HARDWARE_GREEN,
3700 EL_SP_HARDWARE_BLUE,
3702 EL_SP_HARDWARE_YELLOW,
3703 EL_SP_HARDWARE_BASE_2,
3704 EL_SP_HARDWARE_BASE_3,
3705 EL_SP_HARDWARE_BASE_4,
3706 EL_SP_HARDWARE_BASE_5,
3707 EL_SP_HARDWARE_BASE_6,
3711 /* additional elements that appeared in newer Supaplex levels */
3714 /* additional gravity port elements (not switching, but setting gravity) */
3715 EL_SP_GRAVITY_ON_PORT_LEFT,
3716 EL_SP_GRAVITY_ON_PORT_RIGHT,
3717 EL_SP_GRAVITY_ON_PORT_UP,
3718 EL_SP_GRAVITY_ON_PORT_DOWN,
3719 EL_SP_GRAVITY_OFF_PORT_LEFT,
3720 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3721 EL_SP_GRAVITY_OFF_PORT_UP,
3722 EL_SP_GRAVITY_OFF_PORT_DOWN,
3724 /* more than one Murphy in a level results in an inactive clone */
3727 /* runtime Supaplex elements */
3728 EL_SP_DISK_RED_ACTIVE,
3729 EL_SP_TERMINAL_ACTIVE,
3730 EL_SP_BUGGY_BASE_ACTIVATING,
3731 EL_SP_BUGGY_BASE_ACTIVE,
3738 static int ep_sb_element[] =
3743 EL_SOKOBAN_FIELD_EMPTY,
3744 EL_SOKOBAN_FIELD_FULL,
3745 EL_SOKOBAN_FIELD_PLAYER,
3750 EL_INVISIBLE_STEELWALL,
3755 static int ep_gem[] =
3767 static int ep_food_dark_yamyam[] =
3795 static int ep_food_penguin[] =
3809 static int ep_food_pig[] =
3821 static int ep_historic_wall[] =
3832 EL_GATE_1_GRAY_ACTIVE,
3833 EL_GATE_2_GRAY_ACTIVE,
3834 EL_GATE_3_GRAY_ACTIVE,
3835 EL_GATE_4_GRAY_ACTIVE,
3844 EL_EM_GATE_1_GRAY_ACTIVE,
3845 EL_EM_GATE_2_GRAY_ACTIVE,
3846 EL_EM_GATE_3_GRAY_ACTIVE,
3847 EL_EM_GATE_4_GRAY_ACTIVE,
3854 EL_EXPANDABLE_WALL_HORIZONTAL,
3855 EL_EXPANDABLE_WALL_VERTICAL,
3856 EL_EXPANDABLE_WALL_ANY,
3857 EL_EXPANDABLE_WALL_GROWING,
3858 EL_BD_EXPANDABLE_WALL,
3865 EL_SP_HARDWARE_GRAY,
3866 EL_SP_HARDWARE_GREEN,
3867 EL_SP_HARDWARE_BLUE,
3869 EL_SP_HARDWARE_YELLOW,
3870 EL_SP_HARDWARE_BASE_1,
3871 EL_SP_HARDWARE_BASE_2,
3872 EL_SP_HARDWARE_BASE_3,
3873 EL_SP_HARDWARE_BASE_4,
3874 EL_SP_HARDWARE_BASE_5,
3875 EL_SP_HARDWARE_BASE_6,
3877 EL_SP_TERMINAL_ACTIVE,
3880 EL_INVISIBLE_STEELWALL,
3881 EL_INVISIBLE_STEELWALL_ACTIVE,
3883 EL_INVISIBLE_WALL_ACTIVE,
3884 EL_STEELWALL_SLIPPERY,
3901 static int ep_historic_solid[] =
3905 EL_EXPANDABLE_WALL_HORIZONTAL,
3906 EL_EXPANDABLE_WALL_VERTICAL,
3907 EL_EXPANDABLE_WALL_ANY,
3908 EL_BD_EXPANDABLE_WALL,
3921 EL_QUICKSAND_FILLING,
3922 EL_QUICKSAND_EMPTYING,
3924 EL_MAGIC_WALL_ACTIVE,
3925 EL_MAGIC_WALL_EMPTYING,
3926 EL_MAGIC_WALL_FILLING,
3930 EL_BD_MAGIC_WALL_ACTIVE,
3931 EL_BD_MAGIC_WALL_EMPTYING,
3932 EL_BD_MAGIC_WALL_FULL,
3933 EL_BD_MAGIC_WALL_FILLING,
3934 EL_BD_MAGIC_WALL_DEAD,
3943 EL_SP_TERMINAL_ACTIVE,
3947 EL_INVISIBLE_WALL_ACTIVE,
3948 EL_SWITCHGATE_SWITCH_UP,
3949 EL_SWITCHGATE_SWITCH_DOWN,
3950 EL_DC_SWITCHGATE_SWITCH_UP,
3951 EL_DC_SWITCHGATE_SWITCH_DOWN,
3953 EL_TIMEGATE_SWITCH_ACTIVE,
3954 EL_DC_TIMEGATE_SWITCH,
3955 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3967 /* the following elements are a direct copy of "indestructible" elements,
3968 except "EL_ACID", which is "indestructible", but not "solid"! */
3973 EL_ACID_POOL_TOPLEFT,
3974 EL_ACID_POOL_TOPRIGHT,
3975 EL_ACID_POOL_BOTTOMLEFT,
3976 EL_ACID_POOL_BOTTOM,
3977 EL_ACID_POOL_BOTTOMRIGHT,
3978 EL_SP_HARDWARE_GRAY,
3979 EL_SP_HARDWARE_GREEN,
3980 EL_SP_HARDWARE_BLUE,
3982 EL_SP_HARDWARE_YELLOW,
3983 EL_SP_HARDWARE_BASE_1,
3984 EL_SP_HARDWARE_BASE_2,
3985 EL_SP_HARDWARE_BASE_3,
3986 EL_SP_HARDWARE_BASE_4,
3987 EL_SP_HARDWARE_BASE_5,
3988 EL_SP_HARDWARE_BASE_6,
3989 EL_INVISIBLE_STEELWALL,
3990 EL_INVISIBLE_STEELWALL_ACTIVE,
3991 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3992 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3993 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3994 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3995 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3996 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3997 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3998 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3999 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4000 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4001 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4002 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4004 EL_LIGHT_SWITCH_ACTIVE,
4005 EL_SIGN_EXCLAMATION,
4006 EL_SIGN_RADIOACTIVITY,
4013 EL_SIGN_ENTRY_FORBIDDEN,
4014 EL_SIGN_EMERGENCY_EXIT,
4022 EL_STEEL_EXIT_CLOSED,
4024 EL_DC_STEELWALL_1_LEFT,
4025 EL_DC_STEELWALL_1_RIGHT,
4026 EL_DC_STEELWALL_1_TOP,
4027 EL_DC_STEELWALL_1_BOTTOM,
4028 EL_DC_STEELWALL_1_HORIZONTAL,
4029 EL_DC_STEELWALL_1_VERTICAL,
4030 EL_DC_STEELWALL_1_TOPLEFT,
4031 EL_DC_STEELWALL_1_TOPRIGHT,
4032 EL_DC_STEELWALL_1_BOTTOMLEFT,
4033 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4034 EL_DC_STEELWALL_1_TOPLEFT_2,
4035 EL_DC_STEELWALL_1_TOPRIGHT_2,
4036 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4037 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4038 EL_DC_STEELWALL_2_LEFT,
4039 EL_DC_STEELWALL_2_RIGHT,
4040 EL_DC_STEELWALL_2_TOP,
4041 EL_DC_STEELWALL_2_BOTTOM,
4042 EL_DC_STEELWALL_2_HORIZONTAL,
4043 EL_DC_STEELWALL_2_VERTICAL,
4044 EL_DC_STEELWALL_2_MIDDLE,
4045 EL_DC_STEELWALL_2_SINGLE,
4046 EL_STEELWALL_SLIPPERY,
4060 EL_GATE_1_GRAY_ACTIVE,
4061 EL_GATE_2_GRAY_ACTIVE,
4062 EL_GATE_3_GRAY_ACTIVE,
4063 EL_GATE_4_GRAY_ACTIVE,
4072 EL_EM_GATE_1_GRAY_ACTIVE,
4073 EL_EM_GATE_2_GRAY_ACTIVE,
4074 EL_EM_GATE_3_GRAY_ACTIVE,
4075 EL_EM_GATE_4_GRAY_ACTIVE,
4077 EL_SWITCHGATE_OPENING,
4078 EL_SWITCHGATE_CLOSED,
4079 EL_SWITCHGATE_CLOSING,
4081 EL_TIMEGATE_OPENING,
4083 EL_TIMEGATE_CLOSING,
4087 EL_TUBE_VERTICAL_LEFT,
4088 EL_TUBE_VERTICAL_RIGHT,
4089 EL_TUBE_HORIZONTAL_UP,
4090 EL_TUBE_HORIZONTAL_DOWN,
4099 static int ep_classic_enemy[] =
4116 static int ep_belt[] =
4118 EL_CONVEYOR_BELT_1_LEFT,
4119 EL_CONVEYOR_BELT_1_MIDDLE,
4120 EL_CONVEYOR_BELT_1_RIGHT,
4121 EL_CONVEYOR_BELT_2_LEFT,
4122 EL_CONVEYOR_BELT_2_MIDDLE,
4123 EL_CONVEYOR_BELT_2_RIGHT,
4124 EL_CONVEYOR_BELT_3_LEFT,
4125 EL_CONVEYOR_BELT_3_MIDDLE,
4126 EL_CONVEYOR_BELT_3_RIGHT,
4127 EL_CONVEYOR_BELT_4_LEFT,
4128 EL_CONVEYOR_BELT_4_MIDDLE,
4129 EL_CONVEYOR_BELT_4_RIGHT,
4134 static int ep_belt_active[] =
4136 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
4137 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
4138 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
4139 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
4140 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
4141 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
4142 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
4143 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
4144 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
4145 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
4146 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
4147 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
4152 static int ep_belt_switch[] =
4154 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4155 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4156 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4157 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4158 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4159 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4160 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4161 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4162 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4163 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4164 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4165 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4170 static int ep_tube[] =
4177 EL_TUBE_HORIZONTAL_UP,
4178 EL_TUBE_HORIZONTAL_DOWN,
4180 EL_TUBE_VERTICAL_LEFT,
4181 EL_TUBE_VERTICAL_RIGHT,
4187 static int ep_acid_pool[] =
4189 EL_ACID_POOL_TOPLEFT,
4190 EL_ACID_POOL_TOPRIGHT,
4191 EL_ACID_POOL_BOTTOMLEFT,
4192 EL_ACID_POOL_BOTTOM,
4193 EL_ACID_POOL_BOTTOMRIGHT,
4198 static int ep_keygate[] =
4208 EL_GATE_1_GRAY_ACTIVE,
4209 EL_GATE_2_GRAY_ACTIVE,
4210 EL_GATE_3_GRAY_ACTIVE,
4211 EL_GATE_4_GRAY_ACTIVE,
4220 EL_EM_GATE_1_GRAY_ACTIVE,
4221 EL_EM_GATE_2_GRAY_ACTIVE,
4222 EL_EM_GATE_3_GRAY_ACTIVE,
4223 EL_EM_GATE_4_GRAY_ACTIVE,
4232 EL_EMC_GATE_5_GRAY_ACTIVE,
4233 EL_EMC_GATE_6_GRAY_ACTIVE,
4234 EL_EMC_GATE_7_GRAY_ACTIVE,
4235 EL_EMC_GATE_8_GRAY_ACTIVE,
4237 EL_DC_GATE_WHITE_GRAY,
4238 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4243 static int ep_amoeboid[] =
4255 static int ep_amoebalive[] =
4266 static int ep_has_editor_content[] =
4272 EL_SOKOBAN_FIELD_PLAYER,
4289 static int ep_can_turn_each_move[] =
4291 /* !!! do something with this one !!! */
4295 static int ep_can_grow[] =
4309 static int ep_active_bomb[] =
4312 EL_EM_DYNAMITE_ACTIVE,
4313 EL_DYNABOMB_PLAYER_1_ACTIVE,
4314 EL_DYNABOMB_PLAYER_2_ACTIVE,
4315 EL_DYNABOMB_PLAYER_3_ACTIVE,
4316 EL_DYNABOMB_PLAYER_4_ACTIVE,
4317 EL_SP_DISK_RED_ACTIVE,
4322 static int ep_inactive[] =
4332 EL_QUICKSAND_FAST_EMPTY,
4355 EL_GATE_1_GRAY_ACTIVE,
4356 EL_GATE_2_GRAY_ACTIVE,
4357 EL_GATE_3_GRAY_ACTIVE,
4358 EL_GATE_4_GRAY_ACTIVE,
4367 EL_EM_GATE_1_GRAY_ACTIVE,
4368 EL_EM_GATE_2_GRAY_ACTIVE,
4369 EL_EM_GATE_3_GRAY_ACTIVE,
4370 EL_EM_GATE_4_GRAY_ACTIVE,
4379 EL_EMC_GATE_5_GRAY_ACTIVE,
4380 EL_EMC_GATE_6_GRAY_ACTIVE,
4381 EL_EMC_GATE_7_GRAY_ACTIVE,
4382 EL_EMC_GATE_8_GRAY_ACTIVE,
4384 EL_DC_GATE_WHITE_GRAY,
4385 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4386 EL_DC_GATE_FAKE_GRAY,
4389 EL_INVISIBLE_STEELWALL,
4397 EL_WALL_EMERALD_YELLOW,
4398 EL_DYNABOMB_INCREASE_NUMBER,
4399 EL_DYNABOMB_INCREASE_SIZE,
4400 EL_DYNABOMB_INCREASE_POWER,
4404 EL_SOKOBAN_FIELD_EMPTY,
4405 EL_SOKOBAN_FIELD_FULL,
4406 EL_WALL_EMERALD_RED,
4407 EL_WALL_EMERALD_PURPLE,
4408 EL_ACID_POOL_TOPLEFT,
4409 EL_ACID_POOL_TOPRIGHT,
4410 EL_ACID_POOL_BOTTOMLEFT,
4411 EL_ACID_POOL_BOTTOM,
4412 EL_ACID_POOL_BOTTOMRIGHT,
4416 EL_BD_MAGIC_WALL_DEAD,
4418 EL_DC_MAGIC_WALL_DEAD,
4419 EL_AMOEBA_TO_DIAMOND,
4427 EL_SP_GRAVITY_PORT_RIGHT,
4428 EL_SP_GRAVITY_PORT_DOWN,
4429 EL_SP_GRAVITY_PORT_LEFT,
4430 EL_SP_GRAVITY_PORT_UP,
4431 EL_SP_PORT_HORIZONTAL,
4432 EL_SP_PORT_VERTICAL,
4443 EL_SP_HARDWARE_GRAY,
4444 EL_SP_HARDWARE_GREEN,
4445 EL_SP_HARDWARE_BLUE,
4447 EL_SP_HARDWARE_YELLOW,
4448 EL_SP_HARDWARE_BASE_1,
4449 EL_SP_HARDWARE_BASE_2,
4450 EL_SP_HARDWARE_BASE_3,
4451 EL_SP_HARDWARE_BASE_4,
4452 EL_SP_HARDWARE_BASE_5,
4453 EL_SP_HARDWARE_BASE_6,
4454 EL_SP_GRAVITY_ON_PORT_LEFT,
4455 EL_SP_GRAVITY_ON_PORT_RIGHT,
4456 EL_SP_GRAVITY_ON_PORT_UP,
4457 EL_SP_GRAVITY_ON_PORT_DOWN,
4458 EL_SP_GRAVITY_OFF_PORT_LEFT,
4459 EL_SP_GRAVITY_OFF_PORT_RIGHT,
4460 EL_SP_GRAVITY_OFF_PORT_UP,
4461 EL_SP_GRAVITY_OFF_PORT_DOWN,
4462 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4463 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4464 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4465 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4466 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4467 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4468 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4469 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4470 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4471 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4472 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4473 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4474 EL_SIGN_EXCLAMATION,
4475 EL_SIGN_RADIOACTIVITY,
4482 EL_SIGN_ENTRY_FORBIDDEN,
4483 EL_SIGN_EMERGENCY_EXIT,
4491 EL_DC_STEELWALL_1_LEFT,
4492 EL_DC_STEELWALL_1_RIGHT,
4493 EL_DC_STEELWALL_1_TOP,
4494 EL_DC_STEELWALL_1_BOTTOM,
4495 EL_DC_STEELWALL_1_HORIZONTAL,
4496 EL_DC_STEELWALL_1_VERTICAL,
4497 EL_DC_STEELWALL_1_TOPLEFT,
4498 EL_DC_STEELWALL_1_TOPRIGHT,
4499 EL_DC_STEELWALL_1_BOTTOMLEFT,
4500 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4501 EL_DC_STEELWALL_1_TOPLEFT_2,
4502 EL_DC_STEELWALL_1_TOPRIGHT_2,
4503 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4504 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4505 EL_DC_STEELWALL_2_LEFT,
4506 EL_DC_STEELWALL_2_RIGHT,
4507 EL_DC_STEELWALL_2_TOP,
4508 EL_DC_STEELWALL_2_BOTTOM,
4509 EL_DC_STEELWALL_2_HORIZONTAL,
4510 EL_DC_STEELWALL_2_VERTICAL,
4511 EL_DC_STEELWALL_2_MIDDLE,
4512 EL_DC_STEELWALL_2_SINGLE,
4513 EL_STEELWALL_SLIPPERY,
4518 EL_EMC_WALL_SLIPPERY_1,
4519 EL_EMC_WALL_SLIPPERY_2,
4520 EL_EMC_WALL_SLIPPERY_3,
4521 EL_EMC_WALL_SLIPPERY_4,
4542 static int ep_em_slippery_wall[] =
4547 static int ep_gfx_crumbled[] =
4558 static int ep_editor_cascade_active[] =
4560 EL_INTERNAL_CASCADE_BD_ACTIVE,
4561 EL_INTERNAL_CASCADE_EM_ACTIVE,
4562 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4563 EL_INTERNAL_CASCADE_RND_ACTIVE,
4564 EL_INTERNAL_CASCADE_SB_ACTIVE,
4565 EL_INTERNAL_CASCADE_SP_ACTIVE,
4566 EL_INTERNAL_CASCADE_DC_ACTIVE,
4567 EL_INTERNAL_CASCADE_DX_ACTIVE,
4568 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4569 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4570 EL_INTERNAL_CASCADE_CE_ACTIVE,
4571 EL_INTERNAL_CASCADE_GE_ACTIVE,
4572 EL_INTERNAL_CASCADE_REF_ACTIVE,
4573 EL_INTERNAL_CASCADE_USER_ACTIVE,
4574 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4579 static int ep_editor_cascade_inactive[] =
4581 EL_INTERNAL_CASCADE_BD,
4582 EL_INTERNAL_CASCADE_EM,
4583 EL_INTERNAL_CASCADE_EMC,
4584 EL_INTERNAL_CASCADE_RND,
4585 EL_INTERNAL_CASCADE_SB,
4586 EL_INTERNAL_CASCADE_SP,
4587 EL_INTERNAL_CASCADE_DC,
4588 EL_INTERNAL_CASCADE_DX,
4589 EL_INTERNAL_CASCADE_CHARS,
4590 EL_INTERNAL_CASCADE_STEEL_CHARS,
4591 EL_INTERNAL_CASCADE_CE,
4592 EL_INTERNAL_CASCADE_GE,
4593 EL_INTERNAL_CASCADE_REF,
4594 EL_INTERNAL_CASCADE_USER,
4595 EL_INTERNAL_CASCADE_DYNAMIC,
4600 static int ep_obsolete[] =
4604 EL_EM_KEY_1_FILE_OBSOLETE,
4605 EL_EM_KEY_2_FILE_OBSOLETE,
4606 EL_EM_KEY_3_FILE_OBSOLETE,
4607 EL_EM_KEY_4_FILE_OBSOLETE,
4608 EL_ENVELOPE_OBSOLETE,
4617 } element_properties[] =
4619 { ep_diggable, EP_DIGGABLE },
4620 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4621 { ep_dont_run_into, EP_DONT_RUN_INTO },
4622 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4623 { ep_dont_touch, EP_DONT_TOUCH },
4624 { ep_indestructible, EP_INDESTRUCTIBLE },
4625 { ep_slippery, EP_SLIPPERY },
4626 { ep_can_change, EP_CAN_CHANGE },
4627 { ep_can_move, EP_CAN_MOVE },
4628 { ep_can_fall, EP_CAN_FALL },
4629 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4630 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4631 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4632 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4633 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4634 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4635 { ep_walkable_over, EP_WALKABLE_OVER },
4636 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4637 { ep_walkable_under, EP_WALKABLE_UNDER },
4638 { ep_passable_over, EP_PASSABLE_OVER },
4639 { ep_passable_inside, EP_PASSABLE_INSIDE },
4640 { ep_passable_under, EP_PASSABLE_UNDER },
4641 { ep_droppable, EP_DROPPABLE },
4642 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4643 { ep_pushable, EP_PUSHABLE },
4644 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4645 { ep_protected, EP_PROTECTED },
4646 { ep_throwable, EP_THROWABLE },
4647 { ep_can_explode, EP_CAN_EXPLODE },
4648 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4650 { ep_player, EP_PLAYER },
4651 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4652 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4653 { ep_switchable, EP_SWITCHABLE },
4654 { ep_bd_element, EP_BD_ELEMENT },
4655 { ep_sp_element, EP_SP_ELEMENT },
4656 { ep_sb_element, EP_SB_ELEMENT },
4658 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4659 { ep_food_penguin, EP_FOOD_PENGUIN },
4660 { ep_food_pig, EP_FOOD_PIG },
4661 { ep_historic_wall, EP_HISTORIC_WALL },
4662 { ep_historic_solid, EP_HISTORIC_SOLID },
4663 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4664 { ep_belt, EP_BELT },
4665 { ep_belt_active, EP_BELT_ACTIVE },
4666 { ep_belt_switch, EP_BELT_SWITCH },
4667 { ep_tube, EP_TUBE },
4668 { ep_acid_pool, EP_ACID_POOL },
4669 { ep_keygate, EP_KEYGATE },
4670 { ep_amoeboid, EP_AMOEBOID },
4671 { ep_amoebalive, EP_AMOEBALIVE },
4672 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4673 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4674 { ep_can_grow, EP_CAN_GROW },
4675 { ep_active_bomb, EP_ACTIVE_BOMB },
4676 { ep_inactive, EP_INACTIVE },
4678 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4680 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4682 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4683 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4685 { ep_obsolete, EP_OBSOLETE },
4692 /* always start with reliable default values (element has no properties) */
4693 /* (but never initialize clipboard elements after the very first time) */
4694 /* (to be able to use clipboard elements between several levels) */
4695 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4696 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4697 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4698 SET_PROPERTY(i, j, FALSE);
4700 /* set all base element properties from above array definitions */
4701 for (i = 0; element_properties[i].elements != NULL; i++)
4702 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4703 SET_PROPERTY((element_properties[i].elements)[j],
4704 element_properties[i].property, TRUE);
4706 /* copy properties to some elements that are only stored in level file */
4707 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4708 for (j = 0; copy_properties[j][0] != -1; j++)
4709 if (HAS_PROPERTY(copy_properties[j][0], i))
4710 for (k = 1; k <= 4; k++)
4711 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4713 /* set static element properties that are not listed in array definitions */
4714 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4715 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4717 clipboard_elements_initialized = TRUE;
4720 void InitElementPropertiesEngine(int engine_version)
4722 static int no_wall_properties[] =
4725 EP_COLLECTIBLE_ONLY,
4727 EP_DONT_COLLIDE_WITH,
4730 EP_CAN_SMASH_PLAYER,
4731 EP_CAN_SMASH_ENEMIES,
4732 EP_CAN_SMASH_EVERYTHING,
4737 EP_FOOD_DARK_YAMYAM,
4753 /* important: after initialization in InitElementPropertiesStatic(), the
4754 elements are not again initialized to a default value; therefore all
4755 changes have to make sure that they leave the element with a defined
4756 property (which means that conditional property changes must be set to
4757 a reliable default value before) */
4759 /* resolve group elements */
4760 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4761 ResolveGroupElement(EL_GROUP_START + i);
4763 /* set all special, combined or engine dependent element properties */
4764 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4766 /* do not change (already initialized) clipboard elements here */
4767 if (IS_CLIPBOARD_ELEMENT(i))
4770 /* ---------- INACTIVE ------------------------------------------------- */
4771 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4772 i <= EL_CHAR_END) ||
4773 (i >= EL_STEEL_CHAR_START &&
4774 i <= EL_STEEL_CHAR_END)));
4776 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4777 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4778 IS_WALKABLE_INSIDE(i) ||
4779 IS_WALKABLE_UNDER(i)));
4781 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4782 IS_PASSABLE_INSIDE(i) ||
4783 IS_PASSABLE_UNDER(i)));
4785 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4786 IS_PASSABLE_OVER(i)));
4788 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4789 IS_PASSABLE_INSIDE(i)));
4791 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4792 IS_PASSABLE_UNDER(i)));
4794 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4797 /* ---------- COLLECTIBLE ---------------------------------------------- */
4798 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4802 /* ---------- SNAPPABLE ------------------------------------------------ */
4803 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4804 IS_COLLECTIBLE(i) ||
4808 /* ---------- WALL ----------------------------------------------------- */
4809 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4811 for (j = 0; no_wall_properties[j] != -1; j++)
4812 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4813 i >= EL_FIRST_RUNTIME_UNREAL)
4814 SET_PROPERTY(i, EP_WALL, FALSE);
4816 if (IS_HISTORIC_WALL(i))
4817 SET_PROPERTY(i, EP_WALL, TRUE);
4819 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4820 if (engine_version < VERSION_IDENT(2,2,0,0))
4821 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4823 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4825 !IS_COLLECTIBLE(i)));
4827 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4828 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4829 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4831 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4832 IS_INDESTRUCTIBLE(i)));
4834 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4836 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4837 else if (engine_version < VERSION_IDENT(2,2,0,0))
4838 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4840 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4844 if (IS_CUSTOM_ELEMENT(i))
4846 /* these are additional properties which are initially false when set */
4848 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4850 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4851 if (DONT_COLLIDE_WITH(i))
4852 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4854 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4855 if (CAN_SMASH_EVERYTHING(i))
4856 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4857 if (CAN_SMASH_ENEMIES(i))
4858 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4861 /* ---------- CAN_SMASH ------------------------------------------------ */
4862 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4863 CAN_SMASH_ENEMIES(i) ||
4864 CAN_SMASH_EVERYTHING(i)));
4866 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4867 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4868 EXPLODES_BY_FIRE(i)));
4870 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4871 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4872 EXPLODES_SMASHED(i)));
4874 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4875 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4876 EXPLODES_IMPACT(i)));
4878 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4879 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4881 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4882 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4883 i == EL_BLACK_ORB));
4885 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4886 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4888 IS_CUSTOM_ELEMENT(i)));
4890 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4891 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4892 i == EL_SP_ELECTRON));
4894 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4895 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4896 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4897 getMoveIntoAcidProperty(&level, i));
4899 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4900 if (MAYBE_DONT_COLLIDE_WITH(i))
4901 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4902 getDontCollideWithProperty(&level, i));
4904 /* ---------- SP_PORT -------------------------------------------------- */
4905 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4906 IS_PASSABLE_INSIDE(i)));
4908 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4909 for (j = 0; j < level.num_android_clone_elements; j++)
4910 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4912 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4914 /* ---------- CAN_CHANGE ----------------------------------------------- */
4915 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4916 for (j = 0; j < element_info[i].num_change_pages; j++)
4917 if (element_info[i].change_page[j].can_change)
4918 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4920 /* ---------- HAS_ACTION ----------------------------------------------- */
4921 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4922 for (j = 0; j < element_info[i].num_change_pages; j++)
4923 if (element_info[i].change_page[j].has_action)
4924 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4926 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4927 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4930 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4932 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4933 element_info[i].crumbled[ACTION_DEFAULT] !=
4934 element_info[i].graphic[ACTION_DEFAULT]);
4936 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
4937 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4938 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
4941 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4942 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4943 IS_EDITOR_CASCADE_INACTIVE(i)));
4946 /* dynamically adjust element properties according to game engine version */
4948 static int ep_em_slippery_wall[] =
4953 EL_EXPANDABLE_WALL_HORIZONTAL,
4954 EL_EXPANDABLE_WALL_VERTICAL,
4955 EL_EXPANDABLE_WALL_ANY,
4956 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4957 EL_EXPANDABLE_STEELWALL_VERTICAL,
4958 EL_EXPANDABLE_STEELWALL_ANY,
4959 EL_EXPANDABLE_STEELWALL_GROWING,
4963 static int ep_em_explodes_by_fire[] =
4966 EL_EM_DYNAMITE_ACTIVE,
4971 /* special EM style gems behaviour */
4972 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4973 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4974 level.em_slippery_gems);
4976 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4977 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4978 (level.em_slippery_gems &&
4979 engine_version > VERSION_IDENT(2,0,1,0)));
4981 /* special EM style explosion behaviour regarding chain reactions */
4982 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4983 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4984 level.em_explodes_by_fire);
4987 /* this is needed because some graphics depend on element properties */
4988 if (game_status == GAME_MODE_PLAYING)
4989 InitElementGraphicInfo();
4992 void InitElementPropertiesAfterLoading(int engine_version)
4996 /* set some other uninitialized values of custom elements in older levels */
4997 if (engine_version < VERSION_IDENT(3,1,0,0))
4999 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
5001 int element = EL_CUSTOM_START + i;
5003 element_info[element].access_direction = MV_ALL_DIRECTIONS;
5005 element_info[element].explosion_delay = 17;
5006 element_info[element].ignition_delay = 8;
5011 void InitElementPropertiesGfxElement()
5015 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5017 struct ElementInfo *ei = &element_info[i];
5019 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
5023 static void InitGlobal()
5028 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
5030 /* check if element_name_info entry defined for each element in "main.h" */
5031 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
5032 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
5034 element_info[i].token_name = element_name_info[i].token_name;
5035 element_info[i].class_name = element_name_info[i].class_name;
5036 element_info[i].editor_description= element_name_info[i].editor_description;
5039 printf("%04d: %s\n", i, element_name_info[i].token_name);
5043 /* create hash from image config list */
5044 image_config_hash = newSetupFileHash();
5045 for (i = 0; image_config[i].token != NULL; i++)
5046 setHashEntry(image_config_hash,
5047 image_config[i].token,
5048 image_config[i].value);
5050 /* create hash from element token list */
5051 element_token_hash = newSetupFileHash();
5052 for (i = 0; element_name_info[i].token_name != NULL; i++)
5053 setHashEntry(element_token_hash,
5054 element_name_info[i].token_name,
5057 /* create hash from graphic token list */
5058 graphic_token_hash = newSetupFileHash();
5059 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
5060 if (strSuffix(image_config[i].value, ".pcx") ||
5061 strSuffix(image_config[i].value, ".wav") ||
5062 strEqual(image_config[i].value, UNDEFINED_FILENAME))
5063 setHashEntry(graphic_token_hash,
5064 image_config[i].token,
5065 int2str(graphic++, 0));
5067 /* create hash from font token list */
5068 font_token_hash = newSetupFileHash();
5069 for (i = 0; font_info[i].token_name != NULL; i++)
5070 setHashEntry(font_token_hash,
5071 font_info[i].token_name,
5074 /* always start with reliable default values (all elements) */
5075 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5076 ActiveElement[i] = i;
5078 /* now add all entries that have an active state (active elements) */
5079 for (i = 0; element_with_active_state[i].element != -1; i++)
5081 int element = element_with_active_state[i].element;
5082 int element_active = element_with_active_state[i].element_active;
5084 ActiveElement[element] = element_active;
5087 /* always start with reliable default values (all buttons) */
5088 for (i = 0; i < NUM_IMAGE_FILES; i++)
5089 ActiveButton[i] = i;
5091 /* now add all entries that have an active state (active buttons) */
5092 for (i = 0; button_with_active_state[i].button != -1; i++)
5094 int button = button_with_active_state[i].button;
5095 int button_active = button_with_active_state[i].button_active;
5097 ActiveButton[button] = button_active;
5100 /* always start with reliable default values (all fonts) */
5101 for (i = 0; i < NUM_FONTS; i++)
5104 /* now add all entries that have an active state (active fonts) */
5105 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
5107 int font = font_with_active_state[i].font_nr;
5108 int font_active = font_with_active_state[i].font_nr_active;
5110 ActiveFont[font] = font_active;
5113 global.autoplay_leveldir = NULL;
5114 global.convert_leveldir = NULL;
5115 global.create_images_dir = NULL;
5117 global.frames_per_second = 0;
5118 global.fps_slowdown = FALSE;
5119 global.fps_slowdown_factor = 1;
5121 global.border_status = GAME_MODE_MAIN;
5123 global.fading_status = GAME_MODE_MAIN;
5124 global.fading_type = TYPE_ENTER_MENU;
5128 void Execute_Command(char *command)
5132 if (strEqual(command, "print graphicsinfo.conf"))
5134 printf("# You can configure additional/alternative image files here.\n");
5135 printf("# (The entries below are default and therefore commented out.)\n");
5137 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
5139 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5142 for (i = 0; image_config[i].token != NULL; i++)
5143 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
5144 image_config[i].value));
5148 else if (strEqual(command, "print soundsinfo.conf"))
5150 printf("# You can configure additional/alternative sound files here.\n");
5151 printf("# (The entries below are default and therefore commented out.)\n");
5153 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
5155 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5158 for (i = 0; sound_config[i].token != NULL; i++)
5159 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
5160 sound_config[i].value));
5164 else if (strEqual(command, "print musicinfo.conf"))
5166 printf("# You can configure additional/alternative music files here.\n");
5167 printf("# (The entries below are default and therefore commented out.)\n");
5169 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
5171 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5174 for (i = 0; music_config[i].token != NULL; i++)
5175 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
5176 music_config[i].value));
5180 else if (strEqual(command, "print editorsetup.conf"))
5182 printf("# You can configure your personal editor element list here.\n");
5183 printf("# (The entries below are default and therefore commented out.)\n");
5186 /* this is needed to be able to check element list for cascade elements */
5187 InitElementPropertiesStatic();
5188 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5190 PrintEditorElementList();
5194 else if (strEqual(command, "print helpanim.conf"))
5196 printf("# You can configure different element help animations here.\n");
5197 printf("# (The entries below are default and therefore commented out.)\n");
5200 for (i = 0; helpanim_config[i].token != NULL; i++)
5202 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
5203 helpanim_config[i].value));
5205 if (strEqual(helpanim_config[i].token, "end"))
5211 else if (strEqual(command, "print helptext.conf"))
5213 printf("# You can configure different element help text here.\n");
5214 printf("# (The entries below are default and therefore commented out.)\n");
5217 for (i = 0; helptext_config[i].token != NULL; i++)
5218 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
5219 helptext_config[i].value));
5223 else if (strPrefix(command, "dump level "))
5225 char *filename = &command[11];
5227 if (!fileExists(filename))
5228 Error(ERR_EXIT, "cannot open file '%s'", filename);
5230 LoadLevelFromFilename(&level, filename);
5235 else if (strPrefix(command, "dump tape "))
5237 char *filename = &command[10];
5239 if (!fileExists(filename))
5240 Error(ERR_EXIT, "cannot open file '%s'", filename);
5242 LoadTapeFromFilename(filename);
5247 else if (strPrefix(command, "autoplay "))
5249 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
5251 while (*str_ptr != '\0') /* continue parsing string */
5253 /* cut leading whitespace from string, replace it by string terminator */
5254 while (*str_ptr == ' ' || *str_ptr == '\t')
5257 if (*str_ptr == '\0') /* end of string reached */
5260 if (global.autoplay_leveldir == NULL) /* read level set string */
5262 global.autoplay_leveldir = str_ptr;
5263 global.autoplay_all = TRUE; /* default: play all tapes */
5265 for (i = 0; i < MAX_TAPES_PER_SET; i++)
5266 global.autoplay_level[i] = FALSE;
5268 else /* read level number string */
5270 int level_nr = atoi(str_ptr); /* get level_nr value */
5272 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5273 global.autoplay_level[level_nr] = TRUE;
5275 global.autoplay_all = FALSE;
5278 /* advance string pointer to the next whitespace (or end of string) */
5279 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5283 else if (strPrefix(command, "convert "))
5285 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
5286 char *str_ptr = strchr(str_copy, ' ');
5288 global.convert_leveldir = str_copy;
5289 global.convert_level_nr = -1;
5291 if (str_ptr != NULL) /* level number follows */
5293 *str_ptr++ = '\0'; /* terminate leveldir string */
5294 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
5297 else if (strPrefix(command, "create images "))
5299 #if defined(TARGET_SDL)
5300 global.create_images_dir = getStringCopy(&command[14]);
5302 if (access(global.create_images_dir, W_OK) != 0)
5303 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
5304 global.create_images_dir);
5306 Error(ERR_EXIT, "command only available for SDL target");
5311 #if defined(TARGET_SDL)
5312 else if (strEqual(command, "SDL_ListModes"))
5317 SDL_Init(SDL_INIT_VIDEO);
5319 /* get available fullscreen/hardware modes */
5320 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
5322 /* check if there are any modes available */
5325 printf("No modes available!\n");
5330 /* check if our resolution is restricted */
5331 if (modes == (SDL_Rect **)-1)
5333 printf("All resolutions available.\n");
5337 printf("Available Modes:\n");
5339 for(i = 0; modes[i]; i++)
5340 printf(" %d x %d\n", modes[i]->w, modes[i]->h);
5350 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
5354 static void InitSetup()
5356 LoadSetup(); /* global setup info */
5358 /* set some options from setup file */
5360 if (setup.options.verbose)
5361 options.verbose = TRUE;
5364 static void InitGameInfo()
5366 game.restart_level = FALSE;
5369 static void InitPlayerInfo()
5373 /* choose default local player */
5374 local_player = &stored_player[0];
5376 for (i = 0; i < MAX_PLAYERS; i++)
5377 stored_player[i].connected = FALSE;
5379 local_player->connected = TRUE;
5382 static void InitArtworkInfo()
5387 static char *get_string_in_brackets(char *string)
5389 char *string_in_brackets = checked_malloc(strlen(string) + 3);
5391 sprintf(string_in_brackets, "[%s]", string);
5393 return string_in_brackets;
5396 static char *get_level_id_suffix(int id_nr)
5398 char *id_suffix = checked_malloc(1 + 3 + 1);
5400 if (id_nr < 0 || id_nr > 999)
5403 sprintf(id_suffix, ".%03d", id_nr);
5409 static char *get_element_class_token(int element)
5411 char *element_class_name = element_info[element].class_name;
5412 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
5414 sprintf(element_class_token, "[%s]", element_class_name);
5416 return element_class_token;
5419 static char *get_action_class_token(int action)
5421 char *action_class_name = &element_action_info[action].suffix[1];
5422 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
5424 sprintf(action_class_token, "[%s]", action_class_name);
5426 return action_class_token;
5430 static void InitArtworkConfig()
5432 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
5433 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
5434 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
5435 static char *action_id_suffix[NUM_ACTIONS + 1];
5436 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5437 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5438 static char *level_id_suffix[MAX_LEVELS + 1];
5439 static char *dummy[1] = { NULL };
5440 static char *ignore_generic_tokens[] =
5446 static char **ignore_image_tokens;
5447 static char **ignore_sound_tokens;
5448 static char **ignore_music_tokens;
5449 int num_ignore_generic_tokens;
5450 int num_ignore_image_tokens;
5451 int num_ignore_sound_tokens;
5452 int num_ignore_music_tokens;
5455 /* dynamically determine list of generic tokens to be ignored */
5456 num_ignore_generic_tokens = 0;
5457 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5458 num_ignore_generic_tokens++;
5460 /* dynamically determine list of image tokens to be ignored */
5461 num_ignore_image_tokens = num_ignore_generic_tokens;
5462 for (i = 0; image_config_vars[i].token != NULL; i++)
5463 num_ignore_image_tokens++;
5464 ignore_image_tokens =
5465 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5466 for (i = 0; i < num_ignore_generic_tokens; i++)
5467 ignore_image_tokens[i] = ignore_generic_tokens[i];
5468 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5469 ignore_image_tokens[num_ignore_generic_tokens + i] =
5470 image_config_vars[i].token;
5471 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5473 /* dynamically determine list of sound tokens to be ignored */
5474 num_ignore_sound_tokens = num_ignore_generic_tokens;
5475 ignore_sound_tokens =
5476 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5477 for (i = 0; i < num_ignore_generic_tokens; i++)
5478 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5479 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5481 /* dynamically determine list of music tokens to be ignored */
5482 num_ignore_music_tokens = num_ignore_generic_tokens;
5483 ignore_music_tokens =
5484 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5485 for (i = 0; i < num_ignore_generic_tokens; i++)
5486 ignore_music_tokens[i] = ignore_generic_tokens[i];
5487 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5489 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5490 image_id_prefix[i] = element_info[i].token_name;
5491 for (i = 0; i < NUM_FONTS; i++)
5492 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5493 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
5495 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5496 sound_id_prefix[i] = element_info[i].token_name;
5497 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5498 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5499 get_string_in_brackets(element_info[i].class_name);
5500 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
5502 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5503 music_id_prefix[i] = music_prefix_info[i].prefix;
5504 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
5506 for (i = 0; i < NUM_ACTIONS; i++)
5507 action_id_suffix[i] = element_action_info[i].suffix;
5508 action_id_suffix[NUM_ACTIONS] = NULL;
5510 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5511 direction_id_suffix[i] = element_direction_info[i].suffix;
5512 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5514 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5515 special_id_suffix[i] = special_suffix_info[i].suffix;
5516 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5518 for (i = 0; i < MAX_LEVELS; i++)
5519 level_id_suffix[i] = get_level_id_suffix(i);
5520 level_id_suffix[MAX_LEVELS] = NULL;
5522 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5523 image_id_prefix, action_id_suffix, direction_id_suffix,
5524 special_id_suffix, ignore_image_tokens);
5525 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5526 sound_id_prefix, action_id_suffix, dummy,
5527 special_id_suffix, ignore_sound_tokens);
5528 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5529 music_id_prefix, special_id_suffix, level_id_suffix,
5530 dummy, ignore_music_tokens);
5533 static void InitMixer()
5540 void InitGfxBuffers()
5542 ReCreateBitmap(&bitmap_db_store, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5543 ReCreateBitmap(&bitmap_db_cross, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5544 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE, DEFAULT_DEPTH);
5545 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE, DEFAULT_DEPTH);
5546 ReCreateBitmap(&bitmap_db_door, 3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
5547 ReCreateBitmap(&bitmap_db_toons, FULL_SXSIZE, FULL_SYSIZE, DEFAULT_DEPTH);
5549 /* initialize screen properties */
5550 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5551 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5553 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5554 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5555 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5556 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5557 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5559 InitGfxBuffers_SP();
5564 struct GraphicInfo *graphic_info_last = graphic_info;
5565 char *filename_font_initial = NULL;
5566 char *filename_anim_initial = NULL;
5567 Bitmap *bitmap_font_initial = NULL;
5571 /* determine settings for initial font (for displaying startup messages) */
5572 for (i = 0; image_config[i].token != NULL; i++)
5574 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5576 char font_token[128];
5579 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5580 len_font_token = strlen(font_token);
5582 if (strEqual(image_config[i].token, font_token))
5583 filename_font_initial = image_config[i].value;
5584 else if (strlen(image_config[i].token) > len_font_token &&
5585 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5587 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5588 font_initial[j].src_x = atoi(image_config[i].value);
5589 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5590 font_initial[j].src_y = atoi(image_config[i].value);
5591 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5592 font_initial[j].width = atoi(image_config[i].value);
5593 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5594 font_initial[j].height = atoi(image_config[i].value);
5599 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5601 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5602 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5605 if (filename_font_initial == NULL) /* should not happen */
5606 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5611 /* create additional image buffers for double-buffering and cross-fading */
5612 bitmap_db_store = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5613 bitmap_db_cross = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5614 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
5615 bitmap_db_panel = CreateBitmap(DXSIZE, DYSIZE, DEFAULT_DEPTH);
5616 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
5617 bitmap_db_toons = CreateBitmap(FULL_SXSIZE, FULL_SYSIZE, DEFAULT_DEPTH);
5619 /* initialize screen properties */
5620 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5621 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5623 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5624 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5625 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5626 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5629 InitGfxCustomArtworkInfo();
5631 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5633 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5634 font_initial[j].bitmap = bitmap_font_initial;
5636 InitFontGraphicInfo();
5638 font_height = getFontHeight(FC_RED);
5641 DrawInitText(getWindowTitleString(), 20, FC_YELLOW);
5643 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
5645 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
5646 DrawInitText(PROGRAM_WEBSITE_STRING, WIN_YSIZE - 20 - font_height, FC_RED);
5648 DrawInitText("Loading graphics", 120, FC_GREEN);
5652 /* initialize busy animation with default values */
5653 int parameter[NUM_GFX_ARGS];
5654 for (i = 0; i < NUM_GFX_ARGS; i++)
5655 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5656 image_config_suffix[i].token,
5657 image_config_suffix[i].type);
5659 for (i = 0; i < NUM_GFX_ARGS; i++)
5660 printf("::: '%s' => %d\n", image_config_suffix[i].token, parameter[i]);
5664 /* determine settings for busy animation (when displaying startup messages) */
5665 for (i = 0; image_config[i].token != NULL; i++)
5667 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5668 int len_anim_token = strlen(anim_token);
5670 if (strEqual(image_config[i].token, anim_token))
5671 filename_anim_initial = image_config[i].value;
5672 else if (strlen(image_config[i].token) > len_anim_token &&
5673 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5676 for (j = 0; image_config_suffix[j].token != NULL; j++)
5678 if (strEqual(&image_config[i].token[len_anim_token],
5679 image_config_suffix[j].token))
5681 get_graphic_parameter_value(image_config[i].value,
5682 image_config_suffix[j].token,
5683 image_config_suffix[j].type);
5686 if (strEqual(&image_config[i].token[len_anim_token], ".x"))
5687 anim_initial.src_x = atoi(image_config[i].value);
5688 else if (strEqual(&image_config[i].token[len_anim_token], ".y"))
5689 anim_initial.src_y = atoi(image_config[i].value);
5690 else if (strEqual(&image_config[i].token[len_anim_token], ".width"))
5691 anim_initial.width = atoi(image_config[i].value);
5692 else if (strEqual(&image_config[i].token[len_anim_token], ".height"))
5693 anim_initial.height = atoi(image_config[i].value);
5694 else if (strEqual(&image_config[i].token[len_anim_token], ".frames"))
5695 anim_initial.anim_frames = atoi(image_config[i].value);
5696 else if (strEqual(&image_config[i].token[len_anim_token],
5697 ".frames_per_line"))
5698 anim_initial.anim_frames_per_line = atoi(image_config[i].value);
5699 else if (strEqual(&image_config[i].token[len_anim_token], ".delay"))
5700 anim_initial.anim_delay = atoi(image_config[i].value);
5705 #if defined(CREATE_SPECIAL_EDITION_RND_JUE)
5706 filename_anim_initial = "loading.pcx";
5708 parameter[GFX_ARG_X] = 0;
5709 parameter[GFX_ARG_Y] = 0;
5710 parameter[GFX_ARG_WIDTH] = 128;
5711 parameter[GFX_ARG_HEIGHT] = 40;
5712 parameter[GFX_ARG_FRAMES] = 32;
5713 parameter[GFX_ARG_DELAY] = 4;
5714 parameter[GFX_ARG_FRAMES_PER_LINE] = ARG_UNDEFINED_VALUE;
5717 if (filename_anim_initial == NULL) /* should not happen */
5718 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5720 anim_initial.bitmap = LoadCustomImage(filename_anim_initial);
5722 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
5724 set_graphic_parameters_ext(0, parameter, anim_initial.bitmap);
5727 printf("::: INIT_GFX: anim_frames_per_line == %d [%d / %d] [%d, %d]\n",
5728 graphic_info[0].anim_frames_per_line,
5729 get_scaled_graphic_width(0),
5730 graphic_info[0].width,
5731 getOriginalImageWidthFromImageID(0),
5732 graphic_info[0].scale_up_factor);
5735 graphic_info = graphic_info_last;
5737 init.busy.width = anim_initial.width;
5738 init.busy.height = anim_initial.height;
5740 InitMenuDesignSettings_Static();
5741 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5743 /* use copy of busy animation to prevent change while reloading artwork */
5748 void RedrawBackground()
5750 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
5751 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
5753 redraw_mask = REDRAW_ALL;
5756 void InitGfxBackground()
5760 fieldbuffer = bitmap_db_field;
5761 SetDrawtoField(DRAW_BACKBUFFER);
5764 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5768 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
5769 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
5772 for (x = 0; x < MAX_BUF_XSIZE; x++)
5773 for (y = 0; y < MAX_BUF_YSIZE; y++)
5776 redraw_mask = REDRAW_ALL;
5779 static void InitLevelInfo()
5781 LoadLevelInfo(); /* global level info */
5782 LoadLevelSetup_LastSeries(); /* last played series info */
5783 LoadLevelSetup_SeriesInfo(); /* last played level info */
5786 static void InitLevelArtworkInfo()
5788 LoadLevelArtworkInfo();
5791 static void InitImages()
5793 print_timestamp_init("InitImages");
5796 printf("::: leveldir_current->identifier == '%s'\n",
5797 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5798 printf("::: leveldir_current->graphics_path == '%s'\n",
5799 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5800 printf("::: leveldir_current->graphics_set == '%s'\n",
5801 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5802 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5803 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5806 setLevelArtworkDir(artwork.gfx_first);
5809 printf("::: leveldir_current->identifier == '%s'\n",
5810 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5811 printf("::: leveldir_current->graphics_path == '%s'\n",
5812 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5813 printf("::: leveldir_current->graphics_set == '%s'\n",
5814 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5815 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5816 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5820 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5821 leveldir_current->identifier,
5822 artwork.gfx_current_identifier,
5823 artwork.gfx_current->identifier,
5824 leveldir_current->graphics_set,
5825 leveldir_current->graphics_path);
5828 UPDATE_BUSY_STATE();
5830 ReloadCustomImages();
5831 print_timestamp_time("ReloadCustomImages");
5833 UPDATE_BUSY_STATE();
5835 LoadCustomElementDescriptions();
5836 print_timestamp_time("LoadCustomElementDescriptions");
5838 UPDATE_BUSY_STATE();
5840 LoadMenuDesignSettings();
5841 print_timestamp_time("LoadMenuDesignSettings");
5843 UPDATE_BUSY_STATE();
5845 ReinitializeGraphics();
5846 print_timestamp_time("ReinitializeGraphics");
5848 UPDATE_BUSY_STATE();
5850 print_timestamp_done("InitImages");
5853 static void InitSound(char *identifier)
5855 print_timestamp_init("InitSound");
5857 if (identifier == NULL)
5858 identifier = artwork.snd_current->identifier;
5860 /* set artwork path to send it to the sound server process */
5861 setLevelArtworkDir(artwork.snd_first);
5863 InitReloadCustomSounds(identifier);
5864 print_timestamp_time("InitReloadCustomSounds");
5866 ReinitializeSounds();
5867 print_timestamp_time("ReinitializeSounds");
5869 print_timestamp_done("InitSound");
5872 static void InitMusic(char *identifier)
5874 print_timestamp_init("InitMusic");
5876 if (identifier == NULL)
5877 identifier = artwork.mus_current->identifier;
5879 /* set artwork path to send it to the sound server process */
5880 setLevelArtworkDir(artwork.mus_first);
5882 InitReloadCustomMusic(identifier);
5883 print_timestamp_time("InitReloadCustomMusic");
5885 ReinitializeMusic();
5886 print_timestamp_time("ReinitializeMusic");
5888 print_timestamp_done("InitMusic");
5891 void InitNetworkServer()
5893 #if defined(NETWORK_AVALIABLE)
5897 if (!options.network)
5900 #if defined(NETWORK_AVALIABLE)
5901 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5903 if (!ConnectToServer(options.server_host, options.server_port))
5904 Error(ERR_EXIT, "cannot connect to network game server");
5906 SendToServer_PlayerName(setup.player_name);
5907 SendToServer_ProtocolVersion();
5910 SendToServer_NrWanted(nr_wanted);
5914 static boolean CheckArtworkConfigForCustomElements(char *filename)
5916 SetupFileHash *setup_file_hash;
5917 boolean redefined_ce_found = FALSE;
5919 /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */
5921 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5923 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5925 char *token = HASH_ITERATION_TOKEN(itr);
5927 if (strPrefix(token, "custom_"))
5929 redefined_ce_found = TRUE;
5934 END_HASH_ITERATION(setup_file_hash, itr)
5936 freeSetupFileHash(setup_file_hash);
5939 return redefined_ce_found;
5942 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5944 char *filename_base, *filename_local;
5945 boolean redefined_ce_found = FALSE;
5947 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5950 printf("::: leveldir_current->identifier == '%s'\n",
5951 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5952 printf("::: leveldir_current->graphics_path == '%s'\n",
5953 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5954 printf("::: leveldir_current->graphics_set == '%s'\n",
5955 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5956 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5957 leveldir_current == NULL ? "[NULL]" :
5958 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5961 /* first look for special artwork configured in level series config */
5962 filename_base = getCustomArtworkLevelConfigFilename(type);
5965 printf("::: filename_base == '%s'\n", filename_base);
5968 if (fileExists(filename_base))
5969 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5971 filename_local = getCustomArtworkConfigFilename(type);
5974 printf("::: filename_local == '%s'\n", filename_local);
5977 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5978 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5981 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5984 return redefined_ce_found;
5987 static void InitOverrideArtwork()
5989 boolean redefined_ce_found = FALSE;
5991 /* to check if this level set redefines any CEs, do not use overriding */
5992 gfx.override_level_graphics = FALSE;
5993 gfx.override_level_sounds = FALSE;
5994 gfx.override_level_music = FALSE;
5996 /* now check if this level set has definitions for custom elements */
5997 if (setup.override_level_graphics == AUTO ||
5998 setup.override_level_sounds == AUTO ||
5999 setup.override_level_music == AUTO)
6000 redefined_ce_found =
6001 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
6002 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
6003 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
6006 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
6009 if (redefined_ce_found)
6011 /* this level set has CE definitions: change "AUTO" to "FALSE" */
6012 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
6013 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
6014 gfx.override_level_music = (setup.override_level_music == TRUE);
6018 /* this level set has no CE definitions: change "AUTO" to "TRUE" */
6019 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
6020 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
6021 gfx.override_level_music = (setup.override_level_music != FALSE);
6025 printf("::: => %d, %d, %d\n",
6026 gfx.override_level_graphics,
6027 gfx.override_level_sounds,
6028 gfx.override_level_music);
6032 static char *getNewArtworkIdentifier(int type)
6034 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
6035 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
6036 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
6037 static boolean initialized[3] = { FALSE, FALSE, FALSE };
6038 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
6040 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
6042 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
6044 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
6045 char *leveldir_identifier = leveldir_current->identifier;
6047 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
6048 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
6050 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
6052 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
6053 char *artwork_current_identifier;
6054 char *artwork_new_identifier = NULL; /* default: nothing has changed */
6056 /* leveldir_current may be invalid (level group, parent link) */
6057 if (!validLevelSeries(leveldir_current))
6060 /* 1st step: determine artwork set to be activated in descending order:
6061 --------------------------------------------------------------------
6062 1. setup artwork (when configured to override everything else)
6063 2. artwork set configured in "levelinfo.conf" of current level set
6064 (artwork in level directory will have priority when loading later)
6065 3. artwork in level directory (stored in artwork sub-directory)
6066 4. setup artwork (currently configured in setup menu) */
6068 if (setup_override_artwork)
6069 artwork_current_identifier = setup_artwork_set;
6070 else if (leveldir_artwork_set != NULL)
6071 artwork_current_identifier = leveldir_artwork_set;
6072 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
6073 artwork_current_identifier = leveldir_identifier;
6075 artwork_current_identifier = setup_artwork_set;
6078 /* 2nd step: check if it is really needed to reload artwork set
6079 ------------------------------------------------------------ */
6082 if (type == ARTWORK_TYPE_GRAPHICS)
6083 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
6084 artwork_new_identifier,
6085 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
6086 artwork_current_identifier,
6087 leveldir_current->graphics_set,
6088 leveldir_current->identifier);
6091 /* ---------- reload if level set and also artwork set has changed ------- */
6092 if (leveldir_current_identifier[type] != leveldir_identifier &&
6093 (last_has_level_artwork_set[type] || has_level_artwork_set))
6094 artwork_new_identifier = artwork_current_identifier;
6096 leveldir_current_identifier[type] = leveldir_identifier;
6097 last_has_level_artwork_set[type] = has_level_artwork_set;
6100 if (type == ARTWORK_TYPE_GRAPHICS)
6101 printf("::: 1: '%s'\n", artwork_new_identifier);
6104 /* ---------- reload if "override artwork" setting has changed ----------- */
6105 if (last_override_level_artwork[type] != setup_override_artwork)
6106 artwork_new_identifier = artwork_current_identifier;
6108 last_override_level_artwork[type] = setup_override_artwork;
6111 if (type == ARTWORK_TYPE_GRAPHICS)
6112 printf("::: 2: '%s'\n", artwork_new_identifier);
6115 /* ---------- reload if current artwork identifier has changed ----------- */
6116 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
6117 artwork_current_identifier))
6118 artwork_new_identifier = artwork_current_identifier;
6120 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
6123 if (type == ARTWORK_TYPE_GRAPHICS)
6124 printf("::: 3: '%s'\n", artwork_new_identifier);
6127 /* ---------- do not reload directly after starting ---------------------- */
6128 if (!initialized[type])
6129 artwork_new_identifier = NULL;
6131 initialized[type] = TRUE;
6134 if (type == ARTWORK_TYPE_GRAPHICS)
6135 printf("::: 4: '%s'\n", artwork_new_identifier);
6139 if (type == ARTWORK_TYPE_GRAPHICS)
6140 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
6141 artwork.gfx_current_identifier, artwork_current_identifier,
6142 artwork.gfx_current->identifier, leveldir_current->graphics_set,
6143 artwork_new_identifier);
6146 return artwork_new_identifier;
6149 void ReloadCustomArtwork(int force_reload)
6151 int last_game_status = game_status; /* save current game status */
6152 char *gfx_new_identifier;
6153 char *snd_new_identifier;
6154 char *mus_new_identifier;
6155 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
6156 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
6157 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
6158 boolean reload_needed;
6160 InitOverrideArtwork();
6162 force_reload_gfx |= AdjustGraphicsForEMC();
6164 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
6165 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
6166 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
6168 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
6169 snd_new_identifier != NULL || force_reload_snd ||
6170 mus_new_identifier != NULL || force_reload_mus);
6175 print_timestamp_init("ReloadCustomArtwork");
6177 game_status = GAME_MODE_LOADING;
6179 FadeOut(REDRAW_ALL);
6182 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6184 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
6186 print_timestamp_time("ClearRectangle");
6189 printf("::: fading in ... %d\n", fading.fade_mode);
6193 printf("::: done\n");
6196 if (gfx_new_identifier != NULL || force_reload_gfx)
6199 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
6200 artwork.gfx_current_identifier,
6202 artwork.gfx_current->identifier,
6203 leveldir_current->graphics_set);
6207 print_timestamp_time("InitImages");
6210 if (snd_new_identifier != NULL || force_reload_snd)
6212 InitSound(snd_new_identifier);
6213 print_timestamp_time("InitSound");
6216 if (mus_new_identifier != NULL || force_reload_mus)
6218 InitMusic(mus_new_identifier);
6219 print_timestamp_time("InitMusic");
6222 game_status = last_game_status; /* restore current game status */
6224 init_last = init; /* switch to new busy animation */
6227 printf("::: ----------------DELAY 1 ...\n");
6232 printf("::: FadeOut @ ReloadCustomArtwork ...\n");
6234 FadeOut(REDRAW_ALL);
6236 printf("::: FadeOut @ ReloadCustomArtwork done\n");
6241 /* force redraw of (open or closed) door graphics */
6242 SetDoorState(DOOR_OPEN_ALL);
6243 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
6248 FadeSetEnterScreen();
6249 FadeSkipNextFadeOut();
6250 // FadeSetDisabled();
6255 fading = fading_none;
6260 redraw_mask = REDRAW_ALL;
6263 print_timestamp_done("ReloadCustomArtwork");
6266 void KeyboardAutoRepeatOffUnlessAutoplay()
6268 if (global.autoplay_leveldir == NULL)
6269 KeyboardAutoRepeatOff();
6273 /* ========================================================================= */
6275 /* ========================================================================= */
6279 print_timestamp_init("OpenAll");
6281 game_status = GAME_MODE_LOADING;
6287 InitGlobal(); /* initialize some global variables */
6289 print_timestamp_time("[init global stuff]");
6291 if (options.execute_command)
6292 Execute_Command(options.execute_command);
6294 if (options.serveronly)
6296 #if defined(PLATFORM_UNIX)
6297 NetworkServer(options.server_port, options.serveronly);
6299 Error(ERR_WARN, "networking only supported in Unix version");
6302 exit(0); /* never reached, server loops forever */
6309 InitArtworkInfo(); /* needed before loading gfx, sound & music */
6310 InitArtworkConfig(); /* needed before forking sound child process */
6317 InitRND(NEW_RANDOMIZE);
6318 InitSimpleRandom(NEW_RANDOMIZE);
6322 print_timestamp_time("[init setup/config stuff]");
6325 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
6327 InitEventFilter(FilterMouseMotionEvents);
6329 print_timestamp_time("[init video stuff]");
6331 InitElementPropertiesStatic();
6332 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
6333 InitElementPropertiesGfxElement();
6335 print_timestamp_time("[init element properties stuff]");
6339 print_timestamp_time("InitGfx");
6342 print_timestamp_time("InitLevelInfo");
6344 InitLevelArtworkInfo();
6345 print_timestamp_time("InitLevelArtworkInfo");
6347 InitOverrideArtwork(); /* needs to know current level directory */
6348 print_timestamp_time("InitOverrideArtwork");
6350 InitImages(); /* needs to know current level directory */
6351 print_timestamp_time("InitImages");
6353 InitSound(NULL); /* needs to know current level directory */
6354 print_timestamp_time("InitSound");
6356 InitMusic(NULL); /* needs to know current level directory */
6357 print_timestamp_time("InitMusic");
6359 InitGfxBackground();
6369 if (global.autoplay_leveldir)
6374 else if (global.convert_leveldir)
6379 else if (global.create_images_dir)
6381 CreateLevelSketchImages();
6385 game_status = GAME_MODE_MAIN;
6388 FadeSetEnterScreen();
6389 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
6390 FadeSkipNextFadeOut();
6391 // FadeSetDisabled();
6393 fading = fading_none;
6396 print_timestamp_time("[post-artwork]");
6398 print_timestamp_done("OpenAll");
6402 InitNetworkServer();
6405 void CloseAllAndExit(int exit_value)
6410 CloseAudio(); /* called after freeing sounds (needed for SDL) */
6422 #if defined(TARGET_SDL)
6423 if (network_server) /* terminate network server */
6424 SDL_KillThread(server_thread);
6427 CloseVideoDisplay();
6428 ClosePlatformDependentStuff();
6430 if (exit_value != 0)
6431 NotifyUserAboutErrorFile();