1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2006 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
14 #include "libgame/libgame.h"
29 #include "conf_e2g.c" /* include auto-generated data structure definitions */
30 #include "conf_esg.c" /* include auto-generated data structure definitions */
31 #include "conf_e2s.c" /* include auto-generated data structure definitions */
32 #include "conf_fnt.c" /* include auto-generated data structure definitions */
33 #include "conf_g2s.c" /* include auto-generated data structure definitions */
34 #include "conf_g2m.c" /* include auto-generated data structure definitions */
35 #include "conf_act.c" /* include auto-generated data structure definitions */
38 #define CONFIG_TOKEN_FONT_INITIAL "font.initial"
39 #define CONFIG_TOKEN_GLOBAL_BUSY "global.busy"
41 #define DEBUG_PRINT_INIT_TIMESTAMPS TRUE
42 #define DEBUG_PRINT_INIT_TIMESTAMPS_DEPTH 1
45 static struct FontBitmapInfo font_initial[NUM_INITIAL_FONTS];
46 static struct GraphicInfo anim_initial;
48 static int copy_properties[][5] =
52 EL_BUG_LEFT, EL_BUG_RIGHT,
53 EL_BUG_UP, EL_BUG_DOWN
57 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
58 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
62 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
63 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
67 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
68 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
72 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
73 EL_PACMAN_UP, EL_PACMAN_DOWN
77 EL_YAMYAM_LEFT, EL_YAMYAM_RIGHT,
78 EL_YAMYAM_UP, EL_YAMYAM_DOWN
82 EL_MOLE_LEFT, EL_MOLE_RIGHT,
83 EL_MOLE_UP, EL_MOLE_DOWN
92 static void print_timestamp_ext(char *message, char *mode)
95 #if DEBUG_PRINT_INIT_TIMESTAMPS
96 static char *debug_message = NULL;
97 static char *last_message = NULL;
98 static int counter_nr = 0;
99 int max_depth = DEBUG_PRINT_INIT_TIMESTAMPS_DEPTH;
101 checked_free(debug_message);
102 debug_message = getStringCat3(mode, " ", message);
104 if (strEqual(mode, "INIT"))
106 debug_print_timestamp(counter_nr, NULL);
108 if (counter_nr + 1 < max_depth)
109 debug_print_timestamp(counter_nr, debug_message);
113 debug_print_timestamp(counter_nr, NULL);
115 else if (strEqual(mode, "DONE"))
119 if (counter_nr + 1 < max_depth ||
120 (counter_nr == 0 && max_depth == 1))
122 last_message = message;
124 if (counter_nr == 0 && max_depth == 1)
126 checked_free(debug_message);
127 debug_message = getStringCat3("TIME", " ", message);
130 debug_print_timestamp(counter_nr, debug_message);
133 else if (!strEqual(mode, "TIME") ||
134 !strEqual(message, last_message))
136 if (counter_nr < max_depth)
137 debug_print_timestamp(counter_nr, debug_message);
143 static void print_timestamp_init(char *message)
145 print_timestamp_ext(message, "INIT");
148 static void print_timestamp_time(char *message)
150 print_timestamp_ext(message, "TIME");
153 static void print_timestamp_done(char *message)
155 print_timestamp_ext(message, "DONE");
160 struct GraphicInfo *graphic_info_last = graphic_info;
162 static unsigned long action_delay = 0;
163 unsigned long action_delay_value = GameFrameDelay;
164 int sync_frame = FrameCounter;
167 if (game_status != GAME_MODE_LOADING)
170 if (anim_initial.bitmap == NULL || window == NULL)
173 if (!DelayReached(&action_delay, action_delay_value))
178 static unsigned long last_counter = -1;
179 unsigned long current_counter = Counter();
180 unsigned long delay = current_counter - last_counter;
182 if (last_counter != -1 && delay > action_delay_value + 5)
183 printf("::: DrawInitAnim: DELAY TOO LONG: %ld\n", delay);
185 last_counter = current_counter;
189 x = ALIGNED_TEXT_XPOS(&init_last.busy);
190 y = ALIGNED_TEXT_YPOS(&init_last.busy);
192 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
196 static boolean done = FALSE;
199 printf("::: %d, %d, %d, %d => %d, %d [%d, %d] [%d, %d]\n",
200 init.busy.x, init.busy.y,
201 init.busy.align, init.busy.valign,
203 graphic_info[graphic].width,
204 graphic_info[graphic].height,
205 sync_frame, anim_initial.anim_delay);
211 if (sync_frame % anim_initial.anim_delay == 0)
216 int width = graphic_info[graphic].width;
217 int height = graphic_info[graphic].height;
218 int frame = getGraphicAnimationFrame(graphic, sync_frame);
220 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
221 BlitBitmap(src_bitmap, window, src_x, src_y, width, height, x, y);
223 /* !!! this can only draw TILEX/TILEY size animations !!! */
224 DrawGraphicAnimationExt(window, x, y, graphic, sync_frame, NO_MASKING);
228 graphic_info = graphic_info_last;
235 FreeLevelEditorGadgets();
244 static boolean gadgets_initialized = FALSE;
246 if (gadgets_initialized)
249 CreateLevelEditorGadgets();
253 CreateScreenGadgets();
255 InitGadgetsSoundCallback(PlaySoundActivating, PlaySoundSelecting);
257 gadgets_initialized = TRUE;
260 inline void InitElementSmallImagesScaledUp(int graphic)
263 struct FileInfo *fi = getImageListEntryFromImageID(graphic);
265 printf("::: '%s' -> '%s'\n", fi->token, fi->filename);
268 CreateImageWithSmallImages(graphic, graphic_info[graphic].scale_up_factor);
271 void InitElementSmallImages()
273 static int special_graphics[] =
275 IMG_EDITOR_ELEMENT_BORDER,
276 IMG_EDITOR_ELEMENT_BORDER_INPUT,
277 IMG_EDITOR_CASCADE_LIST,
278 IMG_EDITOR_CASCADE_LIST_ACTIVE,
281 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
282 int num_property_mappings = getImageListPropertyMappingSize();
285 /* initialize normal images from static configuration */
286 for (i = 0; element_to_graphic[i].element > -1; i++)
287 InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
289 /* initialize special images from static configuration */
290 for (i = 0; element_to_special_graphic[i].element > -1; i++)
291 InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
293 /* initialize images from dynamic configuration (may be elements or other) */
294 for (i = 0; i < num_property_mappings; i++)
295 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
297 /* initialize special images from above list (non-element images) */
298 for (i = 0; special_graphics[i] > -1; i++)
299 InitElementSmallImagesScaledUp(special_graphics[i]);
302 void InitScaledImages()
306 /* scale normal images from static configuration, if not already scaled */
307 for (i = 0; i < NUM_IMAGE_FILES; i++)
308 ScaleImage(i, graphic_info[i].scale_up_factor);
312 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
313 void SetBitmaps_EM(Bitmap **em_bitmap)
315 em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
316 em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].bitmap;
321 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
322 void SetBitmaps_SP(Bitmap **sp_bitmap)
324 *sp_bitmap = graphic_info[IMG_SP_OBJECTS].bitmap;
328 static int getFontBitmapID(int font_nr)
332 /* (special case: do not use special font for GAME_MODE_LOADING) */
333 if (game_status >= GAME_MODE_TITLE_INITIAL &&
334 game_status <= GAME_MODE_PSEUDO_PREVIEW)
335 special = game_status;
336 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
337 special = GFX_SPECIAL_ARG_MAIN;
339 else if (game_status == GAME_MODE_PLAYING)
340 special = GFX_SPECIAL_ARG_DOOR;
347 font_info[font_nr].token_name,
348 special_suffix_info[special].suffix);
353 return font_info[font_nr].special_bitmap_id[special];
358 static int getFontFromToken(char *token)
361 char *value = getHashEntry(font_token_hash, token);
368 /* !!! OPTIMIZE THIS BY USING HASH !!! */
369 for (i = 0; i < NUM_FONTS; i++)
370 if (strEqual(token, font_info[i].token_name))
374 /* if font not found, use reliable default value */
375 return FONT_INITIAL_1;
378 void InitFontGraphicInfo()
380 static struct FontBitmapInfo *font_bitmap_info = NULL;
381 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
382 int num_property_mappings = getImageListPropertyMappingSize();
383 int num_font_bitmaps = NUM_FONTS;
386 if (graphic_info == NULL) /* still at startup phase */
388 InitFontInfo(font_initial, NUM_INITIAL_FONTS,
389 getFontBitmapID, getFontFromToken);
394 /* ---------- initialize font graphic definitions ---------- */
396 /* always start with reliable default values (normal font graphics) */
397 for (i = 0; i < NUM_FONTS; i++)
398 font_info[i].graphic = IMG_FONT_INITIAL_1;
400 /* initialize normal font/graphic mapping from static configuration */
401 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
403 int font_nr = font_to_graphic[i].font_nr;
404 int special = font_to_graphic[i].special;
405 int graphic = font_to_graphic[i].graphic;
410 font_info[font_nr].graphic = graphic;
413 /* always start with reliable default values (special font graphics) */
414 for (i = 0; i < NUM_FONTS; i++)
416 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
418 font_info[i].special_graphic[j] = font_info[i].graphic;
419 font_info[i].special_bitmap_id[j] = i;
423 /* initialize special font/graphic mapping from static configuration */
424 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
426 int font_nr = font_to_graphic[i].font_nr;
427 int special = font_to_graphic[i].special;
428 int graphic = font_to_graphic[i].graphic;
429 int base_graphic = font2baseimg(font_nr);
431 if (IS_SPECIAL_GFX_ARG(special))
433 boolean base_redefined =
434 getImageListEntryFromImageID(base_graphic)->redefined;
435 boolean special_redefined =
436 getImageListEntryFromImageID(graphic)->redefined;
437 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
439 /* if the base font ("font.title_1", for example) has been redefined,
440 but not the special font ("font.title_1.LEVELS", for example), do not
441 use an existing (in this case considered obsolete) special font
442 anymore, but use the automatically determined default font */
443 /* special case: cloned special fonts must be explicitly redefined,
444 but are not automatically redefined by redefining base font */
445 if (base_redefined && !special_redefined && !special_cloned)
448 font_info[font_nr].special_graphic[special] = graphic;
449 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
454 /* initialize special font/graphic mapping from dynamic configuration */
455 for (i = 0; i < num_property_mappings; i++)
457 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
458 int special = property_mapping[i].ext3_index;
459 int graphic = property_mapping[i].artwork_index;
464 if (IS_SPECIAL_GFX_ARG(special))
466 font_info[font_nr].special_graphic[special] = graphic;
467 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
472 /* correct special font/graphic mapping for cloned fonts for downwards
473 compatibility of PREVIEW fonts -- this is only needed for implicit
474 redefinition of special font by redefined base font, and only if other
475 fonts are cloned from this special font (like in the "Zelda" level set) */
476 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
478 int font_nr = font_to_graphic[i].font_nr;
479 int special = font_to_graphic[i].special;
480 int graphic = font_to_graphic[i].graphic;
482 if (IS_SPECIAL_GFX_ARG(special))
484 boolean special_redefined =
485 getImageListEntryFromImageID(graphic)->redefined;
486 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
488 if (special_cloned && !special_redefined)
492 for (j = 0; font_to_graphic[j].font_nr > -1; j++)
494 int font_nr2 = font_to_graphic[j].font_nr;
495 int special2 = font_to_graphic[j].special;
496 int graphic2 = font_to_graphic[j].graphic;
498 if (IS_SPECIAL_GFX_ARG(special2) &&
499 graphic2 == graphic_info[graphic].clone_from)
501 font_info[font_nr].special_graphic[special] =
502 font_info[font_nr2].special_graphic[special2];
503 font_info[font_nr].special_bitmap_id[special] =
504 font_info[font_nr2].special_bitmap_id[special2];
511 /* reset non-redefined ".active" font graphics if normal font is redefined */
512 /* (this different treatment is needed because normal and active fonts are
513 independently defined ("active" is not a property of font definitions!) */
514 for (i = 0; i < NUM_FONTS; i++)
516 int font_nr_base = i;
517 int font_nr_active = FONT_ACTIVE(font_nr_base);
519 /* check only those fonts with exist as normal and ".active" variant */
520 if (font_nr_base != font_nr_active)
522 int base_graphic = font_info[font_nr_base].graphic;
523 int active_graphic = font_info[font_nr_active].graphic;
524 boolean base_redefined =
525 getImageListEntryFromImageID(base_graphic)->redefined;
526 boolean active_redefined =
527 getImageListEntryFromImageID(active_graphic)->redefined;
529 /* if the base font ("font.menu_1", for example) has been redefined,
530 but not the active font ("font.menu_1.active", for example), do not
531 use an existing (in this case considered obsolete) active font
532 anymore, but use the automatically determined default font */
533 if (base_redefined && !active_redefined)
534 font_info[font_nr_active].graphic = base_graphic;
536 /* now also check each "special" font (which may be the same as above) */
537 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
539 int base_graphic = font_info[font_nr_base].special_graphic[j];
540 int active_graphic = font_info[font_nr_active].special_graphic[j];
541 boolean base_redefined =
542 getImageListEntryFromImageID(base_graphic)->redefined;
543 boolean active_redefined =
544 getImageListEntryFromImageID(active_graphic)->redefined;
546 /* same as above, but check special graphic definitions, for example:
547 redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN" */
548 if (base_redefined && !active_redefined)
550 font_info[font_nr_active].special_graphic[j] =
551 font_info[font_nr_base].special_graphic[j];
552 font_info[font_nr_active].special_bitmap_id[j] =
553 font_info[font_nr_base].special_bitmap_id[j];
559 /* ---------- initialize font bitmap array ---------- */
561 if (font_bitmap_info != NULL)
562 FreeFontInfo(font_bitmap_info);
565 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
567 /* ---------- initialize font bitmap definitions ---------- */
569 for (i = 0; i < NUM_FONTS; i++)
571 if (i < NUM_INITIAL_FONTS)
573 font_bitmap_info[i] = font_initial[i];
577 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
579 int font_bitmap_id = font_info[i].special_bitmap_id[j];
580 int graphic = font_info[i].special_graphic[j];
582 /* set 'graphic_info' for font entries, if uninitialized (guessed) */
583 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
585 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
586 graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
589 /* copy font relevant information from graphics information */
590 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
591 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
592 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
593 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
594 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
596 font_bitmap_info[font_bitmap_id].draw_xoffset =
597 graphic_info[graphic].draw_xoffset;
598 font_bitmap_info[font_bitmap_id].draw_yoffset =
599 graphic_info[graphic].draw_yoffset;
601 font_bitmap_info[font_bitmap_id].num_chars =
602 graphic_info[graphic].anim_frames;
603 font_bitmap_info[font_bitmap_id].num_chars_per_line =
604 graphic_info[graphic].anim_frames_per_line;
608 InitFontInfo(font_bitmap_info, num_font_bitmaps,
609 getFontBitmapID, getFontFromToken);
612 void InitElementGraphicInfo()
614 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
615 int num_property_mappings = getImageListPropertyMappingSize();
618 if (graphic_info == NULL) /* still at startup phase */
621 /* set values to -1 to identify later as "uninitialized" values */
622 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
624 for (act = 0; act < NUM_ACTIONS; act++)
626 element_info[i].graphic[act] = -1;
627 element_info[i].crumbled[act] = -1;
629 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
631 element_info[i].direction_graphic[act][dir] = -1;
632 element_info[i].direction_crumbled[act][dir] = -1;
639 /* initialize normal element/graphic mapping from static configuration */
640 for (i = 0; element_to_graphic[i].element > -1; i++)
642 int element = element_to_graphic[i].element;
643 int action = element_to_graphic[i].action;
644 int direction = element_to_graphic[i].direction;
645 boolean crumbled = element_to_graphic[i].crumbled;
646 int graphic = element_to_graphic[i].graphic;
647 int base_graphic = el2baseimg(element);
649 if (graphic_info[graphic].bitmap == NULL)
652 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
655 boolean base_redefined =
656 getImageListEntryFromImageID(base_graphic)->redefined;
657 boolean act_dir_redefined =
658 getImageListEntryFromImageID(graphic)->redefined;
660 /* if the base graphic ("emerald", for example) has been redefined,
661 but not the action graphic ("emerald.falling", for example), do not
662 use an existing (in this case considered obsolete) action graphic
663 anymore, but use the automatically determined default graphic */
664 if (base_redefined && !act_dir_redefined)
669 action = ACTION_DEFAULT;
674 element_info[element].direction_crumbled[action][direction] = graphic;
676 element_info[element].crumbled[action] = graphic;
681 element_info[element].direction_graphic[action][direction] = graphic;
683 element_info[element].graphic[action] = graphic;
687 /* initialize normal element/graphic mapping from dynamic configuration */
688 for (i = 0; i < num_property_mappings; i++)
690 int element = property_mapping[i].base_index;
691 int action = property_mapping[i].ext1_index;
692 int direction = property_mapping[i].ext2_index;
693 int special = property_mapping[i].ext3_index;
694 int graphic = property_mapping[i].artwork_index;
695 boolean crumbled = FALSE;
698 if ((element == EL_EM_DYNAMITE ||
699 element == EL_EM_DYNAMITE_ACTIVE) &&
700 action == ACTION_ACTIVE &&
701 (special == GFX_SPECIAL_ARG_EDITOR ||
702 special == GFX_SPECIAL_ARG_PANEL))
703 printf("::: DYNAMIC: %d, %d, %d -> %d\n",
704 element, action, special, graphic);
707 if (special == GFX_SPECIAL_ARG_CRUMBLED)
713 if (graphic_info[graphic].bitmap == NULL)
716 if (element >= MAX_NUM_ELEMENTS || special != -1)
720 action = ACTION_DEFAULT;
725 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
726 element_info[element].direction_crumbled[action][dir] = -1;
729 element_info[element].direction_crumbled[action][direction] = graphic;
731 element_info[element].crumbled[action] = graphic;
736 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
737 element_info[element].direction_graphic[action][dir] = -1;
740 element_info[element].direction_graphic[action][direction] = graphic;
742 element_info[element].graphic[action] = graphic;
746 /* now copy all graphics that are defined to be cloned from other graphics */
747 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
749 int graphic = element_info[i].graphic[ACTION_DEFAULT];
750 int crumbled_like, diggable_like;
755 crumbled_like = graphic_info[graphic].crumbled_like;
756 diggable_like = graphic_info[graphic].diggable_like;
758 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
760 for (act = 0; act < NUM_ACTIONS; act++)
761 element_info[i].crumbled[act] =
762 element_info[crumbled_like].crumbled[act];
763 for (act = 0; act < NUM_ACTIONS; act++)
764 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
765 element_info[i].direction_crumbled[act][dir] =
766 element_info[crumbled_like].direction_crumbled[act][dir];
769 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
771 element_info[i].graphic[ACTION_DIGGING] =
772 element_info[diggable_like].graphic[ACTION_DIGGING];
773 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
774 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
775 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
780 /* set hardcoded definitions for some runtime elements without graphic */
781 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
785 /* set hardcoded definitions for some internal elements without graphic */
786 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
788 if (IS_EDITOR_CASCADE_INACTIVE(i))
789 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
790 else if (IS_EDITOR_CASCADE_ACTIVE(i))
791 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
795 /* now set all undefined/invalid graphics to -1 to set to default after it */
796 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
798 for (act = 0; act < NUM_ACTIONS; act++)
802 graphic = element_info[i].graphic[act];
803 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
804 element_info[i].graphic[act] = -1;
806 graphic = element_info[i].crumbled[act];
807 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
808 element_info[i].crumbled[act] = -1;
810 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
812 graphic = element_info[i].direction_graphic[act][dir];
813 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
814 element_info[i].direction_graphic[act][dir] = -1;
816 graphic = element_info[i].direction_crumbled[act][dir];
817 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
818 element_info[i].direction_crumbled[act][dir] = -1;
825 /* adjust graphics with 2nd tile for movement according to direction
826 (do this before correcting '-1' values to minimize calculations) */
827 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
829 for (act = 0; act < NUM_ACTIONS; act++)
831 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
833 int graphic = element_info[i].direction_graphic[act][dir];
834 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
836 if (act == ACTION_FALLING) /* special case */
837 graphic = element_info[i].graphic[act];
840 graphic_info[graphic].double_movement &&
841 graphic_info[graphic].swap_double_tiles != 0)
843 struct GraphicInfo *g = &graphic_info[graphic];
844 int src_x_front = g->src_x;
845 int src_y_front = g->src_y;
846 int src_x_back = g->src_x + g->offset2_x;
847 int src_y_back = g->src_y + g->offset2_y;
848 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
850 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
851 src_y_front < src_y_back);
852 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
853 boolean swap_movement_tiles_autodetected =
854 (!frames_are_ordered_diagonally &&
855 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
856 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
857 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
858 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
861 /* swap frontside and backside graphic tile coordinates, if needed */
862 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
864 /* get current (wrong) backside tile coordinates */
865 getGraphicSourceExt(graphic, 0, &dummy, &src_x_back, &src_y_back,
868 /* set frontside tile coordinates to backside tile coordinates */
869 g->src_x = src_x_back;
870 g->src_y = src_y_back;
872 /* invert tile offset to point to new backside tile coordinates */
876 /* do not swap front and backside tiles again after correction */
877 g->swap_double_tiles = 0;
886 /* now set all '-1' values to element specific default values */
887 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
889 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
890 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
891 int default_direction_graphic[NUM_DIRECTIONS_FULL];
892 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
894 if (default_graphic == -1)
895 default_graphic = IMG_UNKNOWN;
897 if (default_crumbled == -1)
898 default_crumbled = default_graphic;
900 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
901 if (default_crumbled == -1)
902 default_crumbled = IMG_EMPTY;
905 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
907 default_direction_graphic[dir] =
908 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
909 default_direction_crumbled[dir] =
910 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
912 if (default_direction_graphic[dir] == -1)
913 default_direction_graphic[dir] = default_graphic;
915 if (default_direction_crumbled[dir] == -1)
916 default_direction_crumbled[dir] = default_direction_graphic[dir];
918 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
919 if (default_direction_crumbled[dir] == -1)
920 default_direction_crumbled[dir] = default_crumbled;
924 for (act = 0; act < NUM_ACTIONS; act++)
926 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
927 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
928 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
929 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
930 act == ACTION_TURNING_FROM_RIGHT ||
931 act == ACTION_TURNING_FROM_UP ||
932 act == ACTION_TURNING_FROM_DOWN);
934 /* generic default action graphic (defined by "[default]" directive) */
935 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
936 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
937 int default_remove_graphic = IMG_EMPTY;
939 if (act_remove && default_action_graphic != -1)
940 default_remove_graphic = default_action_graphic;
942 /* look for special default action graphic (classic game specific) */
943 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
944 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
945 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
946 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
947 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
948 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
950 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
951 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
952 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
953 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
954 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
955 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
958 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
959 /* !!! make this better !!! */
960 if (i == EL_EMPTY_SPACE)
962 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
963 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
967 if (default_action_graphic == -1)
968 default_action_graphic = default_graphic;
970 if (default_action_crumbled == -1)
971 default_action_crumbled = default_action_graphic;
973 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
974 if (default_action_crumbled == -1)
975 default_action_crumbled = default_crumbled;
978 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
980 /* use action graphic as the default direction graphic, if undefined */
981 int default_action_direction_graphic = element_info[i].graphic[act];
982 int default_action_direction_crumbled = element_info[i].crumbled[act];
984 /* no graphic for current action -- use default direction graphic */
985 if (default_action_direction_graphic == -1)
986 default_action_direction_graphic =
987 (act_remove ? default_remove_graphic :
989 element_info[i].direction_graphic[ACTION_TURNING][dir] :
990 default_action_graphic != default_graphic ?
991 default_action_graphic :
992 default_direction_graphic[dir]);
994 if (element_info[i].direction_graphic[act][dir] == -1)
995 element_info[i].direction_graphic[act][dir] =
996 default_action_direction_graphic;
999 if (default_action_direction_crumbled == -1)
1000 default_action_direction_crumbled =
1001 element_info[i].direction_graphic[act][dir];
1003 if (default_action_direction_crumbled == -1)
1004 default_action_direction_crumbled =
1005 (act_remove ? default_remove_graphic :
1007 element_info[i].direction_crumbled[ACTION_TURNING][dir] :
1008 default_action_crumbled != default_crumbled ?
1009 default_action_crumbled :
1010 default_direction_crumbled[dir]);
1013 if (element_info[i].direction_crumbled[act][dir] == -1)
1014 element_info[i].direction_crumbled[act][dir] =
1015 default_action_direction_crumbled;
1018 /* no graphic for this specific action -- use default action graphic */
1019 if (element_info[i].graphic[act] == -1)
1020 element_info[i].graphic[act] =
1021 (act_remove ? default_remove_graphic :
1022 act_turning ? element_info[i].graphic[ACTION_TURNING] :
1023 default_action_graphic);
1025 if (element_info[i].crumbled[act] == -1)
1026 element_info[i].crumbled[act] = element_info[i].graphic[act];
1028 if (element_info[i].crumbled[act] == -1)
1029 element_info[i].crumbled[act] =
1030 (act_remove ? default_remove_graphic :
1031 act_turning ? element_info[i].crumbled[ACTION_TURNING] :
1032 default_action_crumbled);
1037 UPDATE_BUSY_STATE();
1040 /* !!! THIS ALSO CLEARS SPECIAL FLAGS (AND IS NOT NEEDED ANYWAY) !!! */
1041 /* set animation mode to "none" for each graphic with only 1 frame */
1042 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1044 for (act = 0; act < NUM_ACTIONS; act++)
1046 int graphic = element_info[i].graphic[act];
1047 int crumbled = element_info[i].crumbled[act];
1049 if (graphic_info[graphic].anim_frames == 1)
1050 graphic_info[graphic].anim_mode = ANIM_NONE;
1051 if (graphic_info[crumbled].anim_frames == 1)
1052 graphic_info[crumbled].anim_mode = ANIM_NONE;
1054 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1056 graphic = element_info[i].direction_graphic[act][dir];
1057 crumbled = element_info[i].direction_crumbled[act][dir];
1059 if (graphic_info[graphic].anim_frames == 1)
1060 graphic_info[graphic].anim_mode = ANIM_NONE;
1061 if (graphic_info[crumbled].anim_frames == 1)
1062 graphic_info[crumbled].anim_mode = ANIM_NONE;
1070 if (options.verbose)
1072 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1073 if (element_info[i].graphic[ACTION_DEFAULT] == IMG_UNKNOWN &&
1075 Error(ERR_INFO, "warning: no graphic for element '%s' (%d)",
1076 element_info[i].token_name, i);
1082 void InitElementSpecialGraphicInfo()
1084 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
1085 int num_property_mappings = getImageListPropertyMappingSize();
1088 /* always start with reliable default values */
1089 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1090 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1091 element_info[i].special_graphic[j] =
1092 element_info[i].graphic[ACTION_DEFAULT];
1094 /* initialize special element/graphic mapping from static configuration */
1095 for (i = 0; element_to_special_graphic[i].element > -1; i++)
1097 int element = element_to_special_graphic[i].element;
1098 int special = element_to_special_graphic[i].special;
1099 int graphic = element_to_special_graphic[i].graphic;
1100 int base_graphic = el2baseimg(element);
1101 boolean base_redefined =
1102 getImageListEntryFromImageID(base_graphic)->redefined;
1103 boolean special_redefined =
1104 getImageListEntryFromImageID(graphic)->redefined;
1107 if ((element == EL_EM_DYNAMITE ||
1108 element == EL_EM_DYNAMITE_ACTIVE) &&
1109 (special == GFX_SPECIAL_ARG_EDITOR ||
1110 special == GFX_SPECIAL_ARG_PANEL))
1111 printf("::: SPECIAL STATIC: %d, %d -> %d\n",
1112 element, special, graphic);
1115 /* if the base graphic ("emerald", for example) has been redefined,
1116 but not the special graphic ("emerald.EDITOR", for example), do not
1117 use an existing (in this case considered obsolete) special graphic
1118 anymore, but use the automatically created (down-scaled) graphic */
1119 if (base_redefined && !special_redefined)
1122 element_info[element].special_graphic[special] = graphic;
1125 /* initialize special element/graphic mapping from dynamic configuration */
1126 for (i = 0; i < num_property_mappings; i++)
1128 int element = property_mapping[i].base_index;
1129 int action = property_mapping[i].ext1_index;
1130 int direction = property_mapping[i].ext2_index;
1131 int special = property_mapping[i].ext3_index;
1132 int graphic = property_mapping[i].artwork_index;
1135 if ((element == EL_EM_DYNAMITE ||
1136 element == EL_EM_DYNAMITE_ACTIVE ||
1137 element == EL_CONVEYOR_BELT_1_MIDDLE ||
1138 element == EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE) &&
1139 (special == GFX_SPECIAL_ARG_EDITOR ||
1140 special == GFX_SPECIAL_ARG_PANEL))
1141 printf("::: SPECIAL DYNAMIC: %d, %d -> %d [%d]\n",
1142 element, special, graphic, property_mapping[i].ext1_index);
1146 if (element == EL_CONVEYOR_BELT_1_MIDDLE &&
1147 action == ACTION_ACTIVE)
1149 element = EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE;
1155 if (element == EL_MAGIC_WALL &&
1156 action == ACTION_ACTIVE)
1158 element = EL_MAGIC_WALL_ACTIVE;
1164 /* for action ".active", replace element with active element, if exists */
1165 if (action == ACTION_ACTIVE && element != ELEMENT_ACTIVE(element))
1167 element = ELEMENT_ACTIVE(element);
1172 if (element >= MAX_NUM_ELEMENTS)
1175 /* do not change special graphic if action or direction was specified */
1176 if (action != -1 || direction != -1)
1179 if (IS_SPECIAL_GFX_ARG(special))
1180 element_info[element].special_graphic[special] = graphic;
1183 /* now set all undefined/invalid graphics to default */
1184 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1185 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1186 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
1187 element_info[i].special_graphic[j] =
1188 element_info[i].graphic[ACTION_DEFAULT];
1191 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
1193 if (type != TYPE_ELEMENT && type != TYPE_GRAPHIC)
1194 return get_parameter_value(value_raw, suffix, type);
1196 if (strEqual(value_raw, ARG_UNDEFINED))
1197 return ARG_UNDEFINED_VALUE;
1200 if (type == TYPE_ELEMENT)
1202 char *value = getHashEntry(element_token_hash, value_raw);
1204 return (value != NULL ? atoi(value) : EL_UNDEFINED);
1206 else if (type == TYPE_GRAPHIC)
1208 char *value = getHashEntry(graphic_token_hash, value_raw);
1210 return (value != NULL ? atoi(value) : IMG_UNDEFINED);
1218 /* !!! THIS IS BUGGY !!! NOT SURE IF YOU GET ELEMENT ID OR GRAPHIC ID !!! */
1219 /* !!! (possible reason why ".clone_from" with elements doesn't work) !!! */
1221 /* !!! OPTIMIZE THIS BY USING HASH !!! */
1222 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1223 if (strEqual(element_info[i].token_name, value_raw))
1226 /* !!! OPTIMIZE THIS BY USING HASH !!! */
1227 for (i = 0; image_config[i].token != NULL; i++)
1229 int len_config_value = strlen(image_config[i].value);
1231 if (!strEqual(&image_config[i].value[len_config_value - 4], ".pcx") &&
1232 !strEqual(&image_config[i].value[len_config_value - 4], ".wav") &&
1233 !strEqual(image_config[i].value, UNDEFINED_FILENAME))
1236 if (strEqual(image_config[i].token, value_raw))
1246 static int get_scaled_graphic_width(int graphic)
1248 int original_width = getOriginalImageWidthFromImageID(graphic);
1249 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1251 return original_width * scale_up_factor;
1254 static int get_scaled_graphic_height(int graphic)
1256 int original_height = getOriginalImageHeightFromImageID(graphic);
1257 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1259 return original_height * scale_up_factor;
1262 static void set_graphic_parameters_ext(int graphic, int *parameter,
1265 struct GraphicInfo *g = &graphic_info[graphic];
1266 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1267 int anim_frames_per_line = 1;
1269 /* always start with reliable default values */
1270 g->src_image_width = 0;
1271 g->src_image_height = 0;
1274 g->width = TILEX; /* default for element graphics */
1275 g->height = TILEY; /* default for element graphics */
1276 g->offset_x = 0; /* one or both of these values ... */
1277 g->offset_y = 0; /* ... will be corrected later */
1278 g->offset2_x = 0; /* one or both of these values ... */
1279 g->offset2_y = 0; /* ... will be corrected later */
1280 g->swap_double_tiles = -1; /* auto-detect tile swapping */
1281 g->crumbled_like = -1; /* do not use clone element */
1282 g->diggable_like = -1; /* do not use clone element */
1283 g->border_size = TILEX / 8; /* "CRUMBLED" border size */
1284 g->scale_up_factor = 1; /* default: no scaling up */
1285 g->clone_from = -1; /* do not use clone graphic */
1286 g->anim_delay_fixed = 0;
1287 g->anim_delay_random = 0;
1288 g->post_delay_fixed = 0;
1289 g->post_delay_random = 0;
1290 g->fade_mode = FADE_MODE_DEFAULT;
1294 g->align = ALIGN_CENTER; /* default for title screens */
1295 g->valign = VALIGN_MIDDLE; /* default for title screens */
1296 g->sort_priority = 0; /* default for title screens */
1298 g->style = STYLE_DEFAULT;
1300 g->bitmap = src_bitmap;
1303 /* optional zoom factor for scaling up the image to a larger size */
1304 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1305 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1306 if (g->scale_up_factor < 1)
1307 g->scale_up_factor = 1; /* no scaling */
1311 if (g->use_image_size)
1313 /* set new default bitmap size (with scaling, but without small images) */
1314 g->width = get_scaled_graphic_width(graphic);
1315 g->height = get_scaled_graphic_height(graphic);
1319 /* optional x and y tile position of animation frame sequence */
1320 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1321 g->src_x = parameter[GFX_ARG_XPOS] * TILEX;
1322 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1323 g->src_y = parameter[GFX_ARG_YPOS] * TILEY;
1325 /* optional x and y pixel position of animation frame sequence */
1326 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1327 g->src_x = parameter[GFX_ARG_X];
1328 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1329 g->src_y = parameter[GFX_ARG_Y];
1331 /* optional width and height of each animation frame */
1332 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1333 g->width = parameter[GFX_ARG_WIDTH];
1334 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1335 g->height = parameter[GFX_ARG_HEIGHT];
1338 /* optional zoom factor for scaling up the image to a larger size */
1339 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1340 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1341 if (g->scale_up_factor < 1)
1342 g->scale_up_factor = 1; /* no scaling */
1347 /* get final bitmap size (with scaling, but without small images) */
1348 int src_image_width = get_scaled_graphic_width(graphic);
1349 int src_image_height = get_scaled_graphic_height(graphic);
1351 if (src_image_width == 0 || src_image_height == 0)
1353 /* only happens when loaded outside artwork system (like "global.busy") */
1354 src_image_width = src_bitmap->width;
1355 src_image_height = src_bitmap->height;
1358 anim_frames_per_row = src_image_width / g->width;
1359 anim_frames_per_col = src_image_height / g->height;
1361 g->src_image_width = src_image_width;
1362 g->src_image_height = src_image_height;
1365 /* correct x or y offset dependent of vertical or horizontal frame order */
1366 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1368 g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1369 parameter[GFX_ARG_OFFSET] : g->height);
1370 anim_frames_per_line = anim_frames_per_col;
1372 else /* frames are ordered horizontally */
1374 g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1375 parameter[GFX_ARG_OFFSET] : g->width);
1376 anim_frames_per_line = anim_frames_per_row;
1379 /* optionally, the x and y offset of frames can be specified directly */
1380 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1381 g->offset_x = parameter[GFX_ARG_XOFFSET];
1382 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1383 g->offset_y = parameter[GFX_ARG_YOFFSET];
1385 /* optionally, moving animations may have separate start and end graphics */
1386 g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1388 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1389 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1391 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1392 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1393 g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1394 parameter[GFX_ARG_2ND_OFFSET] : g->height);
1395 else /* frames are ordered horizontally */
1396 g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1397 parameter[GFX_ARG_2ND_OFFSET] : g->width);
1399 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1400 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1401 g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1402 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1403 g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1405 /* optionally, the second movement tile can be specified as start tile */
1406 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1407 g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1409 /* automatically determine correct number of frames, if not defined */
1410 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1411 g->anim_frames = parameter[GFX_ARG_FRAMES];
1412 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1413 g->anim_frames = anim_frames_per_row;
1414 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1415 g->anim_frames = anim_frames_per_col;
1419 if (g->anim_frames == 0) /* frames must be at least 1 */
1422 g->anim_frames_per_line =
1423 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1424 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1426 g->anim_delay = parameter[GFX_ARG_DELAY];
1427 if (g->anim_delay == 0) /* delay must be at least 1 */
1430 g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1432 if (g->anim_frames == 1)
1433 g->anim_mode = ANIM_NONE;
1436 /* automatically determine correct start frame, if not defined */
1437 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1438 g->anim_start_frame = 0;
1439 else if (g->anim_mode & ANIM_REVERSE)
1440 g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1442 g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1444 /* animation synchronized with global frame counter, not move position */
1445 g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1447 /* optional element for cloning crumble graphics */
1448 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1449 g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1451 /* optional element for cloning digging graphics */
1452 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1453 g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1455 /* optional border size for "crumbling" diggable graphics */
1456 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1457 g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1459 /* this is only used for player "boring" and "sleeping" actions */
1460 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1461 g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1462 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1463 g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1464 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1465 g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1466 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1467 g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1469 /* this is only used for toon animations */
1470 g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1471 g->step_delay = parameter[GFX_ARG_STEP_DELAY];
1473 /* this is only used for drawing font characters */
1474 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1475 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1477 /* this is only used for drawing envelope graphics */
1478 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1480 /* optional graphic for cloning all graphics settings */
1481 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1482 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1484 /* optional settings for drawing title screens and title messages */
1485 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1486 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1487 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1488 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1489 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1490 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1491 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1492 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1493 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1494 g->align = parameter[GFX_ARG_ALIGN];
1495 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1496 g->valign = parameter[GFX_ARG_VALIGN];
1497 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1498 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1500 if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
1501 g->class = parameter[GFX_ARG_CLASS];
1502 if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
1503 g->style = parameter[GFX_ARG_STYLE];
1505 /* this is only used for drawing menu buttons and text */
1506 g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
1507 g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
1508 g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
1509 g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
1512 static void set_graphic_parameters(int graphic)
1515 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1516 char **parameter_raw = image->parameter;
1517 Bitmap *src_bitmap = getBitmapFromImageID(graphic);
1518 int parameter[NUM_GFX_ARGS];
1521 /* if fallback to default artwork is done, also use the default parameters */
1522 if (image->fallback_to_default)
1523 parameter_raw = image->default_parameter;
1525 /* get integer values from string parameters */
1526 for (i = 0; i < NUM_GFX_ARGS; i++)
1527 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1528 image_config_suffix[i].token,
1529 image_config_suffix[i].type);
1531 set_graphic_parameters_ext(graphic, parameter, src_bitmap);
1535 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1536 char **parameter_raw = image->parameter;
1537 Bitmap *src_bitmap = getBitmapFromImageID(graphic);
1538 int parameter[NUM_GFX_ARGS];
1539 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1540 int anim_frames_per_line = 1;
1543 /* if fallback to default artwork is done, also use the default parameters */
1544 if (image->fallback_to_default)
1545 parameter_raw = image->default_parameter;
1547 /* get integer values from string parameters */
1548 for (i = 0; i < NUM_GFX_ARGS; i++)
1549 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1550 image_config_suffix[i].token,
1551 image_config_suffix[i].type);
1553 graphic_info[graphic].bitmap = src_bitmap;
1555 /* always start with reliable default values */
1556 graphic_info[graphic].src_image_width = 0;
1557 graphic_info[graphic].src_image_height = 0;
1558 graphic_info[graphic].src_x = 0;
1559 graphic_info[graphic].src_y = 0;
1560 graphic_info[graphic].width = TILEX; /* default for element graphics */
1561 graphic_info[graphic].height = TILEY; /* default for element graphics */
1562 graphic_info[graphic].offset_x = 0; /* one or both of these values ... */
1563 graphic_info[graphic].offset_y = 0; /* ... will be corrected later */
1564 graphic_info[graphic].offset2_x = 0; /* one or both of these values ... */
1565 graphic_info[graphic].offset2_y = 0; /* ... will be corrected later */
1566 graphic_info[graphic].swap_double_tiles = -1; /* auto-detect tile swapping */
1567 graphic_info[graphic].crumbled_like = -1; /* do not use clone element */
1568 graphic_info[graphic].diggable_like = -1; /* do not use clone element */
1569 graphic_info[graphic].border_size = TILEX / 8; /* "CRUMBLED" border size */
1570 graphic_info[graphic].scale_up_factor = 1; /* default: no scaling up */
1571 graphic_info[graphic].clone_from = -1; /* do not use clone graphic */
1572 graphic_info[graphic].anim_delay_fixed = 0;
1573 graphic_info[graphic].anim_delay_random = 0;
1574 graphic_info[graphic].post_delay_fixed = 0;
1575 graphic_info[graphic].post_delay_random = 0;
1576 graphic_info[graphic].fade_mode = FADE_MODE_DEFAULT;
1577 graphic_info[graphic].fade_delay = -1;
1578 graphic_info[graphic].post_delay = -1;
1579 graphic_info[graphic].auto_delay = -1;
1580 graphic_info[graphic].align = ALIGN_CENTER; /* default for title screens */
1581 graphic_info[graphic].valign = VALIGN_MIDDLE; /* default for title screens */
1582 graphic_info[graphic].sort_priority = 0; /* default for title screens */
1585 /* optional zoom factor for scaling up the image to a larger size */
1586 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1587 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1588 if (graphic_info[graphic].scale_up_factor < 1)
1589 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
1593 if (graphic_info[graphic].use_image_size)
1595 /* set new default bitmap size (with scaling, but without small images) */
1596 graphic_info[graphic].width = get_scaled_graphic_width(graphic);
1597 graphic_info[graphic].height = get_scaled_graphic_height(graphic);
1601 /* optional x and y tile position of animation frame sequence */
1602 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1603 graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
1604 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1605 graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
1607 /* optional x and y pixel position of animation frame sequence */
1608 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1609 graphic_info[graphic].src_x = parameter[GFX_ARG_X];
1610 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1611 graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
1613 /* optional width and height of each animation frame */
1614 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1615 graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
1616 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1617 graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
1620 /* optional zoom factor for scaling up the image to a larger size */
1621 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1622 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1623 if (graphic_info[graphic].scale_up_factor < 1)
1624 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
1629 /* get final bitmap size (with scaling, but without small images) */
1630 int src_image_width = get_scaled_graphic_width(graphic);
1631 int src_image_height = get_scaled_graphic_height(graphic);
1633 anim_frames_per_row = src_image_width / graphic_info[graphic].width;
1634 anim_frames_per_col = src_image_height / graphic_info[graphic].height;
1636 graphic_info[graphic].src_image_width = src_image_width;
1637 graphic_info[graphic].src_image_height = src_image_height;
1640 /* correct x or y offset dependent of vertical or horizontal frame order */
1641 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1643 graphic_info[graphic].offset_y =
1644 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1645 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
1646 anim_frames_per_line = anim_frames_per_col;
1648 else /* frames are ordered horizontally */
1650 graphic_info[graphic].offset_x =
1651 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1652 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
1653 anim_frames_per_line = anim_frames_per_row;
1656 /* optionally, the x and y offset of frames can be specified directly */
1657 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1658 graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
1659 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1660 graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
1662 /* optionally, moving animations may have separate start and end graphics */
1663 graphic_info[graphic].double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1665 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1666 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1668 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1669 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1670 graphic_info[graphic].offset2_y =
1671 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1672 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].height);
1673 else /* frames are ordered horizontally */
1674 graphic_info[graphic].offset2_x =
1675 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1676 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].width);
1678 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1679 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1680 graphic_info[graphic].offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1681 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1682 graphic_info[graphic].offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1684 /* optionally, the second movement tile can be specified as start tile */
1685 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1686 graphic_info[graphic].swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1688 /* automatically determine correct number of frames, if not defined */
1689 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1690 graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
1691 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1692 graphic_info[graphic].anim_frames = anim_frames_per_row;
1693 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1694 graphic_info[graphic].anim_frames = anim_frames_per_col;
1696 graphic_info[graphic].anim_frames = 1;
1698 if (graphic_info[graphic].anim_frames == 0) /* frames must be at least 1 */
1699 graphic_info[graphic].anim_frames = 1;
1701 graphic_info[graphic].anim_frames_per_line =
1702 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1703 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1705 graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
1706 if (graphic_info[graphic].anim_delay == 0) /* delay must be at least 1 */
1707 graphic_info[graphic].anim_delay = 1;
1709 graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
1711 if (graphic_info[graphic].anim_frames == 1)
1712 graphic_info[graphic].anim_mode = ANIM_NONE;
1715 /* automatically determine correct start frame, if not defined */
1716 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1717 graphic_info[graphic].anim_start_frame = 0;
1718 else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
1719 graphic_info[graphic].anim_start_frame =
1720 graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1722 graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
1724 /* animation synchronized with global frame counter, not move position */
1725 graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1727 /* optional element for cloning crumble graphics */
1728 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1729 graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1731 /* optional element for cloning digging graphics */
1732 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1733 graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1735 /* optional border size for "crumbling" diggable graphics */
1736 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1737 graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
1739 /* this is only used for player "boring" and "sleeping" actions */
1740 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1741 graphic_info[graphic].anim_delay_fixed =
1742 parameter[GFX_ARG_ANIM_DELAY_FIXED];
1743 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1744 graphic_info[graphic].anim_delay_random =
1745 parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1746 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1747 graphic_info[graphic].post_delay_fixed =
1748 parameter[GFX_ARG_POST_DELAY_FIXED];
1749 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1750 graphic_info[graphic].post_delay_random =
1751 parameter[GFX_ARG_POST_DELAY_RANDOM];
1753 /* this is only used for toon animations */
1754 graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
1755 graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY];
1757 /* this is only used for drawing font characters */
1758 graphic_info[graphic].draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1759 graphic_info[graphic].draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1761 /* this is only used for drawing envelope graphics */
1762 graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1764 /* optional graphic for cloning all graphics settings */
1765 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1766 graphic_info[graphic].clone_from = parameter[GFX_ARG_CLONE_FROM];
1768 /* optional settings for drawing title screens and title messages */
1769 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1770 graphic_info[graphic].fade_mode = parameter[GFX_ARG_FADE_MODE];
1771 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1772 graphic_info[graphic].fade_delay = parameter[GFX_ARG_FADE_DELAY];
1773 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1774 graphic_info[graphic].post_delay = parameter[GFX_ARG_POST_DELAY];
1775 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1776 graphic_info[graphic].auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1777 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1778 graphic_info[graphic].align = parameter[GFX_ARG_ALIGN];
1779 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1780 graphic_info[graphic].valign = parameter[GFX_ARG_VALIGN];
1781 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1782 graphic_info[graphic].sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1785 UPDATE_BUSY_STATE();
1788 static void set_cloned_graphic_parameters(int graphic)
1790 int fallback_graphic = IMG_CHAR_EXCLAM;
1791 int max_num_images = getImageListSize();
1792 int clone_graphic = graphic_info[graphic].clone_from;
1793 int num_references_followed = 1;
1795 while (graphic_info[clone_graphic].clone_from != -1 &&
1796 num_references_followed < max_num_images)
1798 clone_graphic = graphic_info[clone_graphic].clone_from;
1800 num_references_followed++;
1803 if (num_references_followed >= max_num_images)
1805 Error(ERR_INFO_LINE, "-");
1806 Error(ERR_INFO, "warning: error found in config file:");
1807 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1808 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1809 Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1810 Error(ERR_INFO, "custom graphic rejected for this element/action");
1812 if (graphic == fallback_graphic)
1813 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1815 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1816 Error(ERR_INFO_LINE, "-");
1818 graphic_info[graphic] = graphic_info[fallback_graphic];
1822 graphic_info[graphic] = graphic_info[clone_graphic];
1823 graphic_info[graphic].clone_from = clone_graphic;
1827 static void InitGraphicInfo()
1829 int fallback_graphic = IMG_CHAR_EXCLAM;
1830 int num_images = getImageListSize();
1833 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1834 static boolean clipmasks_initialized = FALSE;
1836 XGCValues clip_gc_values;
1837 unsigned long clip_gc_valuemask;
1838 GC copy_clipmask_gc = None;
1841 /* use image size as default values for width and height for these images */
1842 static int full_size_graphics[] =
1847 IMG_BACKGROUND_ENVELOPE_1,
1848 IMG_BACKGROUND_ENVELOPE_2,
1849 IMG_BACKGROUND_ENVELOPE_3,
1850 IMG_BACKGROUND_ENVELOPE_4,
1853 IMG_BACKGROUND_TITLE_INITIAL,
1854 IMG_BACKGROUND_TITLE,
1855 IMG_BACKGROUND_MAIN,
1856 IMG_BACKGROUND_LEVELS,
1857 IMG_BACKGROUND_SCORES,
1858 IMG_BACKGROUND_EDITOR,
1859 IMG_BACKGROUND_INFO,
1860 IMG_BACKGROUND_INFO_ELEMENTS,
1861 IMG_BACKGROUND_INFO_MUSIC,
1862 IMG_BACKGROUND_INFO_CREDITS,
1863 IMG_BACKGROUND_INFO_PROGRAM,
1864 IMG_BACKGROUND_INFO_LEVELSET,
1865 IMG_BACKGROUND_SETUP,
1866 IMG_BACKGROUND_DOOR,
1868 IMG_TITLESCREEN_INITIAL_1,
1869 IMG_TITLESCREEN_INITIAL_2,
1870 IMG_TITLESCREEN_INITIAL_3,
1871 IMG_TITLESCREEN_INITIAL_4,
1872 IMG_TITLESCREEN_INITIAL_5,
1882 checked_free(graphic_info);
1884 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1887 /* initialize "use_image_size" flag with default value */
1888 for (i = 0; i < num_images; i++)
1889 graphic_info[i].use_image_size = FALSE;
1891 /* initialize "use_image_size" flag from static configuration above */
1892 for (i = 0; full_size_graphics[i] != -1; i++)
1893 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1896 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1897 if (clipmasks_initialized)
1899 for (i = 0; i < num_images; i++)
1901 if (graphic_info[i].clip_mask)
1902 XFreePixmap(display, graphic_info[i].clip_mask);
1903 if (graphic_info[i].clip_gc)
1904 XFreeGC(display, graphic_info[i].clip_gc);
1906 graphic_info[i].clip_mask = None;
1907 graphic_info[i].clip_gc = None;
1912 /* first set all graphic paramaters ... */
1913 for (i = 0; i < num_images; i++)
1914 set_graphic_parameters(i);
1916 /* ... then copy these parameters for cloned graphics */
1917 for (i = 0; i < num_images; i++)
1918 if (graphic_info[i].clone_from != -1)
1919 set_cloned_graphic_parameters(i);
1921 for (i = 0; i < num_images; i++)
1926 int first_frame, last_frame;
1927 int src_bitmap_width, src_bitmap_height;
1929 /* now check if no animation frames are outside of the loaded image */
1931 if (graphic_info[i].bitmap == NULL)
1932 continue; /* skip check for optional images that are undefined */
1934 /* get image size (this can differ from the standard element tile size!) */
1935 width = graphic_info[i].width;
1936 height = graphic_info[i].height;
1938 /* get final bitmap size (with scaling, but without small images) */
1939 src_bitmap_width = graphic_info[i].src_image_width;
1940 src_bitmap_height = graphic_info[i].src_image_height;
1942 /* check if first animation frame is inside specified bitmap */
1945 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1948 /* this avoids calculating wrong start position for out-of-bounds frame */
1949 src_x = graphic_info[i].src_x;
1950 src_y = graphic_info[i].src_y;
1953 if (src_x < 0 || src_y < 0 ||
1954 src_x + width > src_bitmap_width ||
1955 src_y + height > src_bitmap_height)
1957 Error(ERR_INFO_LINE, "-");
1958 Error(ERR_INFO, "warning: error found in config file:");
1959 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1960 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1961 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1963 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1964 src_x, src_y, src_bitmap_width, src_bitmap_height);
1965 Error(ERR_INFO, "custom graphic rejected for this element/action");
1967 if (i == fallback_graphic)
1968 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1970 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1971 Error(ERR_INFO_LINE, "-");
1973 graphic_info[i] = graphic_info[fallback_graphic];
1976 /* check if last animation frame is inside specified bitmap */
1978 last_frame = graphic_info[i].anim_frames - 1;
1979 getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1981 if (src_x < 0 || src_y < 0 ||
1982 src_x + width > src_bitmap_width ||
1983 src_y + height > src_bitmap_height)
1985 Error(ERR_INFO_LINE, "-");
1986 Error(ERR_INFO, "warning: error found in config file:");
1987 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1988 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1989 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1991 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1992 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1993 Error(ERR_INFO, "custom graphic rejected for this element/action");
1995 if (i == fallback_graphic)
1996 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1998 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1999 Error(ERR_INFO_LINE, "-");
2001 graphic_info[i] = graphic_info[fallback_graphic];
2004 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
2005 /* currently we only need a tile clip mask from the first frame */
2006 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
2008 if (copy_clipmask_gc == None)
2010 clip_gc_values.graphics_exposures = False;
2011 clip_gc_valuemask = GCGraphicsExposures;
2012 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
2013 clip_gc_valuemask, &clip_gc_values);
2016 graphic_info[i].clip_mask =
2017 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
2019 src_pixmap = src_bitmap->clip_mask;
2020 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
2021 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
2023 clip_gc_values.graphics_exposures = False;
2024 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
2025 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
2027 graphic_info[i].clip_gc =
2028 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
2032 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
2033 if (copy_clipmask_gc)
2034 XFreeGC(display, copy_clipmask_gc);
2036 clipmasks_initialized = TRUE;
2040 static void InitGraphicCompatibilityInfo()
2042 struct FileInfo *fi_global_door =
2043 getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
2044 int num_images = getImageListSize();
2047 /* the following compatibility handling is needed for the following case:
2048 versions up to 3.3.0.0 used one large bitmap "global.door" for various
2049 graphics mainly used for door and panel graphics, like editor, tape and
2050 in-game buttons with hard-coded bitmap positions and button sizes; as
2051 these graphics now have individual definitions, redefining "global.door"
2052 to change all these graphics at once like before does not work anymore
2053 (because all those individual definitions still have their default values);
2054 to solve this, remap all those individual definitions that are not
2055 redefined to the new bitmap of "global.door" if it was redefined */
2057 /* special compatibility handling if image "global.door" was redefined */
2058 if (fi_global_door->redefined)
2060 for (i = 0; i < num_images; i++)
2062 struct FileInfo *fi = getImageListEntryFromImageID(i);
2064 /* process only those images that still use the default settings */
2067 /* process all images which default to same image as "global.door" */
2068 if (strEqual(fi->default_filename, fi_global_door->default_filename))
2070 // printf("::: special treatment needed for token '%s'\n", fi->token);
2072 graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2079 for (i = 0; i < num_images; i++)
2081 struct FileInfo *fi = getImageListEntryFromImageID(i);
2083 if (i == IMG_GLOBAL_DOOR)
2085 printf("::: %s, %s, %d\n",
2086 fi->default_filename,
2094 static void InitElementSoundInfo()
2096 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
2097 int num_property_mappings = getSoundListPropertyMappingSize();
2100 /* set values to -1 to identify later as "uninitialized" values */
2101 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2102 for (act = 0; act < NUM_ACTIONS; act++)
2103 element_info[i].sound[act] = -1;
2105 /* initialize element/sound mapping from static configuration */
2106 for (i = 0; element_to_sound[i].element > -1; i++)
2108 int element = element_to_sound[i].element;
2109 int action = element_to_sound[i].action;
2110 int sound = element_to_sound[i].sound;
2111 boolean is_class = element_to_sound[i].is_class;
2114 action = ACTION_DEFAULT;
2117 element_info[element].sound[action] = sound;
2119 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2120 if (strEqual(element_info[j].class_name,
2121 element_info[element].class_name))
2122 element_info[j].sound[action] = sound;
2125 /* initialize element class/sound mapping from dynamic configuration */
2126 for (i = 0; i < num_property_mappings; i++)
2128 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
2129 int action = property_mapping[i].ext1_index;
2130 int sound = property_mapping[i].artwork_index;
2132 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
2136 action = ACTION_DEFAULT;
2138 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2139 if (strEqual(element_info[j].class_name,
2140 element_info[element_class].class_name))
2141 element_info[j].sound[action] = sound;
2144 /* initialize element/sound mapping from dynamic configuration */
2145 for (i = 0; i < num_property_mappings; i++)
2147 int element = property_mapping[i].base_index;
2148 int action = property_mapping[i].ext1_index;
2149 int sound = property_mapping[i].artwork_index;
2151 if (element >= MAX_NUM_ELEMENTS)
2155 action = ACTION_DEFAULT;
2157 element_info[element].sound[action] = sound;
2160 /* now set all '-1' values to element specific default values */
2161 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2163 for (act = 0; act < NUM_ACTIONS; act++)
2165 /* generic default action sound (defined by "[default]" directive) */
2166 int default_action_sound = element_info[EL_DEFAULT].sound[act];
2168 /* look for special default action sound (classic game specific) */
2169 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
2170 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
2171 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
2172 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
2173 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
2174 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
2176 /* !!! there's no such thing as a "default action sound" !!! */
2178 /* look for element specific default sound (independent from action) */
2179 if (element_info[i].sound[ACTION_DEFAULT] != -1)
2180 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
2184 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
2185 /* !!! make this better !!! */
2186 if (i == EL_EMPTY_SPACE)
2187 default_action_sound = element_info[EL_DEFAULT].sound[act];
2190 /* no sound for this specific action -- use default action sound */
2191 if (element_info[i].sound[act] == -1)
2192 element_info[i].sound[act] = default_action_sound;
2196 /* copy sound settings to some elements that are only stored in level file
2197 in native R'n'D levels, but are used by game engine in native EM levels */
2198 for (i = 0; copy_properties[i][0] != -1; i++)
2199 for (j = 1; j <= 4; j++)
2200 for (act = 0; act < NUM_ACTIONS; act++)
2201 element_info[copy_properties[i][j]].sound[act] =
2202 element_info[copy_properties[i][0]].sound[act];
2205 static void InitGameModeSoundInfo()
2209 /* set values to -1 to identify later as "uninitialized" values */
2210 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2213 /* initialize gamemode/sound mapping from static configuration */
2214 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
2216 int gamemode = gamemode_to_sound[i].gamemode;
2217 int sound = gamemode_to_sound[i].sound;
2220 gamemode = GAME_MODE_DEFAULT;
2222 menu.sound[gamemode] = sound;
2225 /* now set all '-1' values to levelset specific default values */
2226 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2227 if (menu.sound[i] == -1)
2228 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
2231 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2232 if (menu.sound[i] != -1)
2233 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
2237 static void set_sound_parameters(int sound, char **parameter_raw)
2239 int parameter[NUM_SND_ARGS];
2242 /* get integer values from string parameters */
2243 for (i = 0; i < NUM_SND_ARGS; i++)
2245 get_parameter_value(parameter_raw[i],
2246 sound_config_suffix[i].token,
2247 sound_config_suffix[i].type);
2249 /* explicit loop mode setting in configuration overrides default value */
2250 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2251 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
2253 /* sound volume to change the original volume when loading the sound file */
2254 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
2256 /* sound priority to give certain sounds a higher or lower priority */
2257 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
2260 static void InitSoundInfo()
2262 int *sound_effect_properties;
2263 int num_sounds = getSoundListSize();
2266 checked_free(sound_info);
2268 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
2269 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
2271 /* initialize sound effect for all elements to "no sound" */
2272 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2273 for (j = 0; j < NUM_ACTIONS; j++)
2274 element_info[i].sound[j] = SND_UNDEFINED;
2276 for (i = 0; i < num_sounds; i++)
2278 struct FileInfo *sound = getSoundListEntry(i);
2279 int len_effect_text = strlen(sound->token);
2281 sound_effect_properties[i] = ACTION_OTHER;
2282 sound_info[i].loop = FALSE; /* default: play sound only once */
2285 printf("::: sound %d: '%s'\n", i, sound->token);
2288 /* determine all loop sounds and identify certain sound classes */
2290 for (j = 0; element_action_info[j].suffix; j++)
2292 int len_action_text = strlen(element_action_info[j].suffix);
2294 if (len_action_text < len_effect_text &&
2295 strEqual(&sound->token[len_effect_text - len_action_text],
2296 element_action_info[j].suffix))
2298 sound_effect_properties[i] = element_action_info[j].value;
2299 sound_info[i].loop = element_action_info[j].is_loop_sound;
2305 /* associate elements and some selected sound actions */
2307 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2309 if (element_info[j].class_name)
2311 int len_class_text = strlen(element_info[j].class_name);
2313 if (len_class_text + 1 < len_effect_text &&
2314 strncmp(sound->token,
2315 element_info[j].class_name, len_class_text) == 0 &&
2316 sound->token[len_class_text] == '.')
2318 int sound_action_value = sound_effect_properties[i];
2320 element_info[j].sound[sound_action_value] = i;
2325 set_sound_parameters(i, sound->parameter);
2328 free(sound_effect_properties);
2331 static void InitGameModeMusicInfo()
2333 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
2334 int num_property_mappings = getMusicListPropertyMappingSize();
2335 int default_levelset_music = -1;
2338 /* set values to -1 to identify later as "uninitialized" values */
2339 for (i = 0; i < MAX_LEVELS; i++)
2340 levelset.music[i] = -1;
2341 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2344 /* initialize gamemode/music mapping from static configuration */
2345 for (i = 0; gamemode_to_music[i].music > -1; i++)
2347 int gamemode = gamemode_to_music[i].gamemode;
2348 int music = gamemode_to_music[i].music;
2351 printf("::: gamemode == %d, music == %d\n", gamemode, music);
2355 gamemode = GAME_MODE_DEFAULT;
2357 menu.music[gamemode] = music;
2360 /* initialize gamemode/music mapping from dynamic configuration */
2361 for (i = 0; i < num_property_mappings; i++)
2363 int prefix = property_mapping[i].base_index;
2364 int gamemode = property_mapping[i].ext1_index;
2365 int level = property_mapping[i].ext2_index;
2366 int music = property_mapping[i].artwork_index;
2369 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
2370 prefix, gamemode, level, music);
2373 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
2377 gamemode = GAME_MODE_DEFAULT;
2379 /* level specific music only allowed for in-game music */
2380 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
2381 gamemode = GAME_MODE_PLAYING;
2386 default_levelset_music = music;
2389 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
2390 levelset.music[level] = music;
2391 if (gamemode != GAME_MODE_PLAYING)
2392 menu.music[gamemode] = music;
2395 /* now set all '-1' values to menu specific default values */
2396 /* (undefined values of "levelset.music[]" might stay at "-1" to
2397 allow dynamic selection of music files from music directory!) */
2398 for (i = 0; i < MAX_LEVELS; i++)
2399 if (levelset.music[i] == -1)
2400 levelset.music[i] = default_levelset_music;
2401 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2402 if (menu.music[i] == -1)
2403 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
2406 for (i = 0; i < MAX_LEVELS; i++)
2407 if (levelset.music[i] != -1)
2408 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
2409 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2410 if (menu.music[i] != -1)
2411 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
2415 static void set_music_parameters(int music, char **parameter_raw)
2417 int parameter[NUM_MUS_ARGS];
2420 /* get integer values from string parameters */
2421 for (i = 0; i < NUM_MUS_ARGS; i++)
2423 get_parameter_value(parameter_raw[i],
2424 music_config_suffix[i].token,
2425 music_config_suffix[i].type);
2427 /* explicit loop mode setting in configuration overrides default value */
2428 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2429 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
2432 static void InitMusicInfo()
2434 int num_music = getMusicListSize();
2437 checked_free(music_info);
2439 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
2441 for (i = 0; i < num_music; i++)
2443 struct FileInfo *music = getMusicListEntry(i);
2444 int len_music_text = strlen(music->token);
2446 music_info[i].loop = TRUE; /* default: play music in loop mode */
2448 /* determine all loop music */
2450 for (j = 0; music_prefix_info[j].prefix; j++)
2452 int len_prefix_text = strlen(music_prefix_info[j].prefix);
2454 if (len_prefix_text < len_music_text &&
2455 strncmp(music->token,
2456 music_prefix_info[j].prefix, len_prefix_text) == 0)
2458 music_info[i].loop = music_prefix_info[j].is_loop_music;
2464 set_music_parameters(i, music->parameter);
2468 static void ReinitializeGraphics()
2470 print_timestamp_init("ReinitializeGraphics");
2472 InitGraphicInfo(); /* graphic properties mapping */
2473 print_timestamp_time("InitGraphicInfo");
2474 InitElementGraphicInfo(); /* element game graphic mapping */
2475 print_timestamp_time("InitElementGraphicInfo");
2476 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
2477 print_timestamp_time("InitElementSpecialGraphicInfo");
2479 InitElementSmallImages(); /* scale elements to all needed sizes */
2480 print_timestamp_time("InitElementSmallImages");
2481 InitScaledImages(); /* scale all other images, if needed */
2482 print_timestamp_time("InitScaledImages");
2483 InitFontGraphicInfo(); /* initialize text drawing functions */
2484 print_timestamp_time("InitFontGraphicInfo");
2486 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
2487 print_timestamp_time("InitGraphicInfo_EM");
2489 InitGraphicCompatibilityInfo();
2490 print_timestamp_time("InitGraphicCompatibilityInfo");
2492 SetMainBackgroundImage(IMG_BACKGROUND);
2493 print_timestamp_time("SetMainBackgroundImage");
2494 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2495 print_timestamp_time("SetDoorBackgroundImage");
2498 print_timestamp_time("InitGadgets");
2500 print_timestamp_time("InitToons");
2502 print_timestamp_done("ReinitializeGraphics");
2505 static void ReinitializeSounds()
2507 InitSoundInfo(); /* sound properties mapping */
2508 InitElementSoundInfo(); /* element game sound mapping */
2509 InitGameModeSoundInfo(); /* game mode sound mapping */
2511 InitPlayLevelSound(); /* internal game sound settings */
2514 static void ReinitializeMusic()
2516 InitMusicInfo(); /* music properties mapping */
2517 InitGameModeMusicInfo(); /* game mode music mapping */
2520 static int get_special_property_bit(int element, int property_bit_nr)
2522 struct PropertyBitInfo
2528 static struct PropertyBitInfo pb_can_move_into_acid[] =
2530 /* the player may be able fall into acid when gravity is activated */
2535 { EL_SP_MURPHY, 0 },
2536 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2538 /* all elements that can move may be able to also move into acid */
2541 { EL_BUG_RIGHT, 1 },
2544 { EL_SPACESHIP, 2 },
2545 { EL_SPACESHIP_LEFT, 2 },
2546 { EL_SPACESHIP_RIGHT, 2 },
2547 { EL_SPACESHIP_UP, 2 },
2548 { EL_SPACESHIP_DOWN, 2 },
2549 { EL_BD_BUTTERFLY, 3 },
2550 { EL_BD_BUTTERFLY_LEFT, 3 },
2551 { EL_BD_BUTTERFLY_RIGHT, 3 },
2552 { EL_BD_BUTTERFLY_UP, 3 },
2553 { EL_BD_BUTTERFLY_DOWN, 3 },
2554 { EL_BD_FIREFLY, 4 },
2555 { EL_BD_FIREFLY_LEFT, 4 },
2556 { EL_BD_FIREFLY_RIGHT, 4 },
2557 { EL_BD_FIREFLY_UP, 4 },
2558 { EL_BD_FIREFLY_DOWN, 4 },
2560 { EL_YAMYAM_LEFT, 5 },
2561 { EL_YAMYAM_RIGHT, 5 },
2562 { EL_YAMYAM_UP, 5 },
2563 { EL_YAMYAM_DOWN, 5 },
2564 { EL_DARK_YAMYAM, 6 },
2567 { EL_PACMAN_LEFT, 8 },
2568 { EL_PACMAN_RIGHT, 8 },
2569 { EL_PACMAN_UP, 8 },
2570 { EL_PACMAN_DOWN, 8 },
2572 { EL_MOLE_LEFT, 9 },
2573 { EL_MOLE_RIGHT, 9 },
2575 { EL_MOLE_DOWN, 9 },
2579 { EL_SATELLITE, 13 },
2580 { EL_SP_SNIKSNAK, 14 },
2581 { EL_SP_ELECTRON, 15 },
2584 { EL_EMC_ANDROID, 18 },
2589 static struct PropertyBitInfo pb_dont_collide_with[] =
2591 { EL_SP_SNIKSNAK, 0 },
2592 { EL_SP_ELECTRON, 1 },
2600 struct PropertyBitInfo *pb_info;
2603 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2604 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2609 struct PropertyBitInfo *pb_info = NULL;
2612 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2613 if (pb_definition[i].bit_nr == property_bit_nr)
2614 pb_info = pb_definition[i].pb_info;
2616 if (pb_info == NULL)
2619 for (i = 0; pb_info[i].element != -1; i++)
2620 if (pb_info[i].element == element)
2621 return pb_info[i].bit_nr;
2626 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2627 boolean property_value)
2629 int bit_nr = get_special_property_bit(element, property_bit_nr);
2634 *bitfield |= (1 << bit_nr);
2636 *bitfield &= ~(1 << bit_nr);
2640 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2642 int bit_nr = get_special_property_bit(element, property_bit_nr);
2645 return ((*bitfield & (1 << bit_nr)) != 0);
2650 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2652 static int group_nr;
2653 static struct ElementGroupInfo *group;
2654 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2657 if (actual_group == NULL) /* not yet initialized */
2660 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
2662 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2663 group_element - EL_GROUP_START + 1);
2665 /* replace element which caused too deep recursion by question mark */
2666 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2671 if (recursion_depth == 0) /* initialization */
2673 group = actual_group;
2674 group_nr = GROUP_NR(group_element);
2676 group->num_elements_resolved = 0;
2677 group->choice_pos = 0;
2679 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2680 element_info[i].in_group[group_nr] = FALSE;
2683 for (i = 0; i < actual_group->num_elements; i++)
2685 int element = actual_group->element[i];
2687 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2690 if (IS_GROUP_ELEMENT(element))
2691 ResolveGroupElementExt(element, recursion_depth + 1);
2694 group->element_resolved[group->num_elements_resolved++] = element;
2695 element_info[element].in_group[group_nr] = TRUE;
2700 void ResolveGroupElement(int group_element)
2702 ResolveGroupElementExt(group_element, 0);
2705 void InitElementPropertiesStatic()
2707 static boolean clipboard_elements_initialized = FALSE;
2709 static int ep_diggable[] =
2714 EL_SP_BUGGY_BASE_ACTIVATING,
2717 EL_INVISIBLE_SAND_ACTIVE,
2720 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2721 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2726 EL_SP_BUGGY_BASE_ACTIVE,
2733 static int ep_collectible_only[] =
2755 EL_DYNABOMB_INCREASE_NUMBER,
2756 EL_DYNABOMB_INCREASE_SIZE,
2757 EL_DYNABOMB_INCREASE_POWER,
2775 /* !!! handle separately !!! */
2776 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2782 static int ep_dont_run_into[] =
2784 /* same elements as in 'ep_dont_touch' */
2790 /* same elements as in 'ep_dont_collide_with' */
2802 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2807 EL_SP_BUGGY_BASE_ACTIVE,
2814 static int ep_dont_collide_with[] =
2816 /* same elements as in 'ep_dont_touch' */
2833 static int ep_dont_touch[] =
2843 static int ep_indestructible[] =
2847 EL_ACID_POOL_TOPLEFT,
2848 EL_ACID_POOL_TOPRIGHT,
2849 EL_ACID_POOL_BOTTOMLEFT,
2850 EL_ACID_POOL_BOTTOM,
2851 EL_ACID_POOL_BOTTOMRIGHT,
2852 EL_SP_HARDWARE_GRAY,
2853 EL_SP_HARDWARE_GREEN,
2854 EL_SP_HARDWARE_BLUE,
2856 EL_SP_HARDWARE_YELLOW,
2857 EL_SP_HARDWARE_BASE_1,
2858 EL_SP_HARDWARE_BASE_2,
2859 EL_SP_HARDWARE_BASE_3,
2860 EL_SP_HARDWARE_BASE_4,
2861 EL_SP_HARDWARE_BASE_5,
2862 EL_SP_HARDWARE_BASE_6,
2863 EL_INVISIBLE_STEELWALL,
2864 EL_INVISIBLE_STEELWALL_ACTIVE,
2865 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2866 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2867 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2868 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2869 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2870 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2871 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2872 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2873 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2874 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2875 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2876 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2878 EL_LIGHT_SWITCH_ACTIVE,
2879 EL_SIGN_EXCLAMATION,
2880 EL_SIGN_RADIOACTIVITY,
2887 EL_SIGN_ENTRY_FORBIDDEN,
2888 EL_SIGN_EMERGENCY_EXIT,
2896 EL_STEEL_EXIT_CLOSED,
2898 EL_STEEL_EXIT_OPENING,
2899 EL_STEEL_EXIT_CLOSING,
2900 EL_EM_STEEL_EXIT_CLOSED,
2901 EL_EM_STEEL_EXIT_OPEN,
2902 EL_EM_STEEL_EXIT_OPENING,
2903 EL_EM_STEEL_EXIT_CLOSING,
2904 EL_DC_STEELWALL_1_LEFT,
2905 EL_DC_STEELWALL_1_RIGHT,
2906 EL_DC_STEELWALL_1_TOP,
2907 EL_DC_STEELWALL_1_BOTTOM,
2908 EL_DC_STEELWALL_1_HORIZONTAL,
2909 EL_DC_STEELWALL_1_VERTICAL,
2910 EL_DC_STEELWALL_1_TOPLEFT,
2911 EL_DC_STEELWALL_1_TOPRIGHT,
2912 EL_DC_STEELWALL_1_BOTTOMLEFT,
2913 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2914 EL_DC_STEELWALL_1_TOPLEFT_2,
2915 EL_DC_STEELWALL_1_TOPRIGHT_2,
2916 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2917 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2918 EL_DC_STEELWALL_2_LEFT,
2919 EL_DC_STEELWALL_2_RIGHT,
2920 EL_DC_STEELWALL_2_TOP,
2921 EL_DC_STEELWALL_2_BOTTOM,
2922 EL_DC_STEELWALL_2_HORIZONTAL,
2923 EL_DC_STEELWALL_2_VERTICAL,
2924 EL_DC_STEELWALL_2_MIDDLE,
2925 EL_DC_STEELWALL_2_SINGLE,
2926 EL_STEELWALL_SLIPPERY,
2940 EL_GATE_1_GRAY_ACTIVE,
2941 EL_GATE_2_GRAY_ACTIVE,
2942 EL_GATE_3_GRAY_ACTIVE,
2943 EL_GATE_4_GRAY_ACTIVE,
2952 EL_EM_GATE_1_GRAY_ACTIVE,
2953 EL_EM_GATE_2_GRAY_ACTIVE,
2954 EL_EM_GATE_3_GRAY_ACTIVE,
2955 EL_EM_GATE_4_GRAY_ACTIVE,
2964 EL_EMC_GATE_5_GRAY_ACTIVE,
2965 EL_EMC_GATE_6_GRAY_ACTIVE,
2966 EL_EMC_GATE_7_GRAY_ACTIVE,
2967 EL_EMC_GATE_8_GRAY_ACTIVE,
2969 EL_DC_GATE_WHITE_GRAY,
2970 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2971 EL_DC_GATE_FAKE_GRAY,
2973 EL_SWITCHGATE_OPENING,
2974 EL_SWITCHGATE_CLOSED,
2975 EL_SWITCHGATE_CLOSING,
2977 EL_DC_SWITCHGATE_SWITCH_UP,
2978 EL_DC_SWITCHGATE_SWITCH_DOWN,
2981 EL_TIMEGATE_OPENING,
2983 EL_TIMEGATE_CLOSING,
2985 EL_DC_TIMEGATE_SWITCH,
2986 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2991 EL_TUBE_VERTICAL_LEFT,
2992 EL_TUBE_VERTICAL_RIGHT,
2993 EL_TUBE_HORIZONTAL_UP,
2994 EL_TUBE_HORIZONTAL_DOWN,
2999 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
3000 EL_EXPANDABLE_STEELWALL_VERTICAL,
3001 EL_EXPANDABLE_STEELWALL_ANY,
3006 static int ep_slippery[] =
3020 EL_ROBOT_WHEEL_ACTIVE,
3026 EL_ACID_POOL_TOPLEFT,
3027 EL_ACID_POOL_TOPRIGHT,
3037 EL_STEELWALL_SLIPPERY,
3040 EL_EMC_WALL_SLIPPERY_1,
3041 EL_EMC_WALL_SLIPPERY_2,
3042 EL_EMC_WALL_SLIPPERY_3,
3043 EL_EMC_WALL_SLIPPERY_4,
3045 EL_EMC_MAGIC_BALL_ACTIVE,
3050 static int ep_can_change[] =
3055 static int ep_can_move[] =
3057 /* same elements as in 'pb_can_move_into_acid' */
3080 static int ep_can_fall[] =
3094 EL_QUICKSAND_FAST_FULL,
3096 EL_BD_MAGIC_WALL_FULL,
3097 EL_DC_MAGIC_WALL_FULL,
3111 static int ep_can_smash_player[] =
3137 static int ep_can_smash_enemies[] =
3146 static int ep_can_smash_everything[] =
3155 static int ep_explodes_by_fire[] =
3157 /* same elements as in 'ep_explodes_impact' */
3162 /* same elements as in 'ep_explodes_smashed' */
3172 EL_EM_DYNAMITE_ACTIVE,
3173 EL_DYNABOMB_PLAYER_1_ACTIVE,
3174 EL_DYNABOMB_PLAYER_2_ACTIVE,
3175 EL_DYNABOMB_PLAYER_3_ACTIVE,
3176 EL_DYNABOMB_PLAYER_4_ACTIVE,
3177 EL_DYNABOMB_INCREASE_NUMBER,
3178 EL_DYNABOMB_INCREASE_SIZE,
3179 EL_DYNABOMB_INCREASE_POWER,
3180 EL_SP_DISK_RED_ACTIVE,
3194 static int ep_explodes_smashed[] =
3196 /* same elements as in 'ep_explodes_impact' */
3210 static int ep_explodes_impact[] =
3219 static int ep_walkable_over[] =
3223 EL_SOKOBAN_FIELD_EMPTY,
3232 EL_EM_STEEL_EXIT_OPEN,
3234 EL_EM_STEEL_EXIT_OPENING,
3244 EL_GATE_1_GRAY_ACTIVE,
3245 EL_GATE_2_GRAY_ACTIVE,
3246 EL_GATE_3_GRAY_ACTIVE,
3247 EL_GATE_4_GRAY_ACTIVE,
3255 static int ep_walkable_inside[] =
3260 EL_TUBE_VERTICAL_LEFT,
3261 EL_TUBE_VERTICAL_RIGHT,
3262 EL_TUBE_HORIZONTAL_UP,
3263 EL_TUBE_HORIZONTAL_DOWN,
3272 static int ep_walkable_under[] =
3277 static int ep_passable_over[] =
3287 EL_EM_GATE_1_GRAY_ACTIVE,
3288 EL_EM_GATE_2_GRAY_ACTIVE,
3289 EL_EM_GATE_3_GRAY_ACTIVE,
3290 EL_EM_GATE_4_GRAY_ACTIVE,
3299 EL_EMC_GATE_5_GRAY_ACTIVE,
3300 EL_EMC_GATE_6_GRAY_ACTIVE,
3301 EL_EMC_GATE_7_GRAY_ACTIVE,
3302 EL_EMC_GATE_8_GRAY_ACTIVE,
3304 EL_DC_GATE_WHITE_GRAY,
3305 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3312 static int ep_passable_inside[] =
3318 EL_SP_PORT_HORIZONTAL,
3319 EL_SP_PORT_VERTICAL,
3321 EL_SP_GRAVITY_PORT_LEFT,
3322 EL_SP_GRAVITY_PORT_RIGHT,
3323 EL_SP_GRAVITY_PORT_UP,
3324 EL_SP_GRAVITY_PORT_DOWN,
3325 EL_SP_GRAVITY_ON_PORT_LEFT,
3326 EL_SP_GRAVITY_ON_PORT_RIGHT,
3327 EL_SP_GRAVITY_ON_PORT_UP,
3328 EL_SP_GRAVITY_ON_PORT_DOWN,
3329 EL_SP_GRAVITY_OFF_PORT_LEFT,
3330 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3331 EL_SP_GRAVITY_OFF_PORT_UP,
3332 EL_SP_GRAVITY_OFF_PORT_DOWN,
3337 static int ep_passable_under[] =
3342 static int ep_droppable[] =
3347 static int ep_explodes_1x1_old[] =
3352 static int ep_pushable[] =
3364 EL_SOKOBAN_FIELD_FULL,
3373 static int ep_explodes_cross_old[] =
3378 static int ep_protected[] =
3380 /* same elements as in 'ep_walkable_inside' */
3384 EL_TUBE_VERTICAL_LEFT,
3385 EL_TUBE_VERTICAL_RIGHT,
3386 EL_TUBE_HORIZONTAL_UP,
3387 EL_TUBE_HORIZONTAL_DOWN,
3393 /* same elements as in 'ep_passable_over' */
3402 EL_EM_GATE_1_GRAY_ACTIVE,
3403 EL_EM_GATE_2_GRAY_ACTIVE,
3404 EL_EM_GATE_3_GRAY_ACTIVE,
3405 EL_EM_GATE_4_GRAY_ACTIVE,
3414 EL_EMC_GATE_5_GRAY_ACTIVE,
3415 EL_EMC_GATE_6_GRAY_ACTIVE,
3416 EL_EMC_GATE_7_GRAY_ACTIVE,
3417 EL_EMC_GATE_8_GRAY_ACTIVE,
3419 EL_DC_GATE_WHITE_GRAY,
3420 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3424 /* same elements as in 'ep_passable_inside' */
3429 EL_SP_PORT_HORIZONTAL,
3430 EL_SP_PORT_VERTICAL,
3432 EL_SP_GRAVITY_PORT_LEFT,
3433 EL_SP_GRAVITY_PORT_RIGHT,
3434 EL_SP_GRAVITY_PORT_UP,
3435 EL_SP_GRAVITY_PORT_DOWN,
3436 EL_SP_GRAVITY_ON_PORT_LEFT,
3437 EL_SP_GRAVITY_ON_PORT_RIGHT,
3438 EL_SP_GRAVITY_ON_PORT_UP,
3439 EL_SP_GRAVITY_ON_PORT_DOWN,
3440 EL_SP_GRAVITY_OFF_PORT_LEFT,
3441 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3442 EL_SP_GRAVITY_OFF_PORT_UP,
3443 EL_SP_GRAVITY_OFF_PORT_DOWN,
3448 static int ep_throwable[] =
3453 static int ep_can_explode[] =
3455 /* same elements as in 'ep_explodes_impact' */
3460 /* same elements as in 'ep_explodes_smashed' */
3466 /* elements that can explode by explosion or by dragonfire */
3470 EL_EM_DYNAMITE_ACTIVE,
3471 EL_DYNABOMB_PLAYER_1_ACTIVE,
3472 EL_DYNABOMB_PLAYER_2_ACTIVE,
3473 EL_DYNABOMB_PLAYER_3_ACTIVE,
3474 EL_DYNABOMB_PLAYER_4_ACTIVE,
3475 EL_DYNABOMB_INCREASE_NUMBER,
3476 EL_DYNABOMB_INCREASE_SIZE,
3477 EL_DYNABOMB_INCREASE_POWER,
3478 EL_SP_DISK_RED_ACTIVE,
3486 /* elements that can explode only by explosion */
3492 static int ep_gravity_reachable[] =
3498 EL_INVISIBLE_SAND_ACTIVE,
3503 EL_SP_PORT_HORIZONTAL,
3504 EL_SP_PORT_VERTICAL,
3506 EL_SP_GRAVITY_PORT_LEFT,
3507 EL_SP_GRAVITY_PORT_RIGHT,
3508 EL_SP_GRAVITY_PORT_UP,
3509 EL_SP_GRAVITY_PORT_DOWN,
3510 EL_SP_GRAVITY_ON_PORT_LEFT,
3511 EL_SP_GRAVITY_ON_PORT_RIGHT,
3512 EL_SP_GRAVITY_ON_PORT_UP,
3513 EL_SP_GRAVITY_ON_PORT_DOWN,
3514 EL_SP_GRAVITY_OFF_PORT_LEFT,
3515 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3516 EL_SP_GRAVITY_OFF_PORT_UP,
3517 EL_SP_GRAVITY_OFF_PORT_DOWN,
3523 static int ep_player[] =
3530 EL_SOKOBAN_FIELD_PLAYER,
3536 static int ep_can_pass_magic_wall[] =
3550 static int ep_can_pass_dc_magic_wall[] =
3566 static int ep_switchable[] =
3570 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3571 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3572 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3573 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3574 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3575 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3576 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3577 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3578 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3579 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3580 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3581 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3582 EL_SWITCHGATE_SWITCH_UP,
3583 EL_SWITCHGATE_SWITCH_DOWN,
3584 EL_DC_SWITCHGATE_SWITCH_UP,
3585 EL_DC_SWITCHGATE_SWITCH_DOWN,
3587 EL_LIGHT_SWITCH_ACTIVE,
3589 EL_DC_TIMEGATE_SWITCH,
3590 EL_BALLOON_SWITCH_LEFT,
3591 EL_BALLOON_SWITCH_RIGHT,
3592 EL_BALLOON_SWITCH_UP,
3593 EL_BALLOON_SWITCH_DOWN,
3594 EL_BALLOON_SWITCH_ANY,
3595 EL_BALLOON_SWITCH_NONE,
3598 EL_EMC_MAGIC_BALL_SWITCH,
3599 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3604 static int ep_bd_element[] =
3638 static int ep_sp_element[] =
3640 /* should always be valid */
3643 /* standard classic Supaplex elements */
3650 EL_SP_HARDWARE_GRAY,
3658 EL_SP_GRAVITY_PORT_RIGHT,
3659 EL_SP_GRAVITY_PORT_DOWN,
3660 EL_SP_GRAVITY_PORT_LEFT,
3661 EL_SP_GRAVITY_PORT_UP,
3666 EL_SP_PORT_VERTICAL,
3667 EL_SP_PORT_HORIZONTAL,
3673 EL_SP_HARDWARE_BASE_1,
3674 EL_SP_HARDWARE_GREEN,
3675 EL_SP_HARDWARE_BLUE,
3677 EL_SP_HARDWARE_YELLOW,
3678 EL_SP_HARDWARE_BASE_2,
3679 EL_SP_HARDWARE_BASE_3,
3680 EL_SP_HARDWARE_BASE_4,
3681 EL_SP_HARDWARE_BASE_5,
3682 EL_SP_HARDWARE_BASE_6,
3686 /* additional elements that appeared in newer Supaplex levels */
3689 /* additional gravity port elements (not switching, but setting gravity) */
3690 EL_SP_GRAVITY_ON_PORT_LEFT,
3691 EL_SP_GRAVITY_ON_PORT_RIGHT,
3692 EL_SP_GRAVITY_ON_PORT_UP,
3693 EL_SP_GRAVITY_ON_PORT_DOWN,
3694 EL_SP_GRAVITY_OFF_PORT_LEFT,
3695 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3696 EL_SP_GRAVITY_OFF_PORT_UP,
3697 EL_SP_GRAVITY_OFF_PORT_DOWN,
3699 /* more than one Murphy in a level results in an inactive clone */
3702 /* runtime Supaplex elements */
3703 EL_SP_DISK_RED_ACTIVE,
3704 EL_SP_TERMINAL_ACTIVE,
3705 EL_SP_BUGGY_BASE_ACTIVATING,
3706 EL_SP_BUGGY_BASE_ACTIVE,
3713 static int ep_sb_element[] =
3718 EL_SOKOBAN_FIELD_EMPTY,
3719 EL_SOKOBAN_FIELD_FULL,
3720 EL_SOKOBAN_FIELD_PLAYER,
3725 EL_INVISIBLE_STEELWALL,
3730 static int ep_gem[] =
3742 static int ep_food_dark_yamyam[] =
3770 static int ep_food_penguin[] =
3784 static int ep_food_pig[] =
3796 static int ep_historic_wall[] =
3807 EL_GATE_1_GRAY_ACTIVE,
3808 EL_GATE_2_GRAY_ACTIVE,
3809 EL_GATE_3_GRAY_ACTIVE,
3810 EL_GATE_4_GRAY_ACTIVE,
3819 EL_EM_GATE_1_GRAY_ACTIVE,
3820 EL_EM_GATE_2_GRAY_ACTIVE,
3821 EL_EM_GATE_3_GRAY_ACTIVE,
3822 EL_EM_GATE_4_GRAY_ACTIVE,
3829 EL_EXPANDABLE_WALL_HORIZONTAL,
3830 EL_EXPANDABLE_WALL_VERTICAL,
3831 EL_EXPANDABLE_WALL_ANY,
3832 EL_EXPANDABLE_WALL_GROWING,
3833 EL_BD_EXPANDABLE_WALL,
3840 EL_SP_HARDWARE_GRAY,
3841 EL_SP_HARDWARE_GREEN,
3842 EL_SP_HARDWARE_BLUE,
3844 EL_SP_HARDWARE_YELLOW,
3845 EL_SP_HARDWARE_BASE_1,
3846 EL_SP_HARDWARE_BASE_2,
3847 EL_SP_HARDWARE_BASE_3,
3848 EL_SP_HARDWARE_BASE_4,
3849 EL_SP_HARDWARE_BASE_5,
3850 EL_SP_HARDWARE_BASE_6,
3852 EL_SP_TERMINAL_ACTIVE,
3855 EL_INVISIBLE_STEELWALL,
3856 EL_INVISIBLE_STEELWALL_ACTIVE,
3858 EL_INVISIBLE_WALL_ACTIVE,
3859 EL_STEELWALL_SLIPPERY,
3876 static int ep_historic_solid[] =
3880 EL_EXPANDABLE_WALL_HORIZONTAL,
3881 EL_EXPANDABLE_WALL_VERTICAL,
3882 EL_EXPANDABLE_WALL_ANY,
3883 EL_BD_EXPANDABLE_WALL,
3896 EL_QUICKSAND_FILLING,
3897 EL_QUICKSAND_EMPTYING,
3899 EL_MAGIC_WALL_ACTIVE,
3900 EL_MAGIC_WALL_EMPTYING,
3901 EL_MAGIC_WALL_FILLING,
3905 EL_BD_MAGIC_WALL_ACTIVE,
3906 EL_BD_MAGIC_WALL_EMPTYING,
3907 EL_BD_MAGIC_WALL_FULL,
3908 EL_BD_MAGIC_WALL_FILLING,
3909 EL_BD_MAGIC_WALL_DEAD,
3918 EL_SP_TERMINAL_ACTIVE,
3922 EL_INVISIBLE_WALL_ACTIVE,
3923 EL_SWITCHGATE_SWITCH_UP,
3924 EL_SWITCHGATE_SWITCH_DOWN,
3925 EL_DC_SWITCHGATE_SWITCH_UP,
3926 EL_DC_SWITCHGATE_SWITCH_DOWN,
3928 EL_TIMEGATE_SWITCH_ACTIVE,
3929 EL_DC_TIMEGATE_SWITCH,
3930 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3942 /* the following elements are a direct copy of "indestructible" elements,
3943 except "EL_ACID", which is "indestructible", but not "solid"! */
3948 EL_ACID_POOL_TOPLEFT,
3949 EL_ACID_POOL_TOPRIGHT,
3950 EL_ACID_POOL_BOTTOMLEFT,
3951 EL_ACID_POOL_BOTTOM,
3952 EL_ACID_POOL_BOTTOMRIGHT,
3953 EL_SP_HARDWARE_GRAY,
3954 EL_SP_HARDWARE_GREEN,
3955 EL_SP_HARDWARE_BLUE,
3957 EL_SP_HARDWARE_YELLOW,
3958 EL_SP_HARDWARE_BASE_1,
3959 EL_SP_HARDWARE_BASE_2,
3960 EL_SP_HARDWARE_BASE_3,
3961 EL_SP_HARDWARE_BASE_4,
3962 EL_SP_HARDWARE_BASE_5,
3963 EL_SP_HARDWARE_BASE_6,
3964 EL_INVISIBLE_STEELWALL,
3965 EL_INVISIBLE_STEELWALL_ACTIVE,
3966 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3967 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3968 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3969 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3970 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3971 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3972 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3973 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3974 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3975 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3976 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3977 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3979 EL_LIGHT_SWITCH_ACTIVE,
3980 EL_SIGN_EXCLAMATION,
3981 EL_SIGN_RADIOACTIVITY,
3988 EL_SIGN_ENTRY_FORBIDDEN,
3989 EL_SIGN_EMERGENCY_EXIT,
3997 EL_STEEL_EXIT_CLOSED,
3999 EL_DC_STEELWALL_1_LEFT,
4000 EL_DC_STEELWALL_1_RIGHT,
4001 EL_DC_STEELWALL_1_TOP,
4002 EL_DC_STEELWALL_1_BOTTOM,
4003 EL_DC_STEELWALL_1_HORIZONTAL,
4004 EL_DC_STEELWALL_1_VERTICAL,
4005 EL_DC_STEELWALL_1_TOPLEFT,
4006 EL_DC_STEELWALL_1_TOPRIGHT,
4007 EL_DC_STEELWALL_1_BOTTOMLEFT,
4008 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4009 EL_DC_STEELWALL_1_TOPLEFT_2,
4010 EL_DC_STEELWALL_1_TOPRIGHT_2,
4011 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4012 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4013 EL_DC_STEELWALL_2_LEFT,
4014 EL_DC_STEELWALL_2_RIGHT,
4015 EL_DC_STEELWALL_2_TOP,
4016 EL_DC_STEELWALL_2_BOTTOM,
4017 EL_DC_STEELWALL_2_HORIZONTAL,
4018 EL_DC_STEELWALL_2_VERTICAL,
4019 EL_DC_STEELWALL_2_MIDDLE,
4020 EL_DC_STEELWALL_2_SINGLE,
4021 EL_STEELWALL_SLIPPERY,
4035 EL_GATE_1_GRAY_ACTIVE,
4036 EL_GATE_2_GRAY_ACTIVE,
4037 EL_GATE_3_GRAY_ACTIVE,
4038 EL_GATE_4_GRAY_ACTIVE,
4047 EL_EM_GATE_1_GRAY_ACTIVE,
4048 EL_EM_GATE_2_GRAY_ACTIVE,
4049 EL_EM_GATE_3_GRAY_ACTIVE,
4050 EL_EM_GATE_4_GRAY_ACTIVE,
4052 EL_SWITCHGATE_OPENING,
4053 EL_SWITCHGATE_CLOSED,
4054 EL_SWITCHGATE_CLOSING,
4056 EL_TIMEGATE_OPENING,
4058 EL_TIMEGATE_CLOSING,
4062 EL_TUBE_VERTICAL_LEFT,
4063 EL_TUBE_VERTICAL_RIGHT,
4064 EL_TUBE_HORIZONTAL_UP,
4065 EL_TUBE_HORIZONTAL_DOWN,
4074 static int ep_classic_enemy[] =
4091 static int ep_belt[] =
4093 EL_CONVEYOR_BELT_1_LEFT,
4094 EL_CONVEYOR_BELT_1_MIDDLE,
4095 EL_CONVEYOR_BELT_1_RIGHT,
4096 EL_CONVEYOR_BELT_2_LEFT,
4097 EL_CONVEYOR_BELT_2_MIDDLE,
4098 EL_CONVEYOR_BELT_2_RIGHT,
4099 EL_CONVEYOR_BELT_3_LEFT,
4100 EL_CONVEYOR_BELT_3_MIDDLE,
4101 EL_CONVEYOR_BELT_3_RIGHT,
4102 EL_CONVEYOR_BELT_4_LEFT,
4103 EL_CONVEYOR_BELT_4_MIDDLE,
4104 EL_CONVEYOR_BELT_4_RIGHT,
4109 static int ep_belt_active[] =
4111 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
4112 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
4113 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
4114 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
4115 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
4116 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
4117 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
4118 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
4119 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
4120 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
4121 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
4122 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
4127 static int ep_belt_switch[] =
4129 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4130 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4131 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4132 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4133 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4134 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4135 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4136 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4137 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4138 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4139 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4140 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4145 static int ep_tube[] =
4152 EL_TUBE_HORIZONTAL_UP,
4153 EL_TUBE_HORIZONTAL_DOWN,
4155 EL_TUBE_VERTICAL_LEFT,
4156 EL_TUBE_VERTICAL_RIGHT,
4162 static int ep_acid_pool[] =
4164 EL_ACID_POOL_TOPLEFT,
4165 EL_ACID_POOL_TOPRIGHT,
4166 EL_ACID_POOL_BOTTOMLEFT,
4167 EL_ACID_POOL_BOTTOM,
4168 EL_ACID_POOL_BOTTOMRIGHT,
4173 static int ep_keygate[] =
4183 EL_GATE_1_GRAY_ACTIVE,
4184 EL_GATE_2_GRAY_ACTIVE,
4185 EL_GATE_3_GRAY_ACTIVE,
4186 EL_GATE_4_GRAY_ACTIVE,
4195 EL_EM_GATE_1_GRAY_ACTIVE,
4196 EL_EM_GATE_2_GRAY_ACTIVE,
4197 EL_EM_GATE_3_GRAY_ACTIVE,
4198 EL_EM_GATE_4_GRAY_ACTIVE,
4207 EL_EMC_GATE_5_GRAY_ACTIVE,
4208 EL_EMC_GATE_6_GRAY_ACTIVE,
4209 EL_EMC_GATE_7_GRAY_ACTIVE,
4210 EL_EMC_GATE_8_GRAY_ACTIVE,
4212 EL_DC_GATE_WHITE_GRAY,
4213 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4218 static int ep_amoeboid[] =
4230 static int ep_amoebalive[] =
4241 static int ep_has_editor_content[] =
4247 EL_SOKOBAN_FIELD_PLAYER,
4264 static int ep_can_turn_each_move[] =
4266 /* !!! do something with this one !!! */
4270 static int ep_can_grow[] =
4284 static int ep_active_bomb[] =
4287 EL_EM_DYNAMITE_ACTIVE,
4288 EL_DYNABOMB_PLAYER_1_ACTIVE,
4289 EL_DYNABOMB_PLAYER_2_ACTIVE,
4290 EL_DYNABOMB_PLAYER_3_ACTIVE,
4291 EL_DYNABOMB_PLAYER_4_ACTIVE,
4292 EL_SP_DISK_RED_ACTIVE,
4297 static int ep_inactive[] =
4307 EL_QUICKSAND_FAST_EMPTY,
4330 EL_GATE_1_GRAY_ACTIVE,
4331 EL_GATE_2_GRAY_ACTIVE,
4332 EL_GATE_3_GRAY_ACTIVE,
4333 EL_GATE_4_GRAY_ACTIVE,
4342 EL_EM_GATE_1_GRAY_ACTIVE,
4343 EL_EM_GATE_2_GRAY_ACTIVE,
4344 EL_EM_GATE_3_GRAY_ACTIVE,
4345 EL_EM_GATE_4_GRAY_ACTIVE,
4354 EL_EMC_GATE_5_GRAY_ACTIVE,
4355 EL_EMC_GATE_6_GRAY_ACTIVE,
4356 EL_EMC_GATE_7_GRAY_ACTIVE,
4357 EL_EMC_GATE_8_GRAY_ACTIVE,
4359 EL_DC_GATE_WHITE_GRAY,
4360 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4361 EL_DC_GATE_FAKE_GRAY,
4364 EL_INVISIBLE_STEELWALL,
4372 EL_WALL_EMERALD_YELLOW,
4373 EL_DYNABOMB_INCREASE_NUMBER,
4374 EL_DYNABOMB_INCREASE_SIZE,
4375 EL_DYNABOMB_INCREASE_POWER,
4379 EL_SOKOBAN_FIELD_EMPTY,
4380 EL_SOKOBAN_FIELD_FULL,
4381 EL_WALL_EMERALD_RED,
4382 EL_WALL_EMERALD_PURPLE,
4383 EL_ACID_POOL_TOPLEFT,
4384 EL_ACID_POOL_TOPRIGHT,
4385 EL_ACID_POOL_BOTTOMLEFT,
4386 EL_ACID_POOL_BOTTOM,
4387 EL_ACID_POOL_BOTTOMRIGHT,
4391 EL_BD_MAGIC_WALL_DEAD,
4393 EL_DC_MAGIC_WALL_DEAD,
4394 EL_AMOEBA_TO_DIAMOND,
4402 EL_SP_GRAVITY_PORT_RIGHT,
4403 EL_SP_GRAVITY_PORT_DOWN,
4404 EL_SP_GRAVITY_PORT_LEFT,
4405 EL_SP_GRAVITY_PORT_UP,
4406 EL_SP_PORT_HORIZONTAL,
4407 EL_SP_PORT_VERTICAL,
4418 EL_SP_HARDWARE_GRAY,
4419 EL_SP_HARDWARE_GREEN,
4420 EL_SP_HARDWARE_BLUE,
4422 EL_SP_HARDWARE_YELLOW,
4423 EL_SP_HARDWARE_BASE_1,
4424 EL_SP_HARDWARE_BASE_2,
4425 EL_SP_HARDWARE_BASE_3,
4426 EL_SP_HARDWARE_BASE_4,
4427 EL_SP_HARDWARE_BASE_5,
4428 EL_SP_HARDWARE_BASE_6,
4429 EL_SP_GRAVITY_ON_PORT_LEFT,
4430 EL_SP_GRAVITY_ON_PORT_RIGHT,
4431 EL_SP_GRAVITY_ON_PORT_UP,
4432 EL_SP_GRAVITY_ON_PORT_DOWN,
4433 EL_SP_GRAVITY_OFF_PORT_LEFT,
4434 EL_SP_GRAVITY_OFF_PORT_RIGHT,
4435 EL_SP_GRAVITY_OFF_PORT_UP,
4436 EL_SP_GRAVITY_OFF_PORT_DOWN,
4437 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4438 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4439 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4440 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4441 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4442 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4443 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4444 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4445 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4446 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4447 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4448 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4449 EL_SIGN_EXCLAMATION,
4450 EL_SIGN_RADIOACTIVITY,
4457 EL_SIGN_ENTRY_FORBIDDEN,
4458 EL_SIGN_EMERGENCY_EXIT,
4466 EL_DC_STEELWALL_1_LEFT,
4467 EL_DC_STEELWALL_1_RIGHT,
4468 EL_DC_STEELWALL_1_TOP,
4469 EL_DC_STEELWALL_1_BOTTOM,
4470 EL_DC_STEELWALL_1_HORIZONTAL,
4471 EL_DC_STEELWALL_1_VERTICAL,
4472 EL_DC_STEELWALL_1_TOPLEFT,
4473 EL_DC_STEELWALL_1_TOPRIGHT,
4474 EL_DC_STEELWALL_1_BOTTOMLEFT,
4475 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4476 EL_DC_STEELWALL_1_TOPLEFT_2,
4477 EL_DC_STEELWALL_1_TOPRIGHT_2,
4478 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4479 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4480 EL_DC_STEELWALL_2_LEFT,
4481 EL_DC_STEELWALL_2_RIGHT,
4482 EL_DC_STEELWALL_2_TOP,
4483 EL_DC_STEELWALL_2_BOTTOM,
4484 EL_DC_STEELWALL_2_HORIZONTAL,
4485 EL_DC_STEELWALL_2_VERTICAL,
4486 EL_DC_STEELWALL_2_MIDDLE,
4487 EL_DC_STEELWALL_2_SINGLE,
4488 EL_STEELWALL_SLIPPERY,
4493 EL_EMC_WALL_SLIPPERY_1,
4494 EL_EMC_WALL_SLIPPERY_2,
4495 EL_EMC_WALL_SLIPPERY_3,
4496 EL_EMC_WALL_SLIPPERY_4,
4517 static int ep_em_slippery_wall[] =
4522 static int ep_gfx_crumbled[] =
4533 static int ep_editor_cascade_active[] =
4535 EL_INTERNAL_CASCADE_BD_ACTIVE,
4536 EL_INTERNAL_CASCADE_EM_ACTIVE,
4537 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4538 EL_INTERNAL_CASCADE_RND_ACTIVE,
4539 EL_INTERNAL_CASCADE_SB_ACTIVE,
4540 EL_INTERNAL_CASCADE_SP_ACTIVE,
4541 EL_INTERNAL_CASCADE_DC_ACTIVE,
4542 EL_INTERNAL_CASCADE_DX_ACTIVE,
4543 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4544 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4545 EL_INTERNAL_CASCADE_CE_ACTIVE,
4546 EL_INTERNAL_CASCADE_GE_ACTIVE,
4547 EL_INTERNAL_CASCADE_REF_ACTIVE,
4548 EL_INTERNAL_CASCADE_USER_ACTIVE,
4549 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4554 static int ep_editor_cascade_inactive[] =
4556 EL_INTERNAL_CASCADE_BD,
4557 EL_INTERNAL_CASCADE_EM,
4558 EL_INTERNAL_CASCADE_EMC,
4559 EL_INTERNAL_CASCADE_RND,
4560 EL_INTERNAL_CASCADE_SB,
4561 EL_INTERNAL_CASCADE_SP,
4562 EL_INTERNAL_CASCADE_DC,
4563 EL_INTERNAL_CASCADE_DX,
4564 EL_INTERNAL_CASCADE_CHARS,
4565 EL_INTERNAL_CASCADE_STEEL_CHARS,
4566 EL_INTERNAL_CASCADE_CE,
4567 EL_INTERNAL_CASCADE_GE,
4568 EL_INTERNAL_CASCADE_REF,
4569 EL_INTERNAL_CASCADE_USER,
4570 EL_INTERNAL_CASCADE_DYNAMIC,
4575 static int ep_obsolete[] =
4579 EL_EM_KEY_1_FILE_OBSOLETE,
4580 EL_EM_KEY_2_FILE_OBSOLETE,
4581 EL_EM_KEY_3_FILE_OBSOLETE,
4582 EL_EM_KEY_4_FILE_OBSOLETE,
4583 EL_ENVELOPE_OBSOLETE,
4592 } element_properties[] =
4594 { ep_diggable, EP_DIGGABLE },
4595 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4596 { ep_dont_run_into, EP_DONT_RUN_INTO },
4597 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4598 { ep_dont_touch, EP_DONT_TOUCH },
4599 { ep_indestructible, EP_INDESTRUCTIBLE },
4600 { ep_slippery, EP_SLIPPERY },
4601 { ep_can_change, EP_CAN_CHANGE },
4602 { ep_can_move, EP_CAN_MOVE },
4603 { ep_can_fall, EP_CAN_FALL },
4604 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4605 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4606 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4607 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4608 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4609 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4610 { ep_walkable_over, EP_WALKABLE_OVER },
4611 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4612 { ep_walkable_under, EP_WALKABLE_UNDER },
4613 { ep_passable_over, EP_PASSABLE_OVER },
4614 { ep_passable_inside, EP_PASSABLE_INSIDE },
4615 { ep_passable_under, EP_PASSABLE_UNDER },
4616 { ep_droppable, EP_DROPPABLE },
4617 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4618 { ep_pushable, EP_PUSHABLE },
4619 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4620 { ep_protected, EP_PROTECTED },
4621 { ep_throwable, EP_THROWABLE },
4622 { ep_can_explode, EP_CAN_EXPLODE },
4623 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4625 { ep_player, EP_PLAYER },
4626 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4627 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4628 { ep_switchable, EP_SWITCHABLE },
4629 { ep_bd_element, EP_BD_ELEMENT },
4630 { ep_sp_element, EP_SP_ELEMENT },
4631 { ep_sb_element, EP_SB_ELEMENT },
4633 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4634 { ep_food_penguin, EP_FOOD_PENGUIN },
4635 { ep_food_pig, EP_FOOD_PIG },
4636 { ep_historic_wall, EP_HISTORIC_WALL },
4637 { ep_historic_solid, EP_HISTORIC_SOLID },
4638 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4639 { ep_belt, EP_BELT },
4640 { ep_belt_active, EP_BELT_ACTIVE },
4641 { ep_belt_switch, EP_BELT_SWITCH },
4642 { ep_tube, EP_TUBE },
4643 { ep_acid_pool, EP_ACID_POOL },
4644 { ep_keygate, EP_KEYGATE },
4645 { ep_amoeboid, EP_AMOEBOID },
4646 { ep_amoebalive, EP_AMOEBALIVE },
4647 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4648 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4649 { ep_can_grow, EP_CAN_GROW },
4650 { ep_active_bomb, EP_ACTIVE_BOMB },
4651 { ep_inactive, EP_INACTIVE },
4653 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4655 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4657 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4658 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4660 { ep_obsolete, EP_OBSOLETE },
4667 /* always start with reliable default values (element has no properties) */
4668 /* (but never initialize clipboard elements after the very first time) */
4669 /* (to be able to use clipboard elements between several levels) */
4670 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4671 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4672 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4673 SET_PROPERTY(i, j, FALSE);
4675 /* set all base element properties from above array definitions */
4676 for (i = 0; element_properties[i].elements != NULL; i++)
4677 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4678 SET_PROPERTY((element_properties[i].elements)[j],
4679 element_properties[i].property, TRUE);
4681 /* copy properties to some elements that are only stored in level file */
4682 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4683 for (j = 0; copy_properties[j][0] != -1; j++)
4684 if (HAS_PROPERTY(copy_properties[j][0], i))
4685 for (k = 1; k <= 4; k++)
4686 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4688 /* set static element properties that are not listed in array definitions */
4689 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4690 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4692 clipboard_elements_initialized = TRUE;
4695 void InitElementPropertiesEngine(int engine_version)
4697 static int no_wall_properties[] =
4700 EP_COLLECTIBLE_ONLY,
4702 EP_DONT_COLLIDE_WITH,
4705 EP_CAN_SMASH_PLAYER,
4706 EP_CAN_SMASH_ENEMIES,
4707 EP_CAN_SMASH_EVERYTHING,
4712 EP_FOOD_DARK_YAMYAM,
4728 /* important: after initialization in InitElementPropertiesStatic(), the
4729 elements are not again initialized to a default value; therefore all
4730 changes have to make sure that they leave the element with a defined
4731 property (which means that conditional property changes must be set to
4732 a reliable default value before) */
4734 /* resolve group elements */
4735 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4736 ResolveGroupElement(EL_GROUP_START + i);
4738 /* set all special, combined or engine dependent element properties */
4739 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4741 /* do not change (already initialized) clipboard elements here */
4742 if (IS_CLIPBOARD_ELEMENT(i))
4745 /* ---------- INACTIVE ------------------------------------------------- */
4746 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4747 i <= EL_CHAR_END) ||
4748 (i >= EL_STEEL_CHAR_START &&
4749 i <= EL_STEEL_CHAR_END)));
4751 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4752 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4753 IS_WALKABLE_INSIDE(i) ||
4754 IS_WALKABLE_UNDER(i)));
4756 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4757 IS_PASSABLE_INSIDE(i) ||
4758 IS_PASSABLE_UNDER(i)));
4760 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4761 IS_PASSABLE_OVER(i)));
4763 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4764 IS_PASSABLE_INSIDE(i)));
4766 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4767 IS_PASSABLE_UNDER(i)));
4769 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4772 /* ---------- COLLECTIBLE ---------------------------------------------- */
4773 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4777 /* ---------- SNAPPABLE ------------------------------------------------ */
4778 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4779 IS_COLLECTIBLE(i) ||
4783 /* ---------- WALL ----------------------------------------------------- */
4784 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4786 for (j = 0; no_wall_properties[j] != -1; j++)
4787 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4788 i >= EL_FIRST_RUNTIME_UNREAL)
4789 SET_PROPERTY(i, EP_WALL, FALSE);
4791 if (IS_HISTORIC_WALL(i))
4792 SET_PROPERTY(i, EP_WALL, TRUE);
4794 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4795 if (engine_version < VERSION_IDENT(2,2,0,0))
4796 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4798 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4800 !IS_COLLECTIBLE(i)));
4802 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4803 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4804 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4806 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4807 IS_INDESTRUCTIBLE(i)));
4809 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4811 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4812 else if (engine_version < VERSION_IDENT(2,2,0,0))
4813 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4815 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4819 if (IS_CUSTOM_ELEMENT(i))
4821 /* these are additional properties which are initially false when set */
4823 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4825 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4826 if (DONT_COLLIDE_WITH(i))
4827 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4829 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4830 if (CAN_SMASH_EVERYTHING(i))
4831 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4832 if (CAN_SMASH_ENEMIES(i))
4833 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4836 /* ---------- CAN_SMASH ------------------------------------------------ */
4837 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4838 CAN_SMASH_ENEMIES(i) ||
4839 CAN_SMASH_EVERYTHING(i)));
4841 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4842 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4843 EXPLODES_BY_FIRE(i)));
4845 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4846 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4847 EXPLODES_SMASHED(i)));
4849 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4850 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4851 EXPLODES_IMPACT(i)));
4853 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4854 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4856 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4857 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4858 i == EL_BLACK_ORB));
4860 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4861 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4863 IS_CUSTOM_ELEMENT(i)));
4865 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4866 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4867 i == EL_SP_ELECTRON));
4869 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4870 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4871 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4872 getMoveIntoAcidProperty(&level, i));
4874 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4875 if (MAYBE_DONT_COLLIDE_WITH(i))
4876 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4877 getDontCollideWithProperty(&level, i));
4879 /* ---------- SP_PORT -------------------------------------------------- */
4880 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4881 IS_PASSABLE_INSIDE(i)));
4883 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4884 for (j = 0; j < level.num_android_clone_elements; j++)
4885 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4887 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4889 /* ---------- CAN_CHANGE ----------------------------------------------- */
4890 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4891 for (j = 0; j < element_info[i].num_change_pages; j++)
4892 if (element_info[i].change_page[j].can_change)
4893 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4895 /* ---------- HAS_ACTION ----------------------------------------------- */
4896 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4897 for (j = 0; j < element_info[i].num_change_pages; j++)
4898 if (element_info[i].change_page[j].has_action)
4899 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4901 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4902 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4905 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4907 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4908 element_info[i].crumbled[ACTION_DEFAULT] !=
4909 element_info[i].graphic[ACTION_DEFAULT]);
4911 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
4912 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4913 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
4916 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4917 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4918 IS_EDITOR_CASCADE_INACTIVE(i)));
4921 /* dynamically adjust element properties according to game engine version */
4923 static int ep_em_slippery_wall[] =
4928 EL_EXPANDABLE_WALL_HORIZONTAL,
4929 EL_EXPANDABLE_WALL_VERTICAL,
4930 EL_EXPANDABLE_WALL_ANY,
4931 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4932 EL_EXPANDABLE_STEELWALL_VERTICAL,
4933 EL_EXPANDABLE_STEELWALL_ANY,
4934 EL_EXPANDABLE_STEELWALL_GROWING,
4938 static int ep_em_explodes_by_fire[] =
4941 EL_EM_DYNAMITE_ACTIVE,
4946 /* special EM style gems behaviour */
4947 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4948 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4949 level.em_slippery_gems);
4951 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4952 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4953 (level.em_slippery_gems &&
4954 engine_version > VERSION_IDENT(2,0,1,0)));
4956 /* special EM style explosion behaviour regarding chain reactions */
4957 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4958 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4959 level.em_explodes_by_fire);
4962 /* this is needed because some graphics depend on element properties */
4963 if (game_status == GAME_MODE_PLAYING)
4964 InitElementGraphicInfo();
4967 void InitElementPropertiesAfterLoading(int engine_version)
4971 /* set some other uninitialized values of custom elements in older levels */
4972 if (engine_version < VERSION_IDENT(3,1,0,0))
4974 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4976 int element = EL_CUSTOM_START + i;
4978 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4980 element_info[element].explosion_delay = 17;
4981 element_info[element].ignition_delay = 8;
4986 void InitElementPropertiesGfxElement()
4990 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4992 struct ElementInfo *ei = &element_info[i];
4994 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4998 static void InitGlobal()
5003 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
5005 /* check if element_name_info entry defined for each element in "main.h" */
5006 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
5007 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
5009 element_info[i].token_name = element_name_info[i].token_name;
5010 element_info[i].class_name = element_name_info[i].class_name;
5011 element_info[i].editor_description= element_name_info[i].editor_description;
5014 printf("%04d: %s\n", i, element_name_info[i].token_name);
5018 /* create hash from image config list */
5019 image_config_hash = newSetupFileHash();
5020 for (i = 0; image_config[i].token != NULL; i++)
5021 setHashEntry(image_config_hash,
5022 image_config[i].token,
5023 image_config[i].value);
5025 /* create hash from element token list */
5026 element_token_hash = newSetupFileHash();
5027 for (i = 0; element_name_info[i].token_name != NULL; i++)
5028 setHashEntry(element_token_hash,
5029 element_name_info[i].token_name,
5032 /* create hash from graphic token list */
5033 graphic_token_hash = newSetupFileHash();
5034 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
5035 if (strSuffix(image_config[i].value, ".pcx") ||
5036 strSuffix(image_config[i].value, ".wav") ||
5037 strEqual(image_config[i].value, UNDEFINED_FILENAME))
5038 setHashEntry(graphic_token_hash,
5039 image_config[i].token,
5040 int2str(graphic++, 0));
5042 /* create hash from font token list */
5043 font_token_hash = newSetupFileHash();
5044 for (i = 0; font_info[i].token_name != NULL; i++)
5045 setHashEntry(font_token_hash,
5046 font_info[i].token_name,
5049 /* always start with reliable default values (all elements) */
5050 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5051 ActiveElement[i] = i;
5053 /* now add all entries that have an active state (active elements) */
5054 for (i = 0; element_with_active_state[i].element != -1; i++)
5056 int element = element_with_active_state[i].element;
5057 int element_active = element_with_active_state[i].element_active;
5059 ActiveElement[element] = element_active;
5062 /* always start with reliable default values (all buttons) */
5063 for (i = 0; i < NUM_IMAGE_FILES; i++)
5064 ActiveButton[i] = i;
5066 /* now add all entries that have an active state (active buttons) */
5067 for (i = 0; button_with_active_state[i].button != -1; i++)
5069 int button = button_with_active_state[i].button;
5070 int button_active = button_with_active_state[i].button_active;
5072 ActiveButton[button] = button_active;
5075 /* always start with reliable default values (all fonts) */
5076 for (i = 0; i < NUM_FONTS; i++)
5079 /* now add all entries that have an active state (active fonts) */
5080 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
5082 int font = font_with_active_state[i].font_nr;
5083 int font_active = font_with_active_state[i].font_nr_active;
5085 ActiveFont[font] = font_active;
5088 global.autoplay_leveldir = NULL;
5089 global.convert_leveldir = NULL;
5090 global.create_images_dir = NULL;
5092 global.frames_per_second = 0;
5093 global.fps_slowdown = FALSE;
5094 global.fps_slowdown_factor = 1;
5096 global.border_status = GAME_MODE_MAIN;
5098 global.fading_status = GAME_MODE_MAIN;
5099 global.fading_type = TYPE_ENTER_MENU;
5103 void Execute_Command(char *command)
5107 if (strEqual(command, "print graphicsinfo.conf"))
5109 printf("# You can configure additional/alternative image files here.\n");
5110 printf("# (The entries below are default and therefore commented out.)\n");
5112 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
5114 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5117 for (i = 0; image_config[i].token != NULL; i++)
5118 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
5119 image_config[i].value));
5123 else if (strEqual(command, "print soundsinfo.conf"))
5125 printf("# You can configure additional/alternative sound files here.\n");
5126 printf("# (The entries below are default and therefore commented out.)\n");
5128 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
5130 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5133 for (i = 0; sound_config[i].token != NULL; i++)
5134 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
5135 sound_config[i].value));
5139 else if (strEqual(command, "print musicinfo.conf"))
5141 printf("# You can configure additional/alternative music files here.\n");
5142 printf("# (The entries below are default and therefore commented out.)\n");
5144 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
5146 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5149 for (i = 0; music_config[i].token != NULL; i++)
5150 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
5151 music_config[i].value));
5155 else if (strEqual(command, "print editorsetup.conf"))
5157 printf("# You can configure your personal editor element list here.\n");
5158 printf("# (The entries below are default and therefore commented out.)\n");
5161 /* this is needed to be able to check element list for cascade elements */
5162 InitElementPropertiesStatic();
5163 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5165 PrintEditorElementList();
5169 else if (strEqual(command, "print helpanim.conf"))
5171 printf("# You can configure different element help animations here.\n");
5172 printf("# (The entries below are default and therefore commented out.)\n");
5175 for (i = 0; helpanim_config[i].token != NULL; i++)
5177 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
5178 helpanim_config[i].value));
5180 if (strEqual(helpanim_config[i].token, "end"))
5186 else if (strEqual(command, "print helptext.conf"))
5188 printf("# You can configure different element help text here.\n");
5189 printf("# (The entries below are default and therefore commented out.)\n");
5192 for (i = 0; helptext_config[i].token != NULL; i++)
5193 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
5194 helptext_config[i].value));
5198 else if (strPrefix(command, "dump level "))
5200 char *filename = &command[11];
5202 if (!fileExists(filename))
5203 Error(ERR_EXIT, "cannot open file '%s'", filename);
5205 LoadLevelFromFilename(&level, filename);
5210 else if (strPrefix(command, "dump tape "))
5212 char *filename = &command[10];
5214 if (!fileExists(filename))
5215 Error(ERR_EXIT, "cannot open file '%s'", filename);
5217 LoadTapeFromFilename(filename);
5222 else if (strPrefix(command, "autoplay "))
5224 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
5226 while (*str_ptr != '\0') /* continue parsing string */
5228 /* cut leading whitespace from string, replace it by string terminator */
5229 while (*str_ptr == ' ' || *str_ptr == '\t')
5232 if (*str_ptr == '\0') /* end of string reached */
5235 if (global.autoplay_leveldir == NULL) /* read level set string */
5237 global.autoplay_leveldir = str_ptr;
5238 global.autoplay_all = TRUE; /* default: play all tapes */
5240 for (i = 0; i < MAX_TAPES_PER_SET; i++)
5241 global.autoplay_level[i] = FALSE;
5243 else /* read level number string */
5245 int level_nr = atoi(str_ptr); /* get level_nr value */
5247 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5248 global.autoplay_level[level_nr] = TRUE;
5250 global.autoplay_all = FALSE;
5253 /* advance string pointer to the next whitespace (or end of string) */
5254 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5258 else if (strPrefix(command, "convert "))
5260 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
5261 char *str_ptr = strchr(str_copy, ' ');
5263 global.convert_leveldir = str_copy;
5264 global.convert_level_nr = -1;
5266 if (str_ptr != NULL) /* level number follows */
5268 *str_ptr++ = '\0'; /* terminate leveldir string */
5269 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
5272 else if (strPrefix(command, "create images "))
5274 #if defined(TARGET_SDL)
5275 global.create_images_dir = getStringCopy(&command[14]);
5277 if (access(global.create_images_dir, W_OK) != 0)
5278 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
5279 global.create_images_dir);
5281 Error(ERR_EXIT, "command only available for SDL target");
5286 #if defined(TARGET_SDL)
5287 else if (strEqual(command, "SDL_ListModes"))
5292 SDL_Init(SDL_INIT_VIDEO);
5294 /* get available fullscreen/hardware modes */
5295 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
5297 /* check if there are any modes available */
5300 printf("No modes available!\n");
5305 /* check if our resolution is restricted */
5306 if (modes == (SDL_Rect **)-1)
5308 printf("All resolutions available.\n");
5312 printf("Available Modes:\n");
5314 for(i = 0; modes[i]; i++)
5315 printf(" %d x %d\n", modes[i]->w, modes[i]->h);
5325 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
5329 static void InitSetup()
5331 LoadSetup(); /* global setup info */
5333 /* set some options from setup file */
5335 if (setup.options.verbose)
5336 options.verbose = TRUE;
5339 static void InitGameInfo()
5341 game.restart_level = FALSE;
5344 static void InitPlayerInfo()
5348 /* choose default local player */
5349 local_player = &stored_player[0];
5351 for (i = 0; i < MAX_PLAYERS; i++)
5352 stored_player[i].connected = FALSE;
5354 local_player->connected = TRUE;
5357 static void InitArtworkInfo()
5362 static char *get_string_in_brackets(char *string)
5364 char *string_in_brackets = checked_malloc(strlen(string) + 3);
5366 sprintf(string_in_brackets, "[%s]", string);
5368 return string_in_brackets;
5371 static char *get_level_id_suffix(int id_nr)
5373 char *id_suffix = checked_malloc(1 + 3 + 1);
5375 if (id_nr < 0 || id_nr > 999)
5378 sprintf(id_suffix, ".%03d", id_nr);
5384 static char *get_element_class_token(int element)
5386 char *element_class_name = element_info[element].class_name;
5387 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
5389 sprintf(element_class_token, "[%s]", element_class_name);
5391 return element_class_token;
5394 static char *get_action_class_token(int action)
5396 char *action_class_name = &element_action_info[action].suffix[1];
5397 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
5399 sprintf(action_class_token, "[%s]", action_class_name);
5401 return action_class_token;
5405 static void InitArtworkConfig()
5407 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
5408 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
5409 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
5410 static char *action_id_suffix[NUM_ACTIONS + 1];
5411 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5412 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5413 static char *level_id_suffix[MAX_LEVELS + 1];
5414 static char *dummy[1] = { NULL };
5415 static char *ignore_generic_tokens[] =
5421 static char **ignore_image_tokens;
5422 static char **ignore_sound_tokens;
5423 static char **ignore_music_tokens;
5424 int num_ignore_generic_tokens;
5425 int num_ignore_image_tokens;
5426 int num_ignore_sound_tokens;
5427 int num_ignore_music_tokens;
5430 /* dynamically determine list of generic tokens to be ignored */
5431 num_ignore_generic_tokens = 0;
5432 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5433 num_ignore_generic_tokens++;
5435 /* dynamically determine list of image tokens to be ignored */
5436 num_ignore_image_tokens = num_ignore_generic_tokens;
5437 for (i = 0; image_config_vars[i].token != NULL; i++)
5438 num_ignore_image_tokens++;
5439 ignore_image_tokens =
5440 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5441 for (i = 0; i < num_ignore_generic_tokens; i++)
5442 ignore_image_tokens[i] = ignore_generic_tokens[i];
5443 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5444 ignore_image_tokens[num_ignore_generic_tokens + i] =
5445 image_config_vars[i].token;
5446 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5448 /* dynamically determine list of sound tokens to be ignored */
5449 num_ignore_sound_tokens = num_ignore_generic_tokens;
5450 ignore_sound_tokens =
5451 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5452 for (i = 0; i < num_ignore_generic_tokens; i++)
5453 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5454 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5456 /* dynamically determine list of music tokens to be ignored */
5457 num_ignore_music_tokens = num_ignore_generic_tokens;
5458 ignore_music_tokens =
5459 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5460 for (i = 0; i < num_ignore_generic_tokens; i++)
5461 ignore_music_tokens[i] = ignore_generic_tokens[i];
5462 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5464 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5465 image_id_prefix[i] = element_info[i].token_name;
5466 for (i = 0; i < NUM_FONTS; i++)
5467 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5468 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
5470 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5471 sound_id_prefix[i] = element_info[i].token_name;
5472 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5473 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5474 get_string_in_brackets(element_info[i].class_name);
5475 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
5477 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5478 music_id_prefix[i] = music_prefix_info[i].prefix;
5479 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
5481 for (i = 0; i < NUM_ACTIONS; i++)
5482 action_id_suffix[i] = element_action_info[i].suffix;
5483 action_id_suffix[NUM_ACTIONS] = NULL;
5485 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5486 direction_id_suffix[i] = element_direction_info[i].suffix;
5487 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5489 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5490 special_id_suffix[i] = special_suffix_info[i].suffix;
5491 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5493 for (i = 0; i < MAX_LEVELS; i++)
5494 level_id_suffix[i] = get_level_id_suffix(i);
5495 level_id_suffix[MAX_LEVELS] = NULL;
5497 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5498 image_id_prefix, action_id_suffix, direction_id_suffix,
5499 special_id_suffix, ignore_image_tokens);
5500 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5501 sound_id_prefix, action_id_suffix, dummy,
5502 special_id_suffix, ignore_sound_tokens);
5503 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5504 music_id_prefix, special_id_suffix, level_id_suffix,
5505 dummy, ignore_music_tokens);
5508 static void InitMixer()
5515 void InitGfxBuffers()
5517 ReCreateBitmap(&bitmap_db_store, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5518 ReCreateBitmap(&bitmap_db_cross, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5519 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE, DEFAULT_DEPTH);
5520 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE, DEFAULT_DEPTH);
5521 ReCreateBitmap(&bitmap_db_door, 3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
5522 ReCreateBitmap(&bitmap_db_toons, FULL_SXSIZE, FULL_SYSIZE, DEFAULT_DEPTH);
5524 /* initialize screen properties */
5525 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5526 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5528 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5529 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5530 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5531 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5532 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5534 InitGfxBuffers_SP();
5539 struct GraphicInfo *graphic_info_last = graphic_info;
5540 char *filename_font_initial = NULL;
5541 char *filename_anim_initial = NULL;
5542 Bitmap *bitmap_font_initial = NULL;
5546 /* determine settings for initial font (for displaying startup messages) */
5547 for (i = 0; image_config[i].token != NULL; i++)
5549 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5551 char font_token[128];
5554 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5555 len_font_token = strlen(font_token);
5557 if (strEqual(image_config[i].token, font_token))
5558 filename_font_initial = image_config[i].value;
5559 else if (strlen(image_config[i].token) > len_font_token &&
5560 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5562 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5563 font_initial[j].src_x = atoi(image_config[i].value);
5564 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5565 font_initial[j].src_y = atoi(image_config[i].value);
5566 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5567 font_initial[j].width = atoi(image_config[i].value);
5568 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5569 font_initial[j].height = atoi(image_config[i].value);
5574 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5576 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5577 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5580 if (filename_font_initial == NULL) /* should not happen */
5581 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5586 /* create additional image buffers for double-buffering and cross-fading */
5587 bitmap_db_store = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5588 bitmap_db_cross = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5589 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
5590 bitmap_db_panel = CreateBitmap(DXSIZE, DYSIZE, DEFAULT_DEPTH);
5591 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
5592 bitmap_db_toons = CreateBitmap(FULL_SXSIZE, FULL_SYSIZE, DEFAULT_DEPTH);
5594 /* initialize screen properties */
5595 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5596 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5598 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5599 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5600 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5601 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5604 InitGfxCustomArtworkInfo();
5606 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5608 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5609 font_initial[j].bitmap = bitmap_font_initial;
5611 InitFontGraphicInfo();
5613 font_height = getFontHeight(FC_RED);
5616 DrawInitText(getWindowTitleString(), 20, FC_YELLOW);
5618 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
5620 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
5621 DrawInitText(PROGRAM_WEBSITE_STRING, WIN_YSIZE - 20 - font_height, FC_RED);
5623 DrawInitText("Loading graphics", 120, FC_GREEN);
5627 /* initialize busy animation with default values */
5628 int parameter[NUM_GFX_ARGS];
5629 for (i = 0; i < NUM_GFX_ARGS; i++)
5630 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5631 image_config_suffix[i].token,
5632 image_config_suffix[i].type);
5634 for (i = 0; i < NUM_GFX_ARGS; i++)
5635 printf("::: '%s' => %d\n", image_config_suffix[i].token, parameter[i]);
5639 /* determine settings for busy animation (when displaying startup messages) */
5640 for (i = 0; image_config[i].token != NULL; i++)
5642 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5643 int len_anim_token = strlen(anim_token);
5645 if (strEqual(image_config[i].token, anim_token))
5646 filename_anim_initial = image_config[i].value;
5647 else if (strlen(image_config[i].token) > len_anim_token &&
5648 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5651 for (j = 0; image_config_suffix[j].token != NULL; j++)
5653 if (strEqual(&image_config[i].token[len_anim_token],
5654 image_config_suffix[j].token))
5656 get_graphic_parameter_value(image_config[i].value,
5657 image_config_suffix[j].token,
5658 image_config_suffix[j].type);
5661 if (strEqual(&image_config[i].token[len_anim_token], ".x"))
5662 anim_initial.src_x = atoi(image_config[i].value);
5663 else if (strEqual(&image_config[i].token[len_anim_token], ".y"))
5664 anim_initial.src_y = atoi(image_config[i].value);
5665 else if (strEqual(&image_config[i].token[len_anim_token], ".width"))
5666 anim_initial.width = atoi(image_config[i].value);
5667 else if (strEqual(&image_config[i].token[len_anim_token], ".height"))
5668 anim_initial.height = atoi(image_config[i].value);
5669 else if (strEqual(&image_config[i].token[len_anim_token], ".frames"))
5670 anim_initial.anim_frames = atoi(image_config[i].value);
5671 else if (strEqual(&image_config[i].token[len_anim_token],
5672 ".frames_per_line"))
5673 anim_initial.anim_frames_per_line = atoi(image_config[i].value);
5674 else if (strEqual(&image_config[i].token[len_anim_token], ".delay"))
5675 anim_initial.anim_delay = atoi(image_config[i].value);
5680 #if defined(CREATE_SPECIAL_EDITION_RND_JUE)
5681 filename_anim_initial = "loading.pcx";
5683 parameter[GFX_ARG_X] = 0;
5684 parameter[GFX_ARG_Y] = 0;
5685 parameter[GFX_ARG_WIDTH] = 128;
5686 parameter[GFX_ARG_HEIGHT] = 40;
5687 parameter[GFX_ARG_FRAMES] = 32;
5688 parameter[GFX_ARG_DELAY] = 4;
5689 parameter[GFX_ARG_FRAMES_PER_LINE] = ARG_UNDEFINED_VALUE;
5692 if (filename_anim_initial == NULL) /* should not happen */
5693 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5695 anim_initial.bitmap = LoadCustomImage(filename_anim_initial);
5697 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
5699 set_graphic_parameters_ext(0, parameter, anim_initial.bitmap);
5702 printf("::: INIT_GFX: anim_frames_per_line == %d [%d / %d] [%d, %d]\n",
5703 graphic_info[0].anim_frames_per_line,
5704 get_scaled_graphic_width(0),
5705 graphic_info[0].width,
5706 getOriginalImageWidthFromImageID(0),
5707 graphic_info[0].scale_up_factor);
5710 graphic_info = graphic_info_last;
5712 init.busy.width = anim_initial.width;
5713 init.busy.height = anim_initial.height;
5715 InitMenuDesignSettings_Static();
5716 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5718 /* use copy of busy animation to prevent change while reloading artwork */
5723 void RedrawBackground()
5725 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
5726 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
5728 redraw_mask = REDRAW_ALL;
5731 void InitGfxBackground()
5735 fieldbuffer = bitmap_db_field;
5736 SetDrawtoField(DRAW_BACKBUFFER);
5739 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5743 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
5744 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
5747 for (x = 0; x < MAX_BUF_XSIZE; x++)
5748 for (y = 0; y < MAX_BUF_YSIZE; y++)
5751 redraw_mask = REDRAW_ALL;
5754 static void InitLevelInfo()
5756 LoadLevelInfo(); /* global level info */
5757 LoadLevelSetup_LastSeries(); /* last played series info */
5758 LoadLevelSetup_SeriesInfo(); /* last played level info */
5761 static void InitLevelArtworkInfo()
5763 LoadLevelArtworkInfo();
5766 static void InitImages()
5768 print_timestamp_init("InitImages");
5771 printf("::: leveldir_current->identifier == '%s'\n",
5772 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5773 printf("::: leveldir_current->graphics_path == '%s'\n",
5774 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5775 printf("::: leveldir_current->graphics_set == '%s'\n",
5776 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5777 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5778 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5781 setLevelArtworkDir(artwork.gfx_first);
5784 printf("::: leveldir_current->identifier == '%s'\n",
5785 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5786 printf("::: leveldir_current->graphics_path == '%s'\n",
5787 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5788 printf("::: leveldir_current->graphics_set == '%s'\n",
5789 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5790 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5791 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5795 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5796 leveldir_current->identifier,
5797 artwork.gfx_current_identifier,
5798 artwork.gfx_current->identifier,
5799 leveldir_current->graphics_set,
5800 leveldir_current->graphics_path);
5803 UPDATE_BUSY_STATE();
5805 ReloadCustomImages();
5806 print_timestamp_time("ReloadCustomImages");
5808 UPDATE_BUSY_STATE();
5810 LoadCustomElementDescriptions();
5811 print_timestamp_time("LoadCustomElementDescriptions");
5813 UPDATE_BUSY_STATE();
5815 LoadMenuDesignSettings();
5816 print_timestamp_time("LoadMenuDesignSettings");
5818 UPDATE_BUSY_STATE();
5820 ReinitializeGraphics();
5821 print_timestamp_time("ReinitializeGraphics");
5823 UPDATE_BUSY_STATE();
5825 print_timestamp_done("InitImages");
5828 static void InitSound(char *identifier)
5830 print_timestamp_init("InitSound");
5832 if (identifier == NULL)
5833 identifier = artwork.snd_current->identifier;
5835 /* set artwork path to send it to the sound server process */
5836 setLevelArtworkDir(artwork.snd_first);
5838 InitReloadCustomSounds(identifier);
5839 print_timestamp_time("InitReloadCustomSounds");
5841 ReinitializeSounds();
5842 print_timestamp_time("ReinitializeSounds");
5844 print_timestamp_done("InitSound");
5847 static void InitMusic(char *identifier)
5849 print_timestamp_init("InitMusic");
5851 if (identifier == NULL)
5852 identifier = artwork.mus_current->identifier;
5854 /* set artwork path to send it to the sound server process */
5855 setLevelArtworkDir(artwork.mus_first);
5857 InitReloadCustomMusic(identifier);
5858 print_timestamp_time("InitReloadCustomMusic");
5860 ReinitializeMusic();
5861 print_timestamp_time("ReinitializeMusic");
5863 print_timestamp_done("InitMusic");
5866 void InitNetworkServer()
5868 #if defined(NETWORK_AVALIABLE)
5872 if (!options.network)
5875 #if defined(NETWORK_AVALIABLE)
5876 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5878 if (!ConnectToServer(options.server_host, options.server_port))
5879 Error(ERR_EXIT, "cannot connect to network game server");
5881 SendToServer_PlayerName(setup.player_name);
5882 SendToServer_ProtocolVersion();
5885 SendToServer_NrWanted(nr_wanted);
5889 static boolean CheckArtworkConfigForCustomElements(char *filename)
5891 SetupFileHash *setup_file_hash;
5892 boolean redefined_ce_found = FALSE;
5894 /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */
5896 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5898 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5900 char *token = HASH_ITERATION_TOKEN(itr);
5902 if (strPrefix(token, "custom_"))
5904 redefined_ce_found = TRUE;
5909 END_HASH_ITERATION(setup_file_hash, itr)
5911 freeSetupFileHash(setup_file_hash);
5914 return redefined_ce_found;
5917 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5919 char *filename_base, *filename_local;
5920 boolean redefined_ce_found = FALSE;
5922 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5925 printf("::: leveldir_current->identifier == '%s'\n",
5926 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5927 printf("::: leveldir_current->graphics_path == '%s'\n",
5928 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5929 printf("::: leveldir_current->graphics_set == '%s'\n",
5930 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5931 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5932 leveldir_current == NULL ? "[NULL]" :
5933 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5936 /* first look for special artwork configured in level series config */
5937 filename_base = getCustomArtworkLevelConfigFilename(type);
5940 printf("::: filename_base == '%s'\n", filename_base);
5943 if (fileExists(filename_base))
5944 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5946 filename_local = getCustomArtworkConfigFilename(type);
5949 printf("::: filename_local == '%s'\n", filename_local);
5952 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5953 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5956 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5959 return redefined_ce_found;
5962 static void InitOverrideArtwork()
5964 boolean redefined_ce_found = FALSE;
5966 /* to check if this level set redefines any CEs, do not use overriding */
5967 gfx.override_level_graphics = FALSE;
5968 gfx.override_level_sounds = FALSE;
5969 gfx.override_level_music = FALSE;
5971 /* now check if this level set has definitions for custom elements */
5972 if (setup.override_level_graphics == AUTO ||
5973 setup.override_level_sounds == AUTO ||
5974 setup.override_level_music == AUTO)
5975 redefined_ce_found =
5976 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5977 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5978 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5981 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5984 if (redefined_ce_found)
5986 /* this level set has CE definitions: change "AUTO" to "FALSE" */
5987 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5988 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
5989 gfx.override_level_music = (setup.override_level_music == TRUE);
5993 /* this level set has no CE definitions: change "AUTO" to "TRUE" */
5994 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5995 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
5996 gfx.override_level_music = (setup.override_level_music != FALSE);
6000 printf("::: => %d, %d, %d\n",
6001 gfx.override_level_graphics,
6002 gfx.override_level_sounds,
6003 gfx.override_level_music);
6007 static char *getNewArtworkIdentifier(int type)
6009 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
6010 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
6011 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
6012 static boolean initialized[3] = { FALSE, FALSE, FALSE };
6013 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
6015 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
6017 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
6019 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
6020 char *leveldir_identifier = leveldir_current->identifier;
6022 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
6023 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
6025 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
6027 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
6028 char *artwork_current_identifier;
6029 char *artwork_new_identifier = NULL; /* default: nothing has changed */
6031 /* leveldir_current may be invalid (level group, parent link) */
6032 if (!validLevelSeries(leveldir_current))
6035 /* 1st step: determine artwork set to be activated in descending order:
6036 --------------------------------------------------------------------
6037 1. setup artwork (when configured to override everything else)
6038 2. artwork set configured in "levelinfo.conf" of current level set
6039 (artwork in level directory will have priority when loading later)
6040 3. artwork in level directory (stored in artwork sub-directory)
6041 4. setup artwork (currently configured in setup menu) */
6043 if (setup_override_artwork)
6044 artwork_current_identifier = setup_artwork_set;
6045 else if (leveldir_artwork_set != NULL)
6046 artwork_current_identifier = leveldir_artwork_set;
6047 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
6048 artwork_current_identifier = leveldir_identifier;
6050 artwork_current_identifier = setup_artwork_set;
6053 /* 2nd step: check if it is really needed to reload artwork set
6054 ------------------------------------------------------------ */
6057 if (type == ARTWORK_TYPE_GRAPHICS)
6058 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
6059 artwork_new_identifier,
6060 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
6061 artwork_current_identifier,
6062 leveldir_current->graphics_set,
6063 leveldir_current->identifier);
6066 /* ---------- reload if level set and also artwork set has changed ------- */
6067 if (leveldir_current_identifier[type] != leveldir_identifier &&
6068 (last_has_level_artwork_set[type] || has_level_artwork_set))
6069 artwork_new_identifier = artwork_current_identifier;
6071 leveldir_current_identifier[type] = leveldir_identifier;
6072 last_has_level_artwork_set[type] = has_level_artwork_set;
6075 if (type == ARTWORK_TYPE_GRAPHICS)
6076 printf("::: 1: '%s'\n", artwork_new_identifier);
6079 /* ---------- reload if "override artwork" setting has changed ----------- */
6080 if (last_override_level_artwork[type] != setup_override_artwork)
6081 artwork_new_identifier = artwork_current_identifier;
6083 last_override_level_artwork[type] = setup_override_artwork;
6086 if (type == ARTWORK_TYPE_GRAPHICS)
6087 printf("::: 2: '%s'\n", artwork_new_identifier);
6090 /* ---------- reload if current artwork identifier has changed ----------- */
6091 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
6092 artwork_current_identifier))
6093 artwork_new_identifier = artwork_current_identifier;
6095 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
6098 if (type == ARTWORK_TYPE_GRAPHICS)
6099 printf("::: 3: '%s'\n", artwork_new_identifier);
6102 /* ---------- do not reload directly after starting ---------------------- */
6103 if (!initialized[type])
6104 artwork_new_identifier = NULL;
6106 initialized[type] = TRUE;
6109 if (type == ARTWORK_TYPE_GRAPHICS)
6110 printf("::: 4: '%s'\n", artwork_new_identifier);
6114 if (type == ARTWORK_TYPE_GRAPHICS)
6115 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
6116 artwork.gfx_current_identifier, artwork_current_identifier,
6117 artwork.gfx_current->identifier, leveldir_current->graphics_set,
6118 artwork_new_identifier);
6121 return artwork_new_identifier;
6124 void ReloadCustomArtwork(int force_reload)
6126 int last_game_status = game_status; /* save current game status */
6127 char *gfx_new_identifier;
6128 char *snd_new_identifier;
6129 char *mus_new_identifier;
6130 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
6131 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
6132 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
6133 boolean reload_needed;
6135 InitOverrideArtwork();
6137 force_reload_gfx |= AdjustGraphicsForEMC();
6139 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
6140 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
6141 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
6143 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
6144 snd_new_identifier != NULL || force_reload_snd ||
6145 mus_new_identifier != NULL || force_reload_mus);
6150 print_timestamp_init("ReloadCustomArtwork");
6152 game_status = GAME_MODE_LOADING;
6154 FadeOut(REDRAW_ALL);
6157 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6159 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
6161 print_timestamp_time("ClearRectangle");
6164 printf("::: fading in ... %d\n", fading.fade_mode);
6168 printf("::: done\n");
6171 if (gfx_new_identifier != NULL || force_reload_gfx)
6174 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
6175 artwork.gfx_current_identifier,
6177 artwork.gfx_current->identifier,
6178 leveldir_current->graphics_set);
6182 print_timestamp_time("InitImages");
6185 if (snd_new_identifier != NULL || force_reload_snd)
6187 InitSound(snd_new_identifier);
6188 print_timestamp_time("InitSound");
6191 if (mus_new_identifier != NULL || force_reload_mus)
6193 InitMusic(mus_new_identifier);
6194 print_timestamp_time("InitMusic");
6197 game_status = last_game_status; /* restore current game status */
6199 init_last = init; /* switch to new busy animation */
6202 printf("::: ----------------DELAY 1 ...\n");
6207 printf("::: FadeOut @ ReloadCustomArtwork ...\n");
6209 FadeOut(REDRAW_ALL);
6211 printf("::: FadeOut @ ReloadCustomArtwork done\n");
6216 /* force redraw of (open or closed) door graphics */
6217 SetDoorState(DOOR_OPEN_ALL);
6218 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
6223 FadeSetEnterScreen();
6224 FadeSkipNextFadeOut();
6225 // FadeSetDisabled();
6230 fading = fading_none;
6235 redraw_mask = REDRAW_ALL;
6238 print_timestamp_done("ReloadCustomArtwork");
6241 void KeyboardAutoRepeatOffUnlessAutoplay()
6243 if (global.autoplay_leveldir == NULL)
6244 KeyboardAutoRepeatOff();
6248 /* ========================================================================= */
6250 /* ========================================================================= */
6254 print_timestamp_init("OpenAll");
6256 game_status = GAME_MODE_LOADING;
6262 InitGlobal(); /* initialize some global variables */
6264 print_timestamp_time("[init global stuff]");
6266 if (options.execute_command)
6267 Execute_Command(options.execute_command);
6269 if (options.serveronly)
6271 #if defined(PLATFORM_UNIX)
6272 NetworkServer(options.server_port, options.serveronly);
6274 Error(ERR_WARN, "networking only supported in Unix version");
6277 exit(0); /* never reached, server loops forever */
6284 InitArtworkInfo(); /* needed before loading gfx, sound & music */
6285 InitArtworkConfig(); /* needed before forking sound child process */
6292 InitRND(NEW_RANDOMIZE);
6293 InitSimpleRandom(NEW_RANDOMIZE);
6297 print_timestamp_time("[init setup/config stuff]");
6300 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
6302 InitEventFilter(FilterMouseMotionEvents);
6304 print_timestamp_time("[init video stuff]");
6306 InitElementPropertiesStatic();
6307 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
6308 InitElementPropertiesGfxElement();
6310 print_timestamp_time("[init element properties stuff]");
6314 print_timestamp_time("InitGfx");
6317 print_timestamp_time("InitLevelInfo");
6319 InitLevelArtworkInfo();
6320 print_timestamp_time("InitLevelArtworkInfo");
6322 InitOverrideArtwork(); /* needs to know current level directory */
6323 print_timestamp_time("InitOverrideArtwork");
6325 InitImages(); /* needs to know current level directory */
6326 print_timestamp_time("InitImages");
6328 InitSound(NULL); /* needs to know current level directory */
6329 print_timestamp_time("InitSound");
6331 InitMusic(NULL); /* needs to know current level directory */
6332 print_timestamp_time("InitMusic");
6334 InitGfxBackground();
6344 if (global.autoplay_leveldir)
6349 else if (global.convert_leveldir)
6354 else if (global.create_images_dir)
6356 CreateLevelSketchImages();
6360 game_status = GAME_MODE_MAIN;
6363 FadeSetEnterScreen();
6364 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
6365 FadeSkipNextFadeOut();
6366 // FadeSetDisabled();
6368 fading = fading_none;
6371 print_timestamp_time("[post-artwork]");
6373 print_timestamp_done("OpenAll");
6377 InitNetworkServer();
6380 void CloseAllAndExit(int exit_value)
6385 CloseAudio(); /* called after freeing sounds (needed for SDL) */
6397 #if defined(TARGET_SDL)
6398 if (network_server) /* terminate network server */
6399 SDL_KillThread(server_thread);
6402 CloseVideoDisplay();
6403 ClosePlatformDependentStuff();
6405 if (exit_value != 0)
6406 NotifyUserAboutErrorFile();