1 // ============================================================================
2 // Rocks'n'Diamonds - McDuffin Strikes Back!
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
7 // http://www.artsoft.org/
8 // ----------------------------------------------------------------------------
10 // ============================================================================
12 #include "libgame/libgame.h"
27 #include "conf_e2g.c" /* include auto-generated data structure definitions */
28 #include "conf_esg.c" /* include auto-generated data structure definitions */
29 #include "conf_e2s.c" /* include auto-generated data structure definitions */
30 #include "conf_fnt.c" /* include auto-generated data structure definitions */
31 #include "conf_g2s.c" /* include auto-generated data structure definitions */
32 #include "conf_g2m.c" /* include auto-generated data structure definitions */
33 #include "conf_act.c" /* include auto-generated data structure definitions */
36 #define CONFIG_TOKEN_FONT_INITIAL "font.initial"
37 #define CONFIG_TOKEN_GLOBAL_BUSY "global.busy"
40 static struct FontBitmapInfo font_initial[NUM_INITIAL_FONTS];
41 static struct GraphicInfo anim_initial;
43 static int copy_properties[][5] =
47 EL_BUG_LEFT, EL_BUG_RIGHT,
48 EL_BUG_UP, EL_BUG_DOWN
52 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
53 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
57 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
58 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
62 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
63 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
67 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
68 EL_PACMAN_UP, EL_PACMAN_DOWN
72 EL_YAMYAM_LEFT, EL_YAMYAM_RIGHT,
73 EL_YAMYAM_UP, EL_YAMYAM_DOWN
77 EL_MOLE_LEFT, EL_MOLE_RIGHT,
78 EL_MOLE_UP, EL_MOLE_DOWN
89 struct GraphicInfo *graphic_info_last = graphic_info;
91 static unsigned int action_delay = 0;
92 unsigned int action_delay_value = GameFrameDelay;
93 int sync_frame = FrameCounter;
96 if (game_status != GAME_MODE_LOADING)
99 if (anim_initial.bitmap == NULL || window == NULL)
102 if (!DelayReached(&action_delay, action_delay_value))
107 static unsigned int last_counter = -1;
108 unsigned int current_counter = Counter();
109 unsigned int delay = current_counter - last_counter;
111 if (last_counter != -1 && delay > action_delay_value + 5)
112 printf("::: DrawInitAnim: DELAY TOO LONG: %ld\n", delay);
114 last_counter = current_counter;
118 x = ALIGNED_TEXT_XPOS(&init_last.busy);
119 y = ALIGNED_TEXT_YPOS(&init_last.busy);
121 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
125 static boolean done = FALSE;
128 printf("::: %d, %d, %d, %d => %d, %d [%d, %d] [%d, %d]\n",
129 init.busy.x, init.busy.y,
130 init.busy.align, init.busy.valign,
132 graphic_info[graphic].width,
133 graphic_info[graphic].height,
134 sync_frame, anim_initial.anim_delay);
140 if (sync_frame % anim_initial.anim_delay == 0)
145 int width = graphic_info[graphic].width;
146 int height = graphic_info[graphic].height;
147 int frame = getGraphicAnimationFrame(graphic, sync_frame);
149 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
150 BlitBitmap(src_bitmap, window, src_x, src_y, width, height, x, y);
152 /* !!! this can only draw TILEX/TILEY size animations !!! */
153 DrawGraphicAnimationExt(window, x, y, graphic, sync_frame, NO_MASKING);
157 graphic_info = graphic_info_last;
164 FreeLevelEditorGadgets();
173 static boolean gadgets_initialized = FALSE;
175 if (gadgets_initialized)
178 CreateLevelEditorGadgets();
182 CreateScreenGadgets();
184 InitGadgetsSoundCallback(PlaySoundActivating, PlaySoundSelecting);
186 gadgets_initialized = TRUE;
189 inline void InitElementSmallImagesScaledUp(int graphic)
192 struct FileInfo *fi = getImageListEntryFromImageID(graphic);
194 printf("::: '%s' -> '%s'\n", fi->token, fi->filename);
197 CreateImageWithSmallImages(graphic, graphic_info[graphic].scale_up_factor,
198 graphic_info[graphic].tile_size);
201 void InitElementSmallImages()
203 print_timestamp_init("InitElementSmallImages");
205 static int special_graphics[] =
207 IMG_EDITOR_ELEMENT_BORDER,
208 IMG_EDITOR_ELEMENT_BORDER_INPUT,
209 IMG_EDITOR_CASCADE_LIST,
210 IMG_EDITOR_CASCADE_LIST_ACTIVE,
213 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
214 int num_property_mappings = getImageListPropertyMappingSize();
217 print_timestamp_time("getImageListPropertyMapping/Size");
219 print_timestamp_init("InitElementSmallImagesScaledUp (1)");
220 /* initialize normal images from static configuration */
221 for (i = 0; element_to_graphic[i].element > -1; i++)
222 InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
223 print_timestamp_done("InitElementSmallImagesScaledUp (1)");
225 /* initialize special images from static configuration */
226 for (i = 0; element_to_special_graphic[i].element > -1; i++)
227 InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
228 print_timestamp_time("InitElementSmallImagesScaledUp (2)");
230 /* initialize images from dynamic configuration (may be elements or other) */
231 for (i = 0; i < num_property_mappings; i++)
232 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
233 print_timestamp_time("InitElementSmallImagesScaledUp (3)");
235 /* initialize special images from above list (non-element images) */
236 for (i = 0; special_graphics[i] > -1; i++)
237 InitElementSmallImagesScaledUp(special_graphics[i]);
238 print_timestamp_time("InitElementSmallImagesScaledUp (4)");
240 print_timestamp_done("InitElementSmallImages");
243 void InitScaledImages()
247 /* scale normal images from static configuration, if not already scaled */
248 for (i = 0; i < NUM_IMAGE_FILES; i++)
249 ScaleImage(i, graphic_info[i].scale_up_factor);
253 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
254 void SetBitmaps_EM(Bitmap **em_bitmap)
256 em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
257 em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].bitmap;
262 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
263 void SetBitmaps_SP(Bitmap **sp_bitmap)
265 *sp_bitmap = graphic_info[IMG_SP_OBJECTS].bitmap;
269 static int getFontBitmapID(int font_nr)
273 /* (special case: do not use special font for GAME_MODE_LOADING) */
274 if (game_status >= GAME_MODE_TITLE_INITIAL &&
275 game_status <= GAME_MODE_PSEUDO_PREVIEW)
276 special = game_status;
277 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
278 special = GFX_SPECIAL_ARG_MAIN;
280 else if (game_status == GAME_MODE_PLAYING)
281 special = GFX_SPECIAL_ARG_DOOR;
288 font_info[font_nr].token_name,
289 special_suffix_info[special].suffix);
294 return font_info[font_nr].special_bitmap_id[special];
299 static int getFontFromToken(char *token)
302 char *value = getHashEntry(font_token_hash, token);
309 /* !!! OPTIMIZE THIS BY USING HASH !!! */
310 for (i = 0; i < NUM_FONTS; i++)
311 if (strEqual(token, font_info[i].token_name))
315 /* if font not found, use reliable default value */
316 return FONT_INITIAL_1;
319 void InitFontGraphicInfo()
321 static struct FontBitmapInfo *font_bitmap_info = NULL;
322 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
323 int num_property_mappings = getImageListPropertyMappingSize();
324 int num_font_bitmaps = NUM_FONTS;
327 if (graphic_info == NULL) /* still at startup phase */
329 InitFontInfo(font_initial, NUM_INITIAL_FONTS,
330 getFontBitmapID, getFontFromToken);
335 /* ---------- initialize font graphic definitions ---------- */
337 /* always start with reliable default values (normal font graphics) */
338 for (i = 0; i < NUM_FONTS; i++)
339 font_info[i].graphic = IMG_FONT_INITIAL_1;
341 /* initialize normal font/graphic mapping from static configuration */
342 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
344 int font_nr = font_to_graphic[i].font_nr;
345 int special = font_to_graphic[i].special;
346 int graphic = font_to_graphic[i].graphic;
351 font_info[font_nr].graphic = graphic;
354 /* always start with reliable default values (special font graphics) */
355 for (i = 0; i < NUM_FONTS; i++)
357 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
359 font_info[i].special_graphic[j] = font_info[i].graphic;
360 font_info[i].special_bitmap_id[j] = i;
364 /* initialize special font/graphic mapping from static configuration */
365 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
367 int font_nr = font_to_graphic[i].font_nr;
368 int special = font_to_graphic[i].special;
369 int graphic = font_to_graphic[i].graphic;
370 int base_graphic = font2baseimg(font_nr);
372 if (IS_SPECIAL_GFX_ARG(special))
374 boolean base_redefined =
375 getImageListEntryFromImageID(base_graphic)->redefined;
376 boolean special_redefined =
377 getImageListEntryFromImageID(graphic)->redefined;
378 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
380 /* if the base font ("font.title_1", for example) has been redefined,
381 but not the special font ("font.title_1.LEVELS", for example), do not
382 use an existing (in this case considered obsolete) special font
383 anymore, but use the automatically determined default font */
384 /* special case: cloned special fonts must be explicitly redefined,
385 but are not automatically redefined by redefining base font */
386 if (base_redefined && !special_redefined && !special_cloned)
389 font_info[font_nr].special_graphic[special] = graphic;
390 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
395 /* initialize special font/graphic mapping from dynamic configuration */
396 for (i = 0; i < num_property_mappings; i++)
398 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
399 int special = property_mapping[i].ext3_index;
400 int graphic = property_mapping[i].artwork_index;
405 if (IS_SPECIAL_GFX_ARG(special))
407 font_info[font_nr].special_graphic[special] = graphic;
408 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
413 /* correct special font/graphic mapping for cloned fonts for downwards
414 compatibility of PREVIEW fonts -- this is only needed for implicit
415 redefinition of special font by redefined base font, and only if other
416 fonts are cloned from this special font (like in the "Zelda" level set) */
417 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
419 int font_nr = font_to_graphic[i].font_nr;
420 int special = font_to_graphic[i].special;
421 int graphic = font_to_graphic[i].graphic;
423 if (IS_SPECIAL_GFX_ARG(special))
425 boolean special_redefined =
426 getImageListEntryFromImageID(graphic)->redefined;
427 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
429 if (special_cloned && !special_redefined)
433 for (j = 0; font_to_graphic[j].font_nr > -1; j++)
435 int font_nr2 = font_to_graphic[j].font_nr;
436 int special2 = font_to_graphic[j].special;
437 int graphic2 = font_to_graphic[j].graphic;
439 if (IS_SPECIAL_GFX_ARG(special2) &&
440 graphic2 == graphic_info[graphic].clone_from)
442 font_info[font_nr].special_graphic[special] =
443 font_info[font_nr2].special_graphic[special2];
444 font_info[font_nr].special_bitmap_id[special] =
445 font_info[font_nr2].special_bitmap_id[special2];
452 /* reset non-redefined ".active" font graphics if normal font is redefined */
453 /* (this different treatment is needed because normal and active fonts are
454 independently defined ("active" is not a property of font definitions!) */
455 for (i = 0; i < NUM_FONTS; i++)
457 int font_nr_base = i;
458 int font_nr_active = FONT_ACTIVE(font_nr_base);
460 /* check only those fonts with exist as normal and ".active" variant */
461 if (font_nr_base != font_nr_active)
463 int base_graphic = font_info[font_nr_base].graphic;
464 int active_graphic = font_info[font_nr_active].graphic;
465 boolean base_redefined =
466 getImageListEntryFromImageID(base_graphic)->redefined;
467 boolean active_redefined =
468 getImageListEntryFromImageID(active_graphic)->redefined;
470 /* if the base font ("font.menu_1", for example) has been redefined,
471 but not the active font ("font.menu_1.active", for example), do not
472 use an existing (in this case considered obsolete) active font
473 anymore, but use the automatically determined default font */
474 if (base_redefined && !active_redefined)
475 font_info[font_nr_active].graphic = base_graphic;
477 /* now also check each "special" font (which may be the same as above) */
478 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
480 int base_graphic = font_info[font_nr_base].special_graphic[j];
481 int active_graphic = font_info[font_nr_active].special_graphic[j];
482 boolean base_redefined =
483 getImageListEntryFromImageID(base_graphic)->redefined;
484 boolean active_redefined =
485 getImageListEntryFromImageID(active_graphic)->redefined;
487 /* same as above, but check special graphic definitions, for example:
488 redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN" */
489 if (base_redefined && !active_redefined)
491 font_info[font_nr_active].special_graphic[j] =
492 font_info[font_nr_base].special_graphic[j];
493 font_info[font_nr_active].special_bitmap_id[j] =
494 font_info[font_nr_base].special_bitmap_id[j];
500 /* ---------- initialize font bitmap array ---------- */
502 if (font_bitmap_info != NULL)
503 FreeFontInfo(font_bitmap_info);
506 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
508 /* ---------- initialize font bitmap definitions ---------- */
510 for (i = 0; i < NUM_FONTS; i++)
512 if (i < NUM_INITIAL_FONTS)
514 font_bitmap_info[i] = font_initial[i];
518 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
520 int font_bitmap_id = font_info[i].special_bitmap_id[j];
521 int graphic = font_info[i].special_graphic[j];
523 /* set 'graphic_info' for font entries, if uninitialized (guessed) */
524 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
526 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
527 graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
530 /* copy font relevant information from graphics information */
531 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
532 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
533 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
534 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
535 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
537 font_bitmap_info[font_bitmap_id].draw_xoffset =
538 graphic_info[graphic].draw_xoffset;
539 font_bitmap_info[font_bitmap_id].draw_yoffset =
540 graphic_info[graphic].draw_yoffset;
542 font_bitmap_info[font_bitmap_id].num_chars =
543 graphic_info[graphic].anim_frames;
544 font_bitmap_info[font_bitmap_id].num_chars_per_line =
545 graphic_info[graphic].anim_frames_per_line;
549 InitFontInfo(font_bitmap_info, num_font_bitmaps,
550 getFontBitmapID, getFontFromToken);
553 void InitElementGraphicInfo()
555 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
556 int num_property_mappings = getImageListPropertyMappingSize();
559 if (graphic_info == NULL) /* still at startup phase */
562 /* set values to -1 to identify later as "uninitialized" values */
563 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
565 for (act = 0; act < NUM_ACTIONS; act++)
567 element_info[i].graphic[act] = -1;
568 element_info[i].crumbled[act] = -1;
570 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
572 element_info[i].direction_graphic[act][dir] = -1;
573 element_info[i].direction_crumbled[act][dir] = -1;
580 /* initialize normal element/graphic mapping from static configuration */
581 for (i = 0; element_to_graphic[i].element > -1; i++)
583 int element = element_to_graphic[i].element;
584 int action = element_to_graphic[i].action;
585 int direction = element_to_graphic[i].direction;
586 boolean crumbled = element_to_graphic[i].crumbled;
587 int graphic = element_to_graphic[i].graphic;
588 int base_graphic = el2baseimg(element);
590 if (graphic_info[graphic].bitmap == NULL)
593 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
596 boolean base_redefined =
597 getImageListEntryFromImageID(base_graphic)->redefined;
598 boolean act_dir_redefined =
599 getImageListEntryFromImageID(graphic)->redefined;
601 /* if the base graphic ("emerald", for example) has been redefined,
602 but not the action graphic ("emerald.falling", for example), do not
603 use an existing (in this case considered obsolete) action graphic
604 anymore, but use the automatically determined default graphic */
605 if (base_redefined && !act_dir_redefined)
610 action = ACTION_DEFAULT;
615 element_info[element].direction_crumbled[action][direction] = graphic;
617 element_info[element].crumbled[action] = graphic;
622 element_info[element].direction_graphic[action][direction] = graphic;
624 element_info[element].graphic[action] = graphic;
628 /* initialize normal element/graphic mapping from dynamic configuration */
629 for (i = 0; i < num_property_mappings; i++)
631 int element = property_mapping[i].base_index;
632 int action = property_mapping[i].ext1_index;
633 int direction = property_mapping[i].ext2_index;
634 int special = property_mapping[i].ext3_index;
635 int graphic = property_mapping[i].artwork_index;
636 boolean crumbled = FALSE;
639 if ((element == EL_EM_DYNAMITE ||
640 element == EL_EM_DYNAMITE_ACTIVE) &&
641 action == ACTION_ACTIVE &&
642 (special == GFX_SPECIAL_ARG_EDITOR ||
643 special == GFX_SPECIAL_ARG_PANEL))
644 printf("::: DYNAMIC: %d, %d, %d -> %d\n",
645 element, action, special, graphic);
648 if (special == GFX_SPECIAL_ARG_CRUMBLED)
654 if (graphic_info[graphic].bitmap == NULL)
657 if (element >= MAX_NUM_ELEMENTS || special != -1)
661 action = ACTION_DEFAULT;
666 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
667 element_info[element].direction_crumbled[action][dir] = -1;
670 element_info[element].direction_crumbled[action][direction] = graphic;
672 element_info[element].crumbled[action] = graphic;
677 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
678 element_info[element].direction_graphic[action][dir] = -1;
681 element_info[element].direction_graphic[action][direction] = graphic;
683 element_info[element].graphic[action] = graphic;
687 /* now copy all graphics that are defined to be cloned from other graphics */
688 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
690 int graphic = element_info[i].graphic[ACTION_DEFAULT];
691 int crumbled_like, diggable_like;
696 crumbled_like = graphic_info[graphic].crumbled_like;
697 diggable_like = graphic_info[graphic].diggable_like;
699 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
701 for (act = 0; act < NUM_ACTIONS; act++)
702 element_info[i].crumbled[act] =
703 element_info[crumbled_like].crumbled[act];
704 for (act = 0; act < NUM_ACTIONS; act++)
705 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
706 element_info[i].direction_crumbled[act][dir] =
707 element_info[crumbled_like].direction_crumbled[act][dir];
710 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
712 element_info[i].graphic[ACTION_DIGGING] =
713 element_info[diggable_like].graphic[ACTION_DIGGING];
714 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
715 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
716 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
721 /* set hardcoded definitions for some runtime elements without graphic */
722 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
726 /* set hardcoded definitions for some internal elements without graphic */
727 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
729 if (IS_EDITOR_CASCADE_INACTIVE(i))
730 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
731 else if (IS_EDITOR_CASCADE_ACTIVE(i))
732 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
736 /* now set all undefined/invalid graphics to -1 to set to default after it */
737 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
739 for (act = 0; act < NUM_ACTIONS; act++)
743 graphic = element_info[i].graphic[act];
744 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
745 element_info[i].graphic[act] = -1;
747 graphic = element_info[i].crumbled[act];
748 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
749 element_info[i].crumbled[act] = -1;
751 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
753 graphic = element_info[i].direction_graphic[act][dir];
754 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
755 element_info[i].direction_graphic[act][dir] = -1;
757 graphic = element_info[i].direction_crumbled[act][dir];
758 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
759 element_info[i].direction_crumbled[act][dir] = -1;
766 /* adjust graphics with 2nd tile for movement according to direction
767 (do this before correcting '-1' values to minimize calculations) */
768 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
770 for (act = 0; act < NUM_ACTIONS; act++)
772 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
774 int graphic = element_info[i].direction_graphic[act][dir];
775 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
777 if (act == ACTION_FALLING) /* special case */
778 graphic = element_info[i].graphic[act];
781 graphic_info[graphic].double_movement &&
782 graphic_info[graphic].swap_double_tiles != 0)
784 struct GraphicInfo *g = &graphic_info[graphic];
785 int src_x_front = g->src_x;
786 int src_y_front = g->src_y;
787 int src_x_back = g->src_x + g->offset2_x;
788 int src_y_back = g->src_y + g->offset2_y;
789 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
791 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
792 src_y_front < src_y_back);
793 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
794 boolean swap_movement_tiles_autodetected =
795 (!frames_are_ordered_diagonally &&
796 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
797 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
798 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
799 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
802 /* swap frontside and backside graphic tile coordinates, if needed */
803 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
805 /* get current (wrong) backside tile coordinates */
806 getFixedGraphicSourceExt(graphic, 0, &dummy,
807 &src_x_back, &src_y_back, TRUE);
809 /* set frontside tile coordinates to backside tile coordinates */
810 g->src_x = src_x_back;
811 g->src_y = src_y_back;
813 /* invert tile offset to point to new backside tile coordinates */
817 /* do not swap front and backside tiles again after correction */
818 g->swap_double_tiles = 0;
827 /* now set all '-1' values to element specific default values */
828 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
830 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
831 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
832 int default_direction_graphic[NUM_DIRECTIONS_FULL];
833 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
835 if (default_graphic == -1)
836 default_graphic = IMG_UNKNOWN;
838 if (default_crumbled == -1)
839 default_crumbled = default_graphic;
841 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
842 if (default_crumbled == -1)
843 default_crumbled = IMG_EMPTY;
846 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
848 default_direction_graphic[dir] =
849 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
850 default_direction_crumbled[dir] =
851 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
853 if (default_direction_graphic[dir] == -1)
854 default_direction_graphic[dir] = default_graphic;
856 if (default_direction_crumbled[dir] == -1)
857 default_direction_crumbled[dir] = default_direction_graphic[dir];
859 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
860 if (default_direction_crumbled[dir] == -1)
861 default_direction_crumbled[dir] = default_crumbled;
865 for (act = 0; act < NUM_ACTIONS; act++)
867 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
868 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
869 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
870 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
871 act == ACTION_TURNING_FROM_RIGHT ||
872 act == ACTION_TURNING_FROM_UP ||
873 act == ACTION_TURNING_FROM_DOWN);
875 /* generic default action graphic (defined by "[default]" directive) */
876 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
877 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
878 int default_remove_graphic = IMG_EMPTY;
880 if (act_remove && default_action_graphic != -1)
881 default_remove_graphic = default_action_graphic;
883 /* look for special default action graphic (classic game specific) */
884 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
885 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
886 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
887 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
888 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
889 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
891 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
892 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
893 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
894 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
895 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
896 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
899 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
900 /* !!! make this better !!! */
901 if (i == EL_EMPTY_SPACE)
903 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
904 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
908 if (default_action_graphic == -1)
909 default_action_graphic = default_graphic;
911 if (default_action_crumbled == -1)
912 default_action_crumbled = default_action_graphic;
914 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
915 if (default_action_crumbled == -1)
916 default_action_crumbled = default_crumbled;
919 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
921 /* use action graphic as the default direction graphic, if undefined */
922 int default_action_direction_graphic = element_info[i].graphic[act];
923 int default_action_direction_crumbled = element_info[i].crumbled[act];
925 /* no graphic for current action -- use default direction graphic */
926 if (default_action_direction_graphic == -1)
927 default_action_direction_graphic =
928 (act_remove ? default_remove_graphic :
930 element_info[i].direction_graphic[ACTION_TURNING][dir] :
931 default_action_graphic != default_graphic ?
932 default_action_graphic :
933 default_direction_graphic[dir]);
935 if (element_info[i].direction_graphic[act][dir] == -1)
936 element_info[i].direction_graphic[act][dir] =
937 default_action_direction_graphic;
940 if (default_action_direction_crumbled == -1)
941 default_action_direction_crumbled =
942 element_info[i].direction_graphic[act][dir];
944 if (default_action_direction_crumbled == -1)
945 default_action_direction_crumbled =
946 (act_remove ? default_remove_graphic :
948 element_info[i].direction_crumbled[ACTION_TURNING][dir] :
949 default_action_crumbled != default_crumbled ?
950 default_action_crumbled :
951 default_direction_crumbled[dir]);
954 if (element_info[i].direction_crumbled[act][dir] == -1)
955 element_info[i].direction_crumbled[act][dir] =
956 default_action_direction_crumbled;
959 /* no graphic for this specific action -- use default action graphic */
960 if (element_info[i].graphic[act] == -1)
961 element_info[i].graphic[act] =
962 (act_remove ? default_remove_graphic :
963 act_turning ? element_info[i].graphic[ACTION_TURNING] :
964 default_action_graphic);
966 if (element_info[i].crumbled[act] == -1)
967 element_info[i].crumbled[act] = element_info[i].graphic[act];
969 if (element_info[i].crumbled[act] == -1)
970 element_info[i].crumbled[act] =
971 (act_remove ? default_remove_graphic :
972 act_turning ? element_info[i].crumbled[ACTION_TURNING] :
973 default_action_crumbled);
981 /* !!! THIS ALSO CLEARS SPECIAL FLAGS (AND IS NOT NEEDED ANYWAY) !!! */
982 /* set animation mode to "none" for each graphic with only 1 frame */
983 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
985 for (act = 0; act < NUM_ACTIONS; act++)
987 int graphic = element_info[i].graphic[act];
988 int crumbled = element_info[i].crumbled[act];
990 if (graphic_info[graphic].anim_frames == 1)
991 graphic_info[graphic].anim_mode = ANIM_NONE;
992 if (graphic_info[crumbled].anim_frames == 1)
993 graphic_info[crumbled].anim_mode = ANIM_NONE;
995 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
997 graphic = element_info[i].direction_graphic[act][dir];
998 crumbled = element_info[i].direction_crumbled[act][dir];
1000 if (graphic_info[graphic].anim_frames == 1)
1001 graphic_info[graphic].anim_mode = ANIM_NONE;
1002 if (graphic_info[crumbled].anim_frames == 1)
1003 graphic_info[crumbled].anim_mode = ANIM_NONE;
1011 if (options.verbose)
1013 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1014 if (element_info[i].graphic[ACTION_DEFAULT] == IMG_UNKNOWN &&
1016 Error(ERR_INFO, "warning: no graphic for element '%s' (%d)",
1017 element_info[i].token_name, i);
1023 void InitElementSpecialGraphicInfo()
1025 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
1026 int num_property_mappings = getImageListPropertyMappingSize();
1029 /* always start with reliable default values */
1030 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1031 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1032 element_info[i].special_graphic[j] =
1033 element_info[i].graphic[ACTION_DEFAULT];
1035 /* initialize special element/graphic mapping from static configuration */
1036 for (i = 0; element_to_special_graphic[i].element > -1; i++)
1038 int element = element_to_special_graphic[i].element;
1039 int special = element_to_special_graphic[i].special;
1040 int graphic = element_to_special_graphic[i].graphic;
1041 int base_graphic = el2baseimg(element);
1042 boolean base_redefined =
1043 getImageListEntryFromImageID(base_graphic)->redefined;
1044 boolean special_redefined =
1045 getImageListEntryFromImageID(graphic)->redefined;
1048 if ((element == EL_EM_DYNAMITE ||
1049 element == EL_EM_DYNAMITE_ACTIVE) &&
1050 (special == GFX_SPECIAL_ARG_EDITOR ||
1051 special == GFX_SPECIAL_ARG_PANEL))
1052 printf("::: SPECIAL STATIC: %d, %d -> %d\n",
1053 element, special, graphic);
1056 /* if the base graphic ("emerald", for example) has been redefined,
1057 but not the special graphic ("emerald.EDITOR", for example), do not
1058 use an existing (in this case considered obsolete) special graphic
1059 anymore, but use the automatically created (down-scaled) graphic */
1060 if (base_redefined && !special_redefined)
1063 element_info[element].special_graphic[special] = graphic;
1066 /* initialize special element/graphic mapping from dynamic configuration */
1067 for (i = 0; i < num_property_mappings; i++)
1069 int element = property_mapping[i].base_index;
1070 int action = property_mapping[i].ext1_index;
1071 int direction = property_mapping[i].ext2_index;
1072 int special = property_mapping[i].ext3_index;
1073 int graphic = property_mapping[i].artwork_index;
1076 if ((element == EL_EM_DYNAMITE ||
1077 element == EL_EM_DYNAMITE_ACTIVE ||
1078 element == EL_CONVEYOR_BELT_1_MIDDLE ||
1079 element == EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE) &&
1080 (special == GFX_SPECIAL_ARG_EDITOR ||
1081 special == GFX_SPECIAL_ARG_PANEL))
1082 printf("::: SPECIAL DYNAMIC: %d, %d -> %d [%d]\n",
1083 element, special, graphic, property_mapping[i].ext1_index);
1087 if (element == EL_CONVEYOR_BELT_1_MIDDLE &&
1088 action == ACTION_ACTIVE)
1090 element = EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE;
1096 if (element == EL_MAGIC_WALL &&
1097 action == ACTION_ACTIVE)
1099 element = EL_MAGIC_WALL_ACTIVE;
1105 /* for action ".active", replace element with active element, if exists */
1106 if (action == ACTION_ACTIVE && element != ELEMENT_ACTIVE(element))
1108 element = ELEMENT_ACTIVE(element);
1113 if (element >= MAX_NUM_ELEMENTS)
1116 /* do not change special graphic if action or direction was specified */
1117 if (action != -1 || direction != -1)
1120 if (IS_SPECIAL_GFX_ARG(special))
1121 element_info[element].special_graphic[special] = graphic;
1124 /* now set all undefined/invalid graphics to default */
1125 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1126 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1127 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
1128 element_info[i].special_graphic[j] =
1129 element_info[i].graphic[ACTION_DEFAULT];
1132 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
1134 if (type != TYPE_ELEMENT && type != TYPE_GRAPHIC)
1135 return get_parameter_value(value_raw, suffix, type);
1137 if (strEqual(value_raw, ARG_UNDEFINED))
1138 return ARG_UNDEFINED_VALUE;
1140 if (type == TYPE_ELEMENT)
1142 char *value = getHashEntry(element_token_hash, value_raw);
1144 return (value != NULL ? atoi(value) : EL_UNDEFINED);
1146 else if (type == TYPE_GRAPHIC)
1148 char *value = getHashEntry(graphic_token_hash, value_raw);
1150 return (value != NULL ? atoi(value) : IMG_UNDEFINED);
1156 static int get_scaled_graphic_width(int graphic)
1158 int original_width = getOriginalImageWidthFromImageID(graphic);
1159 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1161 return original_width * scale_up_factor;
1164 static int get_scaled_graphic_height(int graphic)
1166 int original_height = getOriginalImageHeightFromImageID(graphic);
1167 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1169 return original_height * scale_up_factor;
1172 static void set_graphic_parameters_ext(int graphic, int *parameter,
1175 struct GraphicInfo *g = &graphic_info[graphic];
1176 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1177 int anim_frames_per_line = 1;
1179 /* always start with reliable default values */
1180 g->src_image_width = 0;
1181 g->src_image_height = 0;
1184 g->width = TILEX; /* default for element graphics */
1185 g->height = TILEY; /* default for element graphics */
1186 g->offset_x = 0; /* one or both of these values ... */
1187 g->offset_y = 0; /* ... will be corrected later */
1188 g->offset2_x = 0; /* one or both of these values ... */
1189 g->offset2_y = 0; /* ... will be corrected later */
1190 g->swap_double_tiles = -1; /* auto-detect tile swapping */
1191 g->crumbled_like = -1; /* do not use clone element */
1192 g->diggable_like = -1; /* do not use clone element */
1193 g->border_size = TILEX / 8; /* "CRUMBLED" border size */
1194 g->scale_up_factor = 1; /* default: no scaling up */
1195 g->tile_size = TILESIZE; /* default: standard tile size */
1196 g->clone_from = -1; /* do not use clone graphic */
1197 g->anim_delay_fixed = 0;
1198 g->anim_delay_random = 0;
1199 g->post_delay_fixed = 0;
1200 g->post_delay_random = 0;
1201 g->fade_mode = FADE_MODE_DEFAULT;
1205 g->align = ALIGN_CENTER; /* default for title screens */
1206 g->valign = VALIGN_MIDDLE; /* default for title screens */
1207 g->sort_priority = 0; /* default for title screens */
1209 g->style = STYLE_DEFAULT;
1211 g->bitmap = src_bitmap;
1214 /* optional zoom factor for scaling up the image to a larger size */
1215 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1216 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1217 if (g->scale_up_factor < 1)
1218 g->scale_up_factor = 1; /* no scaling */
1222 /* optional tile size for using non-standard image size */
1223 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1224 g->tile_size = parameter[GFX_ARG_TILE_SIZE];
1225 if (g->tile_size < TILESIZE)
1226 g->tile_size = TILESIZE; /* standard tile size */
1230 if (g->use_image_size)
1232 /* set new default bitmap size (with scaling, but without small images) */
1233 g->width = get_scaled_graphic_width(graphic);
1234 g->height = get_scaled_graphic_height(graphic);
1238 /* optional x and y tile position of animation frame sequence */
1239 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1240 g->src_x = parameter[GFX_ARG_XPOS] * TILEX;
1241 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1242 g->src_y = parameter[GFX_ARG_YPOS] * TILEY;
1244 /* optional x and y pixel position of animation frame sequence */
1245 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1246 g->src_x = parameter[GFX_ARG_X];
1247 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1248 g->src_y = parameter[GFX_ARG_Y];
1250 /* optional width and height of each animation frame */
1251 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1252 g->width = parameter[GFX_ARG_WIDTH];
1253 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1254 g->height = parameter[GFX_ARG_HEIGHT];
1260 Error(ERR_INFO_LINE, "-");
1261 Error(ERR_WARN, "invalid value %d for '%s.width' (fallback done to %d)",
1262 g->width, getTokenFromImageID(graphic), TILEX);
1263 Error(ERR_INFO_LINE, "-");
1265 g->width = TILEX; /* will be checked to be inside bitmap later */
1270 Error(ERR_INFO_LINE, "-");
1271 Error(ERR_WARN, "invalid value %d for '%s.height' (fallback done to %d)",
1272 g->height, getTokenFromImageID(graphic), TILEY);
1273 Error(ERR_INFO_LINE, "-");
1275 g->height = TILEY; /* will be checked to be inside bitmap later */
1280 /* optional zoom factor for scaling up the image to a larger size */
1281 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1282 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1283 if (g->scale_up_factor < 1)
1284 g->scale_up_factor = 1; /* no scaling */
1289 /* get final bitmap size (with scaling, but without small images) */
1290 int src_image_width = get_scaled_graphic_width(graphic);
1291 int src_image_height = get_scaled_graphic_height(graphic);
1293 if (src_image_width == 0 || src_image_height == 0)
1295 /* only happens when loaded outside artwork system (like "global.busy") */
1296 src_image_width = src_bitmap->width;
1297 src_image_height = src_bitmap->height;
1300 anim_frames_per_row = src_image_width / g->width;
1301 anim_frames_per_col = src_image_height / g->height;
1303 g->src_image_width = src_image_width;
1304 g->src_image_height = src_image_height;
1307 /* correct x or y offset dependent of vertical or horizontal frame order */
1308 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1310 g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1311 parameter[GFX_ARG_OFFSET] : g->height);
1312 anim_frames_per_line = anim_frames_per_col;
1314 else /* frames are ordered horizontally */
1316 g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1317 parameter[GFX_ARG_OFFSET] : g->width);
1318 anim_frames_per_line = anim_frames_per_row;
1321 /* optionally, the x and y offset of frames can be specified directly */
1322 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1323 g->offset_x = parameter[GFX_ARG_XOFFSET];
1324 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1325 g->offset_y = parameter[GFX_ARG_YOFFSET];
1327 /* optionally, moving animations may have separate start and end graphics */
1328 g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1330 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1331 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1333 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1334 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1335 g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1336 parameter[GFX_ARG_2ND_OFFSET] : g->height);
1337 else /* frames are ordered horizontally */
1338 g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1339 parameter[GFX_ARG_2ND_OFFSET] : g->width);
1341 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1342 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1343 g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1344 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1345 g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1347 /* optionally, the second movement tile can be specified as start tile */
1348 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1349 g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1351 /* automatically determine correct number of frames, if not defined */
1352 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1353 g->anim_frames = parameter[GFX_ARG_FRAMES];
1354 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1355 g->anim_frames = anim_frames_per_row;
1356 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1357 g->anim_frames = anim_frames_per_col;
1361 if (g->anim_frames == 0) /* frames must be at least 1 */
1364 g->anim_frames_per_line =
1365 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1366 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1368 g->anim_delay = parameter[GFX_ARG_DELAY];
1369 if (g->anim_delay == 0) /* delay must be at least 1 */
1372 g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1374 if (g->anim_frames == 1)
1375 g->anim_mode = ANIM_NONE;
1378 /* automatically determine correct start frame, if not defined */
1379 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1380 g->anim_start_frame = 0;
1381 else if (g->anim_mode & ANIM_REVERSE)
1382 g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1384 g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1386 /* animation synchronized with global frame counter, not move position */
1387 g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1389 /* optional element for cloning crumble graphics */
1390 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1391 g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1393 /* optional element for cloning digging graphics */
1394 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1395 g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1397 /* optional border size for "crumbling" diggable graphics */
1398 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1399 g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1401 /* this is only used for player "boring" and "sleeping" actions */
1402 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1403 g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1404 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1405 g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1406 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1407 g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1408 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1409 g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1411 /* this is only used for toon animations */
1412 g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1413 g->step_delay = parameter[GFX_ARG_STEP_DELAY];
1415 /* this is only used for drawing font characters */
1416 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1417 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1419 /* this is only used for drawing envelope graphics */
1420 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1422 /* optional graphic for cloning all graphics settings */
1423 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1424 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1426 /* optional settings for drawing title screens and title messages */
1427 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1428 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1429 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1430 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1431 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1432 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1433 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1434 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1435 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1436 g->align = parameter[GFX_ARG_ALIGN];
1437 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1438 g->valign = parameter[GFX_ARG_VALIGN];
1439 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1440 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1442 if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
1443 g->class = parameter[GFX_ARG_CLASS];
1444 if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
1445 g->style = parameter[GFX_ARG_STYLE];
1447 /* this is only used for drawing menu buttons and text */
1448 g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
1449 g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
1450 g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
1451 g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
1454 static void set_graphic_parameters(int graphic)
1457 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1458 char **parameter_raw = image->parameter;
1459 Bitmap *src_bitmap = getBitmapFromImageID(graphic);
1460 int parameter[NUM_GFX_ARGS];
1463 /* if fallback to default artwork is done, also use the default parameters */
1464 if (image->fallback_to_default)
1465 parameter_raw = image->default_parameter;
1467 /* get integer values from string parameters */
1468 for (i = 0; i < NUM_GFX_ARGS; i++)
1469 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1470 image_config_suffix[i].token,
1471 image_config_suffix[i].type);
1473 set_graphic_parameters_ext(graphic, parameter, src_bitmap);
1477 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1478 char **parameter_raw = image->parameter;
1479 Bitmap *src_bitmap = getBitmapFromImageID(graphic);
1480 int parameter[NUM_GFX_ARGS];
1481 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1482 int anim_frames_per_line = 1;
1485 /* if fallback to default artwork is done, also use the default parameters */
1486 if (image->fallback_to_default)
1487 parameter_raw = image->default_parameter;
1489 /* get integer values from string parameters */
1490 for (i = 0; i < NUM_GFX_ARGS; i++)
1491 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1492 image_config_suffix[i].token,
1493 image_config_suffix[i].type);
1495 graphic_info[graphic].bitmap = src_bitmap;
1497 /* always start with reliable default values */
1498 graphic_info[graphic].src_image_width = 0;
1499 graphic_info[graphic].src_image_height = 0;
1500 graphic_info[graphic].src_x = 0;
1501 graphic_info[graphic].src_y = 0;
1502 graphic_info[graphic].width = TILEX; /* default for element graphics */
1503 graphic_info[graphic].height = TILEY; /* default for element graphics */
1504 graphic_info[graphic].offset_x = 0; /* one or both of these values ... */
1505 graphic_info[graphic].offset_y = 0; /* ... will be corrected later */
1506 graphic_info[graphic].offset2_x = 0; /* one or both of these values ... */
1507 graphic_info[graphic].offset2_y = 0; /* ... will be corrected later */
1508 graphic_info[graphic].swap_double_tiles = -1; /* auto-detect tile swapping */
1509 graphic_info[graphic].crumbled_like = -1; /* do not use clone element */
1510 graphic_info[graphic].diggable_like = -1; /* do not use clone element */
1511 graphic_info[graphic].border_size = TILEX / 8; /* "CRUMBLED" border size */
1512 graphic_info[graphic].scale_up_factor = 1; /* default: no scaling up */
1513 graphic_info[graphic].clone_from = -1; /* do not use clone graphic */
1514 graphic_info[graphic].anim_delay_fixed = 0;
1515 graphic_info[graphic].anim_delay_random = 0;
1516 graphic_info[graphic].post_delay_fixed = 0;
1517 graphic_info[graphic].post_delay_random = 0;
1518 graphic_info[graphic].fade_mode = FADE_MODE_DEFAULT;
1519 graphic_info[graphic].fade_delay = -1;
1520 graphic_info[graphic].post_delay = -1;
1521 graphic_info[graphic].auto_delay = -1;
1522 graphic_info[graphic].align = ALIGN_CENTER; /* default for title screens */
1523 graphic_info[graphic].valign = VALIGN_MIDDLE; /* default for title screens */
1524 graphic_info[graphic].sort_priority = 0; /* default for title screens */
1527 /* optional zoom factor for scaling up the image to a larger size */
1528 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1529 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1530 if (graphic_info[graphic].scale_up_factor < 1)
1531 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
1535 if (graphic_info[graphic].use_image_size)
1537 /* set new default bitmap size (with scaling, but without small images) */
1538 graphic_info[graphic].width = get_scaled_graphic_width(graphic);
1539 graphic_info[graphic].height = get_scaled_graphic_height(graphic);
1543 /* optional x and y tile position of animation frame sequence */
1544 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1545 graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
1546 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1547 graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
1549 /* optional x and y pixel position of animation frame sequence */
1550 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1551 graphic_info[graphic].src_x = parameter[GFX_ARG_X];
1552 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1553 graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
1555 /* optional width and height of each animation frame */
1556 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1557 graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
1558 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1559 graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
1562 /* optional zoom factor for scaling up the image to a larger size */
1563 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1564 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1565 if (graphic_info[graphic].scale_up_factor < 1)
1566 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
1571 /* get final bitmap size (with scaling, but without small images) */
1572 int src_image_width = get_scaled_graphic_width(graphic);
1573 int src_image_height = get_scaled_graphic_height(graphic);
1575 anim_frames_per_row = src_image_width / graphic_info[graphic].width;
1576 anim_frames_per_col = src_image_height / graphic_info[graphic].height;
1578 graphic_info[graphic].src_image_width = src_image_width;
1579 graphic_info[graphic].src_image_height = src_image_height;
1582 /* correct x or y offset dependent of vertical or horizontal frame order */
1583 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1585 graphic_info[graphic].offset_y =
1586 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1587 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
1588 anim_frames_per_line = anim_frames_per_col;
1590 else /* frames are ordered horizontally */
1592 graphic_info[graphic].offset_x =
1593 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1594 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
1595 anim_frames_per_line = anim_frames_per_row;
1598 /* optionally, the x and y offset of frames can be specified directly */
1599 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1600 graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
1601 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1602 graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
1604 /* optionally, moving animations may have separate start and end graphics */
1605 graphic_info[graphic].double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1607 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1608 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1610 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1611 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1612 graphic_info[graphic].offset2_y =
1613 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1614 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].height);
1615 else /* frames are ordered horizontally */
1616 graphic_info[graphic].offset2_x =
1617 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1618 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].width);
1620 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1621 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1622 graphic_info[graphic].offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1623 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1624 graphic_info[graphic].offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1626 /* optionally, the second movement tile can be specified as start tile */
1627 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1628 graphic_info[graphic].swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1630 /* automatically determine correct number of frames, if not defined */
1631 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1632 graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
1633 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1634 graphic_info[graphic].anim_frames = anim_frames_per_row;
1635 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1636 graphic_info[graphic].anim_frames = anim_frames_per_col;
1638 graphic_info[graphic].anim_frames = 1;
1640 if (graphic_info[graphic].anim_frames == 0) /* frames must be at least 1 */
1641 graphic_info[graphic].anim_frames = 1;
1643 graphic_info[graphic].anim_frames_per_line =
1644 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1645 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1647 graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
1648 if (graphic_info[graphic].anim_delay == 0) /* delay must be at least 1 */
1649 graphic_info[graphic].anim_delay = 1;
1651 graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
1653 if (graphic_info[graphic].anim_frames == 1)
1654 graphic_info[graphic].anim_mode = ANIM_NONE;
1657 /* automatically determine correct start frame, if not defined */
1658 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1659 graphic_info[graphic].anim_start_frame = 0;
1660 else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
1661 graphic_info[graphic].anim_start_frame =
1662 graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1664 graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
1666 /* animation synchronized with global frame counter, not move position */
1667 graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1669 /* optional element for cloning crumble graphics */
1670 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1671 graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1673 /* optional element for cloning digging graphics */
1674 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1675 graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1677 /* optional border size for "crumbling" diggable graphics */
1678 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1679 graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
1681 /* this is only used for player "boring" and "sleeping" actions */
1682 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1683 graphic_info[graphic].anim_delay_fixed =
1684 parameter[GFX_ARG_ANIM_DELAY_FIXED];
1685 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1686 graphic_info[graphic].anim_delay_random =
1687 parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1688 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1689 graphic_info[graphic].post_delay_fixed =
1690 parameter[GFX_ARG_POST_DELAY_FIXED];
1691 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1692 graphic_info[graphic].post_delay_random =
1693 parameter[GFX_ARG_POST_DELAY_RANDOM];
1695 /* this is only used for toon animations */
1696 graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
1697 graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY];
1699 /* this is only used for drawing font characters */
1700 graphic_info[graphic].draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1701 graphic_info[graphic].draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1703 /* this is only used for drawing envelope graphics */
1704 graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1706 /* optional graphic for cloning all graphics settings */
1707 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1708 graphic_info[graphic].clone_from = parameter[GFX_ARG_CLONE_FROM];
1710 /* optional settings for drawing title screens and title messages */
1711 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1712 graphic_info[graphic].fade_mode = parameter[GFX_ARG_FADE_MODE];
1713 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1714 graphic_info[graphic].fade_delay = parameter[GFX_ARG_FADE_DELAY];
1715 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1716 graphic_info[graphic].post_delay = parameter[GFX_ARG_POST_DELAY];
1717 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1718 graphic_info[graphic].auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1719 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1720 graphic_info[graphic].align = parameter[GFX_ARG_ALIGN];
1721 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1722 graphic_info[graphic].valign = parameter[GFX_ARG_VALIGN];
1723 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1724 graphic_info[graphic].sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1727 UPDATE_BUSY_STATE();
1730 static void set_cloned_graphic_parameters(int graphic)
1732 int fallback_graphic = IMG_CHAR_EXCLAM;
1733 int max_num_images = getImageListSize();
1734 int clone_graphic = graphic_info[graphic].clone_from;
1735 int num_references_followed = 1;
1737 while (graphic_info[clone_graphic].clone_from != -1 &&
1738 num_references_followed < max_num_images)
1740 clone_graphic = graphic_info[clone_graphic].clone_from;
1742 num_references_followed++;
1745 if (num_references_followed >= max_num_images)
1747 Error(ERR_INFO_LINE, "-");
1748 Error(ERR_INFO, "warning: error found in config file:");
1749 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1750 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1751 Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1752 Error(ERR_INFO, "custom graphic rejected for this element/action");
1754 if (graphic == fallback_graphic)
1755 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1757 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1758 Error(ERR_INFO_LINE, "-");
1760 graphic_info[graphic] = graphic_info[fallback_graphic];
1764 graphic_info[graphic] = graphic_info[clone_graphic];
1765 graphic_info[graphic].clone_from = clone_graphic;
1769 static void InitGraphicInfo()
1771 int fallback_graphic = IMG_CHAR_EXCLAM;
1772 int num_images = getImageListSize();
1775 /* use image size as default values for width and height for these images */
1776 static int full_size_graphics[] =
1781 IMG_BACKGROUND_ENVELOPE_1,
1782 IMG_BACKGROUND_ENVELOPE_2,
1783 IMG_BACKGROUND_ENVELOPE_3,
1784 IMG_BACKGROUND_ENVELOPE_4,
1785 IMG_BACKGROUND_REQUEST,
1788 IMG_BACKGROUND_TITLE_INITIAL,
1789 IMG_BACKGROUND_TITLE,
1790 IMG_BACKGROUND_MAIN,
1791 IMG_BACKGROUND_LEVELS,
1792 IMG_BACKGROUND_LEVELNR,
1793 IMG_BACKGROUND_SCORES,
1794 IMG_BACKGROUND_EDITOR,
1795 IMG_BACKGROUND_INFO,
1796 IMG_BACKGROUND_INFO_ELEMENTS,
1797 IMG_BACKGROUND_INFO_MUSIC,
1798 IMG_BACKGROUND_INFO_CREDITS,
1799 IMG_BACKGROUND_INFO_PROGRAM,
1800 IMG_BACKGROUND_INFO_VERSION,
1801 IMG_BACKGROUND_INFO_LEVELSET,
1802 IMG_BACKGROUND_SETUP,
1803 IMG_BACKGROUND_PLAYING,
1804 IMG_BACKGROUND_DOOR,
1805 IMG_BACKGROUND_TAPE,
1806 IMG_BACKGROUND_PANEL,
1807 IMG_BACKGROUND_PALETTE,
1808 IMG_BACKGROUND_TOOLBOX,
1810 IMG_TITLESCREEN_INITIAL_1,
1811 IMG_TITLESCREEN_INITIAL_2,
1812 IMG_TITLESCREEN_INITIAL_3,
1813 IMG_TITLESCREEN_INITIAL_4,
1814 IMG_TITLESCREEN_INITIAL_5,
1821 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1,
1822 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2,
1823 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3,
1824 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4,
1825 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5,
1826 IMG_BACKGROUND_TITLEMESSAGE_1,
1827 IMG_BACKGROUND_TITLEMESSAGE_2,
1828 IMG_BACKGROUND_TITLEMESSAGE_3,
1829 IMG_BACKGROUND_TITLEMESSAGE_4,
1830 IMG_BACKGROUND_TITLEMESSAGE_5,
1835 checked_free(graphic_info);
1837 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1840 /* initialize "use_image_size" flag with default value */
1841 for (i = 0; i < num_images; i++)
1842 graphic_info[i].use_image_size = FALSE;
1844 /* initialize "use_image_size" flag from static configuration above */
1845 for (i = 0; full_size_graphics[i] != -1; i++)
1846 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1849 /* first set all graphic paramaters ... */
1850 for (i = 0; i < num_images; i++)
1851 set_graphic_parameters(i);
1853 /* ... then copy these parameters for cloned graphics */
1854 for (i = 0; i < num_images; i++)
1855 if (graphic_info[i].clone_from != -1)
1856 set_cloned_graphic_parameters(i);
1858 for (i = 0; i < num_images; i++)
1863 int first_frame, last_frame;
1864 int src_bitmap_width, src_bitmap_height;
1866 /* now check if no animation frames are outside of the loaded image */
1868 if (graphic_info[i].bitmap == NULL)
1869 continue; /* skip check for optional images that are undefined */
1871 /* get image size (this can differ from the standard element tile size!) */
1872 width = graphic_info[i].width;
1873 height = graphic_info[i].height;
1875 /* get final bitmap size (with scaling, but without small images) */
1876 src_bitmap_width = graphic_info[i].src_image_width;
1877 src_bitmap_height = graphic_info[i].src_image_height;
1879 /* check if first animation frame is inside specified bitmap */
1882 getFixedGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1885 /* this avoids calculating wrong start position for out-of-bounds frame */
1886 src_x = graphic_info[i].src_x;
1887 src_y = graphic_info[i].src_y;
1890 if (src_x < 0 || src_y < 0 ||
1891 src_x + width > src_bitmap_width ||
1892 src_y + height > src_bitmap_height)
1894 Error(ERR_INFO_LINE, "-");
1895 Error(ERR_INFO, "warning: error found in config file:");
1896 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1897 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1898 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1900 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1901 src_x, src_y, src_bitmap_width, src_bitmap_height);
1902 Error(ERR_INFO, "custom graphic rejected for this element/action");
1904 if (i == fallback_graphic)
1905 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1907 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1908 Error(ERR_INFO_LINE, "-");
1910 graphic_info[i] = graphic_info[fallback_graphic];
1913 /* check if last animation frame is inside specified bitmap */
1915 last_frame = graphic_info[i].anim_frames - 1;
1916 getFixedGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1918 if (src_x < 0 || src_y < 0 ||
1919 src_x + width > src_bitmap_width ||
1920 src_y + height > src_bitmap_height)
1922 Error(ERR_INFO_LINE, "-");
1923 Error(ERR_INFO, "warning: error found in config file:");
1924 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1925 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1926 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1928 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1929 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1930 Error(ERR_INFO, "::: %d, %d", width, height);
1931 Error(ERR_INFO, "custom graphic rejected for this element/action");
1933 if (i == fallback_graphic)
1934 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1936 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1937 Error(ERR_INFO_LINE, "-");
1939 graphic_info[i] = graphic_info[fallback_graphic];
1944 static void InitGraphicCompatibilityInfo()
1946 struct FileInfo *fi_global_door =
1947 getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1948 int num_images = getImageListSize();
1951 /* the following compatibility handling is needed for the following case:
1952 versions up to 3.3.0.0 used one large bitmap "global.door" for various
1953 graphics mainly used for door and panel graphics, like editor, tape and
1954 in-game buttons with hard-coded bitmap positions and button sizes; as
1955 these graphics now have individual definitions, redefining "global.door"
1956 to change all these graphics at once like before does not work anymore
1957 (because all those individual definitions still have their default values);
1958 to solve this, remap all those individual definitions that are not
1959 redefined to the new bitmap of "global.door" if it was redefined */
1961 /* special compatibility handling if image "global.door" was redefined */
1962 if (fi_global_door->redefined)
1964 for (i = 0; i < num_images; i++)
1966 struct FileInfo *fi = getImageListEntryFromImageID(i);
1968 /* process only those images that still use the default settings */
1971 /* process all images which default to same image as "global.door" */
1972 if (strEqual(fi->default_filename, fi_global_door->default_filename))
1974 // printf("::: special treatment needed for token '%s'\n", fi->token);
1976 graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
1983 InitGraphicCompatibilityInfo_Doors();
1990 int *width, *height;
1995 { IMG_DOOR_1_WING_LEFT, &door_1.width, &door_1.height, FALSE },
1996 { IMG_DOOR_1_WING_RIGHT, &door_1.width, &door_1.height, TRUE },
1997 { IMG_DOOR_2_WING_LEFT, &door_2.width, &door_2.height, FALSE },
1998 { IMG_DOOR_2_WING_RIGHT, &door_2.width, &door_2.height, TRUE },
2000 { 0, NULL, NULL, FALSE }
2003 for (i = 0; doors[i].graphic != 0; i++)
2005 int graphic = doors[i].graphic;
2006 int *width = doors[i].width;
2007 int *height = doors[i].height;
2008 boolean right_wing = doors[i].right_wing;
2010 struct FileInfo *fi = getImageListEntryFromImageID(graphic);
2011 struct GraphicInfo *g = &graphic_info[graphic];
2017 // correct start position for right wing of "standard" door graphic
2019 g->src_x += g->width - *width;
2025 g->height = *height;
2031 for (i = 0; i < num_images; i++)
2033 struct FileInfo *fi = getImageListEntryFromImageID(i);
2035 if (i == IMG_GLOBAL_DOOR)
2037 printf("::: %s, %s, %d\n",
2038 fi->default_filename,
2046 static void InitElementSoundInfo()
2048 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
2049 int num_property_mappings = getSoundListPropertyMappingSize();
2052 /* set values to -1 to identify later as "uninitialized" values */
2053 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2054 for (act = 0; act < NUM_ACTIONS; act++)
2055 element_info[i].sound[act] = -1;
2057 /* initialize element/sound mapping from static configuration */
2058 for (i = 0; element_to_sound[i].element > -1; i++)
2060 int element = element_to_sound[i].element;
2061 int action = element_to_sound[i].action;
2062 int sound = element_to_sound[i].sound;
2063 boolean is_class = element_to_sound[i].is_class;
2066 action = ACTION_DEFAULT;
2069 element_info[element].sound[action] = sound;
2071 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2072 if (strEqual(element_info[j].class_name,
2073 element_info[element].class_name))
2074 element_info[j].sound[action] = sound;
2077 /* initialize element class/sound mapping from dynamic configuration */
2078 for (i = 0; i < num_property_mappings; i++)
2080 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
2081 int action = property_mapping[i].ext1_index;
2082 int sound = property_mapping[i].artwork_index;
2084 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
2088 action = ACTION_DEFAULT;
2090 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2091 if (strEqual(element_info[j].class_name,
2092 element_info[element_class].class_name))
2093 element_info[j].sound[action] = sound;
2096 /* initialize element/sound mapping from dynamic configuration */
2097 for (i = 0; i < num_property_mappings; i++)
2099 int element = property_mapping[i].base_index;
2100 int action = property_mapping[i].ext1_index;
2101 int sound = property_mapping[i].artwork_index;
2103 if (element >= MAX_NUM_ELEMENTS)
2107 action = ACTION_DEFAULT;
2109 element_info[element].sound[action] = sound;
2112 /* now set all '-1' values to element specific default values */
2113 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2115 for (act = 0; act < NUM_ACTIONS; act++)
2117 /* generic default action sound (defined by "[default]" directive) */
2118 int default_action_sound = element_info[EL_DEFAULT].sound[act];
2120 /* look for special default action sound (classic game specific) */
2121 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
2122 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
2123 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
2124 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
2125 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
2126 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
2128 /* !!! there's no such thing as a "default action sound" !!! */
2130 /* look for element specific default sound (independent from action) */
2131 if (element_info[i].sound[ACTION_DEFAULT] != -1)
2132 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
2136 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
2137 /* !!! make this better !!! */
2138 if (i == EL_EMPTY_SPACE)
2139 default_action_sound = element_info[EL_DEFAULT].sound[act];
2142 /* no sound for this specific action -- use default action sound */
2143 if (element_info[i].sound[act] == -1)
2144 element_info[i].sound[act] = default_action_sound;
2148 /* copy sound settings to some elements that are only stored in level file
2149 in native R'n'D levels, but are used by game engine in native EM levels */
2150 for (i = 0; copy_properties[i][0] != -1; i++)
2151 for (j = 1; j <= 4; j++)
2152 for (act = 0; act < NUM_ACTIONS; act++)
2153 element_info[copy_properties[i][j]].sound[act] =
2154 element_info[copy_properties[i][0]].sound[act];
2157 static void InitGameModeSoundInfo()
2161 /* set values to -1 to identify later as "uninitialized" values */
2162 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2165 /* initialize gamemode/sound mapping from static configuration */
2166 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
2168 int gamemode = gamemode_to_sound[i].gamemode;
2169 int sound = gamemode_to_sound[i].sound;
2172 gamemode = GAME_MODE_DEFAULT;
2174 menu.sound[gamemode] = sound;
2177 /* now set all '-1' values to levelset specific default values */
2178 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2179 if (menu.sound[i] == -1)
2180 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
2183 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2184 if (menu.sound[i] != -1)
2185 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
2189 static void set_sound_parameters(int sound, char **parameter_raw)
2191 int parameter[NUM_SND_ARGS];
2194 /* get integer values from string parameters */
2195 for (i = 0; i < NUM_SND_ARGS; i++)
2197 get_parameter_value(parameter_raw[i],
2198 sound_config_suffix[i].token,
2199 sound_config_suffix[i].type);
2201 /* explicit loop mode setting in configuration overrides default value */
2202 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2203 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
2205 /* sound volume to change the original volume when loading the sound file */
2206 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
2208 /* sound priority to give certain sounds a higher or lower priority */
2209 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
2212 static void InitSoundInfo()
2214 int *sound_effect_properties;
2215 int num_sounds = getSoundListSize();
2218 checked_free(sound_info);
2220 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
2221 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
2223 /* initialize sound effect for all elements to "no sound" */
2224 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2225 for (j = 0; j < NUM_ACTIONS; j++)
2226 element_info[i].sound[j] = SND_UNDEFINED;
2228 for (i = 0; i < num_sounds; i++)
2230 struct FileInfo *sound = getSoundListEntry(i);
2231 int len_effect_text = strlen(sound->token);
2233 sound_effect_properties[i] = ACTION_OTHER;
2234 sound_info[i].loop = FALSE; /* default: play sound only once */
2237 printf("::: sound %d: '%s'\n", i, sound->token);
2240 /* determine all loop sounds and identify certain sound classes */
2242 for (j = 0; element_action_info[j].suffix; j++)
2244 int len_action_text = strlen(element_action_info[j].suffix);
2246 if (len_action_text < len_effect_text &&
2247 strEqual(&sound->token[len_effect_text - len_action_text],
2248 element_action_info[j].suffix))
2250 sound_effect_properties[i] = element_action_info[j].value;
2251 sound_info[i].loop = element_action_info[j].is_loop_sound;
2257 /* associate elements and some selected sound actions */
2259 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2261 if (element_info[j].class_name)
2263 int len_class_text = strlen(element_info[j].class_name);
2265 if (len_class_text + 1 < len_effect_text &&
2266 strncmp(sound->token,
2267 element_info[j].class_name, len_class_text) == 0 &&
2268 sound->token[len_class_text] == '.')
2270 int sound_action_value = sound_effect_properties[i];
2272 element_info[j].sound[sound_action_value] = i;
2277 set_sound_parameters(i, sound->parameter);
2280 free(sound_effect_properties);
2283 static void InitGameModeMusicInfo()
2285 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
2286 int num_property_mappings = getMusicListPropertyMappingSize();
2287 int default_levelset_music = -1;
2290 /* set values to -1 to identify later as "uninitialized" values */
2291 for (i = 0; i < MAX_LEVELS; i++)
2292 levelset.music[i] = -1;
2293 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2296 /* initialize gamemode/music mapping from static configuration */
2297 for (i = 0; gamemode_to_music[i].music > -1; i++)
2299 int gamemode = gamemode_to_music[i].gamemode;
2300 int music = gamemode_to_music[i].music;
2303 printf("::: gamemode == %d, music == %d\n", gamemode, music);
2307 gamemode = GAME_MODE_DEFAULT;
2309 menu.music[gamemode] = music;
2312 /* initialize gamemode/music mapping from dynamic configuration */
2313 for (i = 0; i < num_property_mappings; i++)
2315 int prefix = property_mapping[i].base_index;
2316 int gamemode = property_mapping[i].ext1_index;
2317 int level = property_mapping[i].ext2_index;
2318 int music = property_mapping[i].artwork_index;
2321 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
2322 prefix, gamemode, level, music);
2325 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
2329 gamemode = GAME_MODE_DEFAULT;
2331 /* level specific music only allowed for in-game music */
2332 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
2333 gamemode = GAME_MODE_PLAYING;
2338 default_levelset_music = music;
2341 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
2342 levelset.music[level] = music;
2343 if (gamemode != GAME_MODE_PLAYING)
2344 menu.music[gamemode] = music;
2347 /* now set all '-1' values to menu specific default values */
2348 /* (undefined values of "levelset.music[]" might stay at "-1" to
2349 allow dynamic selection of music files from music directory!) */
2350 for (i = 0; i < MAX_LEVELS; i++)
2351 if (levelset.music[i] == -1)
2352 levelset.music[i] = default_levelset_music;
2353 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2354 if (menu.music[i] == -1)
2355 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
2358 for (i = 0; i < MAX_LEVELS; i++)
2359 if (levelset.music[i] != -1)
2360 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
2361 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2362 if (menu.music[i] != -1)
2363 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
2367 static void set_music_parameters(int music, char **parameter_raw)
2369 int parameter[NUM_MUS_ARGS];
2372 /* get integer values from string parameters */
2373 for (i = 0; i < NUM_MUS_ARGS; i++)
2375 get_parameter_value(parameter_raw[i],
2376 music_config_suffix[i].token,
2377 music_config_suffix[i].type);
2379 /* explicit loop mode setting in configuration overrides default value */
2380 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2381 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
2384 static void InitMusicInfo()
2386 int num_music = getMusicListSize();
2389 checked_free(music_info);
2391 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
2393 for (i = 0; i < num_music; i++)
2395 struct FileInfo *music = getMusicListEntry(i);
2396 int len_music_text = strlen(music->token);
2398 music_info[i].loop = TRUE; /* default: play music in loop mode */
2400 /* determine all loop music */
2402 for (j = 0; music_prefix_info[j].prefix; j++)
2404 int len_prefix_text = strlen(music_prefix_info[j].prefix);
2406 if (len_prefix_text < len_music_text &&
2407 strncmp(music->token,
2408 music_prefix_info[j].prefix, len_prefix_text) == 0)
2410 music_info[i].loop = music_prefix_info[j].is_loop_music;
2416 set_music_parameters(i, music->parameter);
2420 static void ReinitializeGraphics()
2422 print_timestamp_init("ReinitializeGraphics");
2424 #if NEW_GAME_TILESIZE
2425 InitGfxTileSizeInfo(game.tile_size, TILESIZE);
2428 InitGraphicInfo(); /* graphic properties mapping */
2429 print_timestamp_time("InitGraphicInfo");
2430 InitElementGraphicInfo(); /* element game graphic mapping */
2431 print_timestamp_time("InitElementGraphicInfo");
2432 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
2433 print_timestamp_time("InitElementSpecialGraphicInfo");
2435 InitElementSmallImages(); /* scale elements to all needed sizes */
2436 print_timestamp_time("InitElementSmallImages");
2437 InitScaledImages(); /* scale all other images, if needed */
2438 print_timestamp_time("InitScaledImages");
2439 InitFontGraphicInfo(); /* initialize text drawing functions */
2440 print_timestamp_time("InitFontGraphicInfo");
2442 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
2443 print_timestamp_time("InitGraphicInfo_EM");
2445 InitGraphicCompatibilityInfo();
2446 print_timestamp_time("InitGraphicCompatibilityInfo");
2448 SetMainBackgroundImage(IMG_BACKGROUND);
2449 print_timestamp_time("SetMainBackgroundImage");
2450 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2451 print_timestamp_time("SetDoorBackgroundImage");
2454 print_timestamp_time("InitGadgets");
2456 print_timestamp_time("InitToons");
2458 print_timestamp_time("InitDoors");
2460 print_timestamp_done("ReinitializeGraphics");
2463 static void ReinitializeSounds()
2465 InitSoundInfo(); /* sound properties mapping */
2466 InitElementSoundInfo(); /* element game sound mapping */
2467 InitGameModeSoundInfo(); /* game mode sound mapping */
2469 InitPlayLevelSound(); /* internal game sound settings */
2472 static void ReinitializeMusic()
2474 InitMusicInfo(); /* music properties mapping */
2475 InitGameModeMusicInfo(); /* game mode music mapping */
2478 static int get_special_property_bit(int element, int property_bit_nr)
2480 struct PropertyBitInfo
2486 static struct PropertyBitInfo pb_can_move_into_acid[] =
2488 /* the player may be able fall into acid when gravity is activated */
2493 { EL_SP_MURPHY, 0 },
2494 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2496 /* all elements that can move may be able to also move into acid */
2499 { EL_BUG_RIGHT, 1 },
2502 { EL_SPACESHIP, 2 },
2503 { EL_SPACESHIP_LEFT, 2 },
2504 { EL_SPACESHIP_RIGHT, 2 },
2505 { EL_SPACESHIP_UP, 2 },
2506 { EL_SPACESHIP_DOWN, 2 },
2507 { EL_BD_BUTTERFLY, 3 },
2508 { EL_BD_BUTTERFLY_LEFT, 3 },
2509 { EL_BD_BUTTERFLY_RIGHT, 3 },
2510 { EL_BD_BUTTERFLY_UP, 3 },
2511 { EL_BD_BUTTERFLY_DOWN, 3 },
2512 { EL_BD_FIREFLY, 4 },
2513 { EL_BD_FIREFLY_LEFT, 4 },
2514 { EL_BD_FIREFLY_RIGHT, 4 },
2515 { EL_BD_FIREFLY_UP, 4 },
2516 { EL_BD_FIREFLY_DOWN, 4 },
2518 { EL_YAMYAM_LEFT, 5 },
2519 { EL_YAMYAM_RIGHT, 5 },
2520 { EL_YAMYAM_UP, 5 },
2521 { EL_YAMYAM_DOWN, 5 },
2522 { EL_DARK_YAMYAM, 6 },
2525 { EL_PACMAN_LEFT, 8 },
2526 { EL_PACMAN_RIGHT, 8 },
2527 { EL_PACMAN_UP, 8 },
2528 { EL_PACMAN_DOWN, 8 },
2530 { EL_MOLE_LEFT, 9 },
2531 { EL_MOLE_RIGHT, 9 },
2533 { EL_MOLE_DOWN, 9 },
2537 { EL_SATELLITE, 13 },
2538 { EL_SP_SNIKSNAK, 14 },
2539 { EL_SP_ELECTRON, 15 },
2542 { EL_EMC_ANDROID, 18 },
2547 static struct PropertyBitInfo pb_dont_collide_with[] =
2549 { EL_SP_SNIKSNAK, 0 },
2550 { EL_SP_ELECTRON, 1 },
2558 struct PropertyBitInfo *pb_info;
2561 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2562 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2567 struct PropertyBitInfo *pb_info = NULL;
2570 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2571 if (pb_definition[i].bit_nr == property_bit_nr)
2572 pb_info = pb_definition[i].pb_info;
2574 if (pb_info == NULL)
2577 for (i = 0; pb_info[i].element != -1; i++)
2578 if (pb_info[i].element == element)
2579 return pb_info[i].bit_nr;
2584 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2585 boolean property_value)
2587 int bit_nr = get_special_property_bit(element, property_bit_nr);
2592 *bitfield |= (1 << bit_nr);
2594 *bitfield &= ~(1 << bit_nr);
2598 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2600 int bit_nr = get_special_property_bit(element, property_bit_nr);
2603 return ((*bitfield & (1 << bit_nr)) != 0);
2608 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2610 static int group_nr;
2611 static struct ElementGroupInfo *group;
2612 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2615 if (actual_group == NULL) /* not yet initialized */
2618 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
2620 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2621 group_element - EL_GROUP_START + 1);
2623 /* replace element which caused too deep recursion by question mark */
2624 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2629 if (recursion_depth == 0) /* initialization */
2631 group = actual_group;
2632 group_nr = GROUP_NR(group_element);
2634 group->num_elements_resolved = 0;
2635 group->choice_pos = 0;
2637 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2638 element_info[i].in_group[group_nr] = FALSE;
2641 for (i = 0; i < actual_group->num_elements; i++)
2643 int element = actual_group->element[i];
2645 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2648 if (IS_GROUP_ELEMENT(element))
2649 ResolveGroupElementExt(element, recursion_depth + 1);
2652 group->element_resolved[group->num_elements_resolved++] = element;
2653 element_info[element].in_group[group_nr] = TRUE;
2658 void ResolveGroupElement(int group_element)
2660 ResolveGroupElementExt(group_element, 0);
2663 void InitElementPropertiesStatic()
2665 static boolean clipboard_elements_initialized = FALSE;
2667 static int ep_diggable[] =
2672 EL_SP_BUGGY_BASE_ACTIVATING,
2675 EL_INVISIBLE_SAND_ACTIVE,
2678 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2679 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2684 EL_SP_BUGGY_BASE_ACTIVE,
2691 static int ep_collectible_only[] =
2713 EL_DYNABOMB_INCREASE_NUMBER,
2714 EL_DYNABOMB_INCREASE_SIZE,
2715 EL_DYNABOMB_INCREASE_POWER,
2733 /* !!! handle separately !!! */
2734 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2740 static int ep_dont_run_into[] =
2742 /* same elements as in 'ep_dont_touch' */
2748 /* same elements as in 'ep_dont_collide_with' */
2760 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2765 EL_SP_BUGGY_BASE_ACTIVE,
2772 static int ep_dont_collide_with[] =
2774 /* same elements as in 'ep_dont_touch' */
2791 static int ep_dont_touch[] =
2801 static int ep_indestructible[] =
2805 EL_ACID_POOL_TOPLEFT,
2806 EL_ACID_POOL_TOPRIGHT,
2807 EL_ACID_POOL_BOTTOMLEFT,
2808 EL_ACID_POOL_BOTTOM,
2809 EL_ACID_POOL_BOTTOMRIGHT,
2810 EL_SP_HARDWARE_GRAY,
2811 EL_SP_HARDWARE_GREEN,
2812 EL_SP_HARDWARE_BLUE,
2814 EL_SP_HARDWARE_YELLOW,
2815 EL_SP_HARDWARE_BASE_1,
2816 EL_SP_HARDWARE_BASE_2,
2817 EL_SP_HARDWARE_BASE_3,
2818 EL_SP_HARDWARE_BASE_4,
2819 EL_SP_HARDWARE_BASE_5,
2820 EL_SP_HARDWARE_BASE_6,
2821 EL_INVISIBLE_STEELWALL,
2822 EL_INVISIBLE_STEELWALL_ACTIVE,
2823 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2824 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2825 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2826 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2827 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2828 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2829 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2830 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2831 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2832 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2833 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2834 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2836 EL_LIGHT_SWITCH_ACTIVE,
2837 EL_SIGN_EXCLAMATION,
2838 EL_SIGN_RADIOACTIVITY,
2845 EL_SIGN_ENTRY_FORBIDDEN,
2846 EL_SIGN_EMERGENCY_EXIT,
2854 EL_STEEL_EXIT_CLOSED,
2856 EL_STEEL_EXIT_OPENING,
2857 EL_STEEL_EXIT_CLOSING,
2858 EL_EM_STEEL_EXIT_CLOSED,
2859 EL_EM_STEEL_EXIT_OPEN,
2860 EL_EM_STEEL_EXIT_OPENING,
2861 EL_EM_STEEL_EXIT_CLOSING,
2862 EL_DC_STEELWALL_1_LEFT,
2863 EL_DC_STEELWALL_1_RIGHT,
2864 EL_DC_STEELWALL_1_TOP,
2865 EL_DC_STEELWALL_1_BOTTOM,
2866 EL_DC_STEELWALL_1_HORIZONTAL,
2867 EL_DC_STEELWALL_1_VERTICAL,
2868 EL_DC_STEELWALL_1_TOPLEFT,
2869 EL_DC_STEELWALL_1_TOPRIGHT,
2870 EL_DC_STEELWALL_1_BOTTOMLEFT,
2871 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2872 EL_DC_STEELWALL_1_TOPLEFT_2,
2873 EL_DC_STEELWALL_1_TOPRIGHT_2,
2874 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2875 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2876 EL_DC_STEELWALL_2_LEFT,
2877 EL_DC_STEELWALL_2_RIGHT,
2878 EL_DC_STEELWALL_2_TOP,
2879 EL_DC_STEELWALL_2_BOTTOM,
2880 EL_DC_STEELWALL_2_HORIZONTAL,
2881 EL_DC_STEELWALL_2_VERTICAL,
2882 EL_DC_STEELWALL_2_MIDDLE,
2883 EL_DC_STEELWALL_2_SINGLE,
2884 EL_STEELWALL_SLIPPERY,
2898 EL_GATE_1_GRAY_ACTIVE,
2899 EL_GATE_2_GRAY_ACTIVE,
2900 EL_GATE_3_GRAY_ACTIVE,
2901 EL_GATE_4_GRAY_ACTIVE,
2910 EL_EM_GATE_1_GRAY_ACTIVE,
2911 EL_EM_GATE_2_GRAY_ACTIVE,
2912 EL_EM_GATE_3_GRAY_ACTIVE,
2913 EL_EM_GATE_4_GRAY_ACTIVE,
2922 EL_EMC_GATE_5_GRAY_ACTIVE,
2923 EL_EMC_GATE_6_GRAY_ACTIVE,
2924 EL_EMC_GATE_7_GRAY_ACTIVE,
2925 EL_EMC_GATE_8_GRAY_ACTIVE,
2927 EL_DC_GATE_WHITE_GRAY,
2928 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2929 EL_DC_GATE_FAKE_GRAY,
2931 EL_SWITCHGATE_OPENING,
2932 EL_SWITCHGATE_CLOSED,
2933 EL_SWITCHGATE_CLOSING,
2935 EL_DC_SWITCHGATE_SWITCH_UP,
2936 EL_DC_SWITCHGATE_SWITCH_DOWN,
2939 EL_TIMEGATE_OPENING,
2941 EL_TIMEGATE_CLOSING,
2943 EL_DC_TIMEGATE_SWITCH,
2944 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2949 EL_TUBE_VERTICAL_LEFT,
2950 EL_TUBE_VERTICAL_RIGHT,
2951 EL_TUBE_HORIZONTAL_UP,
2952 EL_TUBE_HORIZONTAL_DOWN,
2957 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2958 EL_EXPANDABLE_STEELWALL_VERTICAL,
2959 EL_EXPANDABLE_STEELWALL_ANY,
2964 static int ep_slippery[] =
2978 EL_ROBOT_WHEEL_ACTIVE,
2984 EL_ACID_POOL_TOPLEFT,
2985 EL_ACID_POOL_TOPRIGHT,
2995 EL_STEELWALL_SLIPPERY,
2998 EL_EMC_WALL_SLIPPERY_1,
2999 EL_EMC_WALL_SLIPPERY_2,
3000 EL_EMC_WALL_SLIPPERY_3,
3001 EL_EMC_WALL_SLIPPERY_4,
3003 EL_EMC_MAGIC_BALL_ACTIVE,
3008 static int ep_can_change[] =
3013 static int ep_can_move[] =
3015 /* same elements as in 'pb_can_move_into_acid' */
3038 static int ep_can_fall[] =
3052 EL_QUICKSAND_FAST_FULL,
3054 EL_BD_MAGIC_WALL_FULL,
3055 EL_DC_MAGIC_WALL_FULL,
3069 static int ep_can_smash_player[] =
3095 static int ep_can_smash_enemies[] =
3104 static int ep_can_smash_everything[] =
3113 static int ep_explodes_by_fire[] =
3115 /* same elements as in 'ep_explodes_impact' */
3120 /* same elements as in 'ep_explodes_smashed' */
3130 EL_EM_DYNAMITE_ACTIVE,
3131 EL_DYNABOMB_PLAYER_1_ACTIVE,
3132 EL_DYNABOMB_PLAYER_2_ACTIVE,
3133 EL_DYNABOMB_PLAYER_3_ACTIVE,
3134 EL_DYNABOMB_PLAYER_4_ACTIVE,
3135 EL_DYNABOMB_INCREASE_NUMBER,
3136 EL_DYNABOMB_INCREASE_SIZE,
3137 EL_DYNABOMB_INCREASE_POWER,
3138 EL_SP_DISK_RED_ACTIVE,
3152 static int ep_explodes_smashed[] =
3154 /* same elements as in 'ep_explodes_impact' */
3168 static int ep_explodes_impact[] =
3177 static int ep_walkable_over[] =
3181 EL_SOKOBAN_FIELD_EMPTY,
3190 EL_EM_STEEL_EXIT_OPEN,
3192 EL_EM_STEEL_EXIT_OPENING,
3202 EL_GATE_1_GRAY_ACTIVE,
3203 EL_GATE_2_GRAY_ACTIVE,
3204 EL_GATE_3_GRAY_ACTIVE,
3205 EL_GATE_4_GRAY_ACTIVE,
3213 static int ep_walkable_inside[] =
3218 EL_TUBE_VERTICAL_LEFT,
3219 EL_TUBE_VERTICAL_RIGHT,
3220 EL_TUBE_HORIZONTAL_UP,
3221 EL_TUBE_HORIZONTAL_DOWN,
3230 static int ep_walkable_under[] =
3235 static int ep_passable_over[] =
3245 EL_EM_GATE_1_GRAY_ACTIVE,
3246 EL_EM_GATE_2_GRAY_ACTIVE,
3247 EL_EM_GATE_3_GRAY_ACTIVE,
3248 EL_EM_GATE_4_GRAY_ACTIVE,
3257 EL_EMC_GATE_5_GRAY_ACTIVE,
3258 EL_EMC_GATE_6_GRAY_ACTIVE,
3259 EL_EMC_GATE_7_GRAY_ACTIVE,
3260 EL_EMC_GATE_8_GRAY_ACTIVE,
3262 EL_DC_GATE_WHITE_GRAY,
3263 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3270 static int ep_passable_inside[] =
3276 EL_SP_PORT_HORIZONTAL,
3277 EL_SP_PORT_VERTICAL,
3279 EL_SP_GRAVITY_PORT_LEFT,
3280 EL_SP_GRAVITY_PORT_RIGHT,
3281 EL_SP_GRAVITY_PORT_UP,
3282 EL_SP_GRAVITY_PORT_DOWN,
3283 EL_SP_GRAVITY_ON_PORT_LEFT,
3284 EL_SP_GRAVITY_ON_PORT_RIGHT,
3285 EL_SP_GRAVITY_ON_PORT_UP,
3286 EL_SP_GRAVITY_ON_PORT_DOWN,
3287 EL_SP_GRAVITY_OFF_PORT_LEFT,
3288 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3289 EL_SP_GRAVITY_OFF_PORT_UP,
3290 EL_SP_GRAVITY_OFF_PORT_DOWN,
3295 static int ep_passable_under[] =
3300 static int ep_droppable[] =
3305 static int ep_explodes_1x1_old[] =
3310 static int ep_pushable[] =
3322 EL_SOKOBAN_FIELD_FULL,
3331 static int ep_explodes_cross_old[] =
3336 static int ep_protected[] =
3338 /* same elements as in 'ep_walkable_inside' */
3342 EL_TUBE_VERTICAL_LEFT,
3343 EL_TUBE_VERTICAL_RIGHT,
3344 EL_TUBE_HORIZONTAL_UP,
3345 EL_TUBE_HORIZONTAL_DOWN,
3351 /* same elements as in 'ep_passable_over' */
3360 EL_EM_GATE_1_GRAY_ACTIVE,
3361 EL_EM_GATE_2_GRAY_ACTIVE,
3362 EL_EM_GATE_3_GRAY_ACTIVE,
3363 EL_EM_GATE_4_GRAY_ACTIVE,
3372 EL_EMC_GATE_5_GRAY_ACTIVE,
3373 EL_EMC_GATE_6_GRAY_ACTIVE,
3374 EL_EMC_GATE_7_GRAY_ACTIVE,
3375 EL_EMC_GATE_8_GRAY_ACTIVE,
3377 EL_DC_GATE_WHITE_GRAY,
3378 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3382 /* same elements as in 'ep_passable_inside' */
3387 EL_SP_PORT_HORIZONTAL,
3388 EL_SP_PORT_VERTICAL,
3390 EL_SP_GRAVITY_PORT_LEFT,
3391 EL_SP_GRAVITY_PORT_RIGHT,
3392 EL_SP_GRAVITY_PORT_UP,
3393 EL_SP_GRAVITY_PORT_DOWN,
3394 EL_SP_GRAVITY_ON_PORT_LEFT,
3395 EL_SP_GRAVITY_ON_PORT_RIGHT,
3396 EL_SP_GRAVITY_ON_PORT_UP,
3397 EL_SP_GRAVITY_ON_PORT_DOWN,
3398 EL_SP_GRAVITY_OFF_PORT_LEFT,
3399 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3400 EL_SP_GRAVITY_OFF_PORT_UP,
3401 EL_SP_GRAVITY_OFF_PORT_DOWN,
3406 static int ep_throwable[] =
3411 static int ep_can_explode[] =
3413 /* same elements as in 'ep_explodes_impact' */
3418 /* same elements as in 'ep_explodes_smashed' */
3424 /* elements that can explode by explosion or by dragonfire */
3428 EL_EM_DYNAMITE_ACTIVE,
3429 EL_DYNABOMB_PLAYER_1_ACTIVE,
3430 EL_DYNABOMB_PLAYER_2_ACTIVE,
3431 EL_DYNABOMB_PLAYER_3_ACTIVE,
3432 EL_DYNABOMB_PLAYER_4_ACTIVE,
3433 EL_DYNABOMB_INCREASE_NUMBER,
3434 EL_DYNABOMB_INCREASE_SIZE,
3435 EL_DYNABOMB_INCREASE_POWER,
3436 EL_SP_DISK_RED_ACTIVE,
3444 /* elements that can explode only by explosion */
3450 static int ep_gravity_reachable[] =
3456 EL_INVISIBLE_SAND_ACTIVE,
3461 EL_SP_PORT_HORIZONTAL,
3462 EL_SP_PORT_VERTICAL,
3464 EL_SP_GRAVITY_PORT_LEFT,
3465 EL_SP_GRAVITY_PORT_RIGHT,
3466 EL_SP_GRAVITY_PORT_UP,
3467 EL_SP_GRAVITY_PORT_DOWN,
3468 EL_SP_GRAVITY_ON_PORT_LEFT,
3469 EL_SP_GRAVITY_ON_PORT_RIGHT,
3470 EL_SP_GRAVITY_ON_PORT_UP,
3471 EL_SP_GRAVITY_ON_PORT_DOWN,
3472 EL_SP_GRAVITY_OFF_PORT_LEFT,
3473 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3474 EL_SP_GRAVITY_OFF_PORT_UP,
3475 EL_SP_GRAVITY_OFF_PORT_DOWN,
3481 static int ep_player[] =
3488 EL_SOKOBAN_FIELD_PLAYER,
3494 static int ep_can_pass_magic_wall[] =
3508 static int ep_can_pass_dc_magic_wall[] =
3524 static int ep_switchable[] =
3528 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3529 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3530 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3531 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3532 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3533 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3534 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3535 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3536 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3537 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3538 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3539 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3540 EL_SWITCHGATE_SWITCH_UP,
3541 EL_SWITCHGATE_SWITCH_DOWN,
3542 EL_DC_SWITCHGATE_SWITCH_UP,
3543 EL_DC_SWITCHGATE_SWITCH_DOWN,
3545 EL_LIGHT_SWITCH_ACTIVE,
3547 EL_DC_TIMEGATE_SWITCH,
3548 EL_BALLOON_SWITCH_LEFT,
3549 EL_BALLOON_SWITCH_RIGHT,
3550 EL_BALLOON_SWITCH_UP,
3551 EL_BALLOON_SWITCH_DOWN,
3552 EL_BALLOON_SWITCH_ANY,
3553 EL_BALLOON_SWITCH_NONE,
3556 EL_EMC_MAGIC_BALL_SWITCH,
3557 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3562 static int ep_bd_element[] =
3596 static int ep_sp_element[] =
3598 /* should always be valid */
3601 /* standard classic Supaplex elements */
3608 EL_SP_HARDWARE_GRAY,
3616 EL_SP_GRAVITY_PORT_RIGHT,
3617 EL_SP_GRAVITY_PORT_DOWN,
3618 EL_SP_GRAVITY_PORT_LEFT,
3619 EL_SP_GRAVITY_PORT_UP,
3624 EL_SP_PORT_VERTICAL,
3625 EL_SP_PORT_HORIZONTAL,
3631 EL_SP_HARDWARE_BASE_1,
3632 EL_SP_HARDWARE_GREEN,
3633 EL_SP_HARDWARE_BLUE,
3635 EL_SP_HARDWARE_YELLOW,
3636 EL_SP_HARDWARE_BASE_2,
3637 EL_SP_HARDWARE_BASE_3,
3638 EL_SP_HARDWARE_BASE_4,
3639 EL_SP_HARDWARE_BASE_5,
3640 EL_SP_HARDWARE_BASE_6,
3644 /* additional elements that appeared in newer Supaplex levels */
3647 /* additional gravity port elements (not switching, but setting gravity) */
3648 EL_SP_GRAVITY_ON_PORT_LEFT,
3649 EL_SP_GRAVITY_ON_PORT_RIGHT,
3650 EL_SP_GRAVITY_ON_PORT_UP,
3651 EL_SP_GRAVITY_ON_PORT_DOWN,
3652 EL_SP_GRAVITY_OFF_PORT_LEFT,
3653 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3654 EL_SP_GRAVITY_OFF_PORT_UP,
3655 EL_SP_GRAVITY_OFF_PORT_DOWN,
3657 /* more than one Murphy in a level results in an inactive clone */
3660 /* runtime Supaplex elements */
3661 EL_SP_DISK_RED_ACTIVE,
3662 EL_SP_TERMINAL_ACTIVE,
3663 EL_SP_BUGGY_BASE_ACTIVATING,
3664 EL_SP_BUGGY_BASE_ACTIVE,
3671 static int ep_sb_element[] =
3676 EL_SOKOBAN_FIELD_EMPTY,
3677 EL_SOKOBAN_FIELD_FULL,
3678 EL_SOKOBAN_FIELD_PLAYER,
3683 EL_INVISIBLE_STEELWALL,
3688 static int ep_gem[] =
3700 static int ep_food_dark_yamyam[] =
3728 static int ep_food_penguin[] =
3742 static int ep_food_pig[] =
3754 static int ep_historic_wall[] =
3765 EL_GATE_1_GRAY_ACTIVE,
3766 EL_GATE_2_GRAY_ACTIVE,
3767 EL_GATE_3_GRAY_ACTIVE,
3768 EL_GATE_4_GRAY_ACTIVE,
3777 EL_EM_GATE_1_GRAY_ACTIVE,
3778 EL_EM_GATE_2_GRAY_ACTIVE,
3779 EL_EM_GATE_3_GRAY_ACTIVE,
3780 EL_EM_GATE_4_GRAY_ACTIVE,
3787 EL_EXPANDABLE_WALL_HORIZONTAL,
3788 EL_EXPANDABLE_WALL_VERTICAL,
3789 EL_EXPANDABLE_WALL_ANY,
3790 EL_EXPANDABLE_WALL_GROWING,
3791 EL_BD_EXPANDABLE_WALL,
3798 EL_SP_HARDWARE_GRAY,
3799 EL_SP_HARDWARE_GREEN,
3800 EL_SP_HARDWARE_BLUE,
3802 EL_SP_HARDWARE_YELLOW,
3803 EL_SP_HARDWARE_BASE_1,
3804 EL_SP_HARDWARE_BASE_2,
3805 EL_SP_HARDWARE_BASE_3,
3806 EL_SP_HARDWARE_BASE_4,
3807 EL_SP_HARDWARE_BASE_5,
3808 EL_SP_HARDWARE_BASE_6,
3810 EL_SP_TERMINAL_ACTIVE,
3813 EL_INVISIBLE_STEELWALL,
3814 EL_INVISIBLE_STEELWALL_ACTIVE,
3816 EL_INVISIBLE_WALL_ACTIVE,
3817 EL_STEELWALL_SLIPPERY,
3834 static int ep_historic_solid[] =
3838 EL_EXPANDABLE_WALL_HORIZONTAL,
3839 EL_EXPANDABLE_WALL_VERTICAL,
3840 EL_EXPANDABLE_WALL_ANY,
3841 EL_BD_EXPANDABLE_WALL,
3854 EL_QUICKSAND_FILLING,
3855 EL_QUICKSAND_EMPTYING,
3857 EL_MAGIC_WALL_ACTIVE,
3858 EL_MAGIC_WALL_EMPTYING,
3859 EL_MAGIC_WALL_FILLING,
3863 EL_BD_MAGIC_WALL_ACTIVE,
3864 EL_BD_MAGIC_WALL_EMPTYING,
3865 EL_BD_MAGIC_WALL_FULL,
3866 EL_BD_MAGIC_WALL_FILLING,
3867 EL_BD_MAGIC_WALL_DEAD,
3876 EL_SP_TERMINAL_ACTIVE,
3880 EL_INVISIBLE_WALL_ACTIVE,
3881 EL_SWITCHGATE_SWITCH_UP,
3882 EL_SWITCHGATE_SWITCH_DOWN,
3883 EL_DC_SWITCHGATE_SWITCH_UP,
3884 EL_DC_SWITCHGATE_SWITCH_DOWN,
3886 EL_TIMEGATE_SWITCH_ACTIVE,
3887 EL_DC_TIMEGATE_SWITCH,
3888 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3900 /* the following elements are a direct copy of "indestructible" elements,
3901 except "EL_ACID", which is "indestructible", but not "solid"! */
3906 EL_ACID_POOL_TOPLEFT,
3907 EL_ACID_POOL_TOPRIGHT,
3908 EL_ACID_POOL_BOTTOMLEFT,
3909 EL_ACID_POOL_BOTTOM,
3910 EL_ACID_POOL_BOTTOMRIGHT,
3911 EL_SP_HARDWARE_GRAY,
3912 EL_SP_HARDWARE_GREEN,
3913 EL_SP_HARDWARE_BLUE,
3915 EL_SP_HARDWARE_YELLOW,
3916 EL_SP_HARDWARE_BASE_1,
3917 EL_SP_HARDWARE_BASE_2,
3918 EL_SP_HARDWARE_BASE_3,
3919 EL_SP_HARDWARE_BASE_4,
3920 EL_SP_HARDWARE_BASE_5,
3921 EL_SP_HARDWARE_BASE_6,
3922 EL_INVISIBLE_STEELWALL,
3923 EL_INVISIBLE_STEELWALL_ACTIVE,
3924 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3925 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3926 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3927 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3928 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3929 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3930 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3931 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3932 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3933 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3934 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3935 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3937 EL_LIGHT_SWITCH_ACTIVE,
3938 EL_SIGN_EXCLAMATION,
3939 EL_SIGN_RADIOACTIVITY,
3946 EL_SIGN_ENTRY_FORBIDDEN,
3947 EL_SIGN_EMERGENCY_EXIT,
3955 EL_STEEL_EXIT_CLOSED,
3957 EL_DC_STEELWALL_1_LEFT,
3958 EL_DC_STEELWALL_1_RIGHT,
3959 EL_DC_STEELWALL_1_TOP,
3960 EL_DC_STEELWALL_1_BOTTOM,
3961 EL_DC_STEELWALL_1_HORIZONTAL,
3962 EL_DC_STEELWALL_1_VERTICAL,
3963 EL_DC_STEELWALL_1_TOPLEFT,
3964 EL_DC_STEELWALL_1_TOPRIGHT,
3965 EL_DC_STEELWALL_1_BOTTOMLEFT,
3966 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3967 EL_DC_STEELWALL_1_TOPLEFT_2,
3968 EL_DC_STEELWALL_1_TOPRIGHT_2,
3969 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3970 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3971 EL_DC_STEELWALL_2_LEFT,
3972 EL_DC_STEELWALL_2_RIGHT,
3973 EL_DC_STEELWALL_2_TOP,
3974 EL_DC_STEELWALL_2_BOTTOM,
3975 EL_DC_STEELWALL_2_HORIZONTAL,
3976 EL_DC_STEELWALL_2_VERTICAL,
3977 EL_DC_STEELWALL_2_MIDDLE,
3978 EL_DC_STEELWALL_2_SINGLE,
3979 EL_STEELWALL_SLIPPERY,
3993 EL_GATE_1_GRAY_ACTIVE,
3994 EL_GATE_2_GRAY_ACTIVE,
3995 EL_GATE_3_GRAY_ACTIVE,
3996 EL_GATE_4_GRAY_ACTIVE,
4005 EL_EM_GATE_1_GRAY_ACTIVE,
4006 EL_EM_GATE_2_GRAY_ACTIVE,
4007 EL_EM_GATE_3_GRAY_ACTIVE,
4008 EL_EM_GATE_4_GRAY_ACTIVE,
4010 EL_SWITCHGATE_OPENING,
4011 EL_SWITCHGATE_CLOSED,
4012 EL_SWITCHGATE_CLOSING,
4014 EL_TIMEGATE_OPENING,
4016 EL_TIMEGATE_CLOSING,
4020 EL_TUBE_VERTICAL_LEFT,
4021 EL_TUBE_VERTICAL_RIGHT,
4022 EL_TUBE_HORIZONTAL_UP,
4023 EL_TUBE_HORIZONTAL_DOWN,
4032 static int ep_classic_enemy[] =
4049 static int ep_belt[] =
4051 EL_CONVEYOR_BELT_1_LEFT,
4052 EL_CONVEYOR_BELT_1_MIDDLE,
4053 EL_CONVEYOR_BELT_1_RIGHT,
4054 EL_CONVEYOR_BELT_2_LEFT,
4055 EL_CONVEYOR_BELT_2_MIDDLE,
4056 EL_CONVEYOR_BELT_2_RIGHT,
4057 EL_CONVEYOR_BELT_3_LEFT,
4058 EL_CONVEYOR_BELT_3_MIDDLE,
4059 EL_CONVEYOR_BELT_3_RIGHT,
4060 EL_CONVEYOR_BELT_4_LEFT,
4061 EL_CONVEYOR_BELT_4_MIDDLE,
4062 EL_CONVEYOR_BELT_4_RIGHT,
4067 static int ep_belt_active[] =
4069 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
4070 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
4071 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
4072 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
4073 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
4074 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
4075 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
4076 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
4077 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
4078 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
4079 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
4080 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
4085 static int ep_belt_switch[] =
4087 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4088 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4089 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4090 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4091 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4092 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4093 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4094 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4095 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4096 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4097 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4098 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4103 static int ep_tube[] =
4110 EL_TUBE_HORIZONTAL_UP,
4111 EL_TUBE_HORIZONTAL_DOWN,
4113 EL_TUBE_VERTICAL_LEFT,
4114 EL_TUBE_VERTICAL_RIGHT,
4120 static int ep_acid_pool[] =
4122 EL_ACID_POOL_TOPLEFT,
4123 EL_ACID_POOL_TOPRIGHT,
4124 EL_ACID_POOL_BOTTOMLEFT,
4125 EL_ACID_POOL_BOTTOM,
4126 EL_ACID_POOL_BOTTOMRIGHT,
4131 static int ep_keygate[] =
4141 EL_GATE_1_GRAY_ACTIVE,
4142 EL_GATE_2_GRAY_ACTIVE,
4143 EL_GATE_3_GRAY_ACTIVE,
4144 EL_GATE_4_GRAY_ACTIVE,
4153 EL_EM_GATE_1_GRAY_ACTIVE,
4154 EL_EM_GATE_2_GRAY_ACTIVE,
4155 EL_EM_GATE_3_GRAY_ACTIVE,
4156 EL_EM_GATE_4_GRAY_ACTIVE,
4165 EL_EMC_GATE_5_GRAY_ACTIVE,
4166 EL_EMC_GATE_6_GRAY_ACTIVE,
4167 EL_EMC_GATE_7_GRAY_ACTIVE,
4168 EL_EMC_GATE_8_GRAY_ACTIVE,
4170 EL_DC_GATE_WHITE_GRAY,
4171 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4176 static int ep_amoeboid[] =
4188 static int ep_amoebalive[] =
4199 static int ep_has_editor_content[] =
4205 EL_SOKOBAN_FIELD_PLAYER,
4222 static int ep_can_turn_each_move[] =
4224 /* !!! do something with this one !!! */
4228 static int ep_can_grow[] =
4242 static int ep_active_bomb[] =
4245 EL_EM_DYNAMITE_ACTIVE,
4246 EL_DYNABOMB_PLAYER_1_ACTIVE,
4247 EL_DYNABOMB_PLAYER_2_ACTIVE,
4248 EL_DYNABOMB_PLAYER_3_ACTIVE,
4249 EL_DYNABOMB_PLAYER_4_ACTIVE,
4250 EL_SP_DISK_RED_ACTIVE,
4255 static int ep_inactive[] =
4265 EL_QUICKSAND_FAST_EMPTY,
4288 EL_GATE_1_GRAY_ACTIVE,
4289 EL_GATE_2_GRAY_ACTIVE,
4290 EL_GATE_3_GRAY_ACTIVE,
4291 EL_GATE_4_GRAY_ACTIVE,
4300 EL_EM_GATE_1_GRAY_ACTIVE,
4301 EL_EM_GATE_2_GRAY_ACTIVE,
4302 EL_EM_GATE_3_GRAY_ACTIVE,
4303 EL_EM_GATE_4_GRAY_ACTIVE,
4312 EL_EMC_GATE_5_GRAY_ACTIVE,
4313 EL_EMC_GATE_6_GRAY_ACTIVE,
4314 EL_EMC_GATE_7_GRAY_ACTIVE,
4315 EL_EMC_GATE_8_GRAY_ACTIVE,
4317 EL_DC_GATE_WHITE_GRAY,
4318 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4319 EL_DC_GATE_FAKE_GRAY,
4322 EL_INVISIBLE_STEELWALL,
4330 EL_WALL_EMERALD_YELLOW,
4331 EL_DYNABOMB_INCREASE_NUMBER,
4332 EL_DYNABOMB_INCREASE_SIZE,
4333 EL_DYNABOMB_INCREASE_POWER,
4337 EL_SOKOBAN_FIELD_EMPTY,
4338 EL_SOKOBAN_FIELD_FULL,
4339 EL_WALL_EMERALD_RED,
4340 EL_WALL_EMERALD_PURPLE,
4341 EL_ACID_POOL_TOPLEFT,
4342 EL_ACID_POOL_TOPRIGHT,
4343 EL_ACID_POOL_BOTTOMLEFT,
4344 EL_ACID_POOL_BOTTOM,
4345 EL_ACID_POOL_BOTTOMRIGHT,
4349 EL_BD_MAGIC_WALL_DEAD,
4351 EL_DC_MAGIC_WALL_DEAD,
4352 EL_AMOEBA_TO_DIAMOND,
4360 EL_SP_GRAVITY_PORT_RIGHT,
4361 EL_SP_GRAVITY_PORT_DOWN,
4362 EL_SP_GRAVITY_PORT_LEFT,
4363 EL_SP_GRAVITY_PORT_UP,
4364 EL_SP_PORT_HORIZONTAL,
4365 EL_SP_PORT_VERTICAL,
4376 EL_SP_HARDWARE_GRAY,
4377 EL_SP_HARDWARE_GREEN,
4378 EL_SP_HARDWARE_BLUE,
4380 EL_SP_HARDWARE_YELLOW,
4381 EL_SP_HARDWARE_BASE_1,
4382 EL_SP_HARDWARE_BASE_2,
4383 EL_SP_HARDWARE_BASE_3,
4384 EL_SP_HARDWARE_BASE_4,
4385 EL_SP_HARDWARE_BASE_5,
4386 EL_SP_HARDWARE_BASE_6,
4387 EL_SP_GRAVITY_ON_PORT_LEFT,
4388 EL_SP_GRAVITY_ON_PORT_RIGHT,
4389 EL_SP_GRAVITY_ON_PORT_UP,
4390 EL_SP_GRAVITY_ON_PORT_DOWN,
4391 EL_SP_GRAVITY_OFF_PORT_LEFT,
4392 EL_SP_GRAVITY_OFF_PORT_RIGHT,
4393 EL_SP_GRAVITY_OFF_PORT_UP,
4394 EL_SP_GRAVITY_OFF_PORT_DOWN,
4395 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4396 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4397 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4398 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4399 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4400 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4401 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4402 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4403 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4404 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4405 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4406 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4407 EL_SIGN_EXCLAMATION,
4408 EL_SIGN_RADIOACTIVITY,
4415 EL_SIGN_ENTRY_FORBIDDEN,
4416 EL_SIGN_EMERGENCY_EXIT,
4424 EL_DC_STEELWALL_1_LEFT,
4425 EL_DC_STEELWALL_1_RIGHT,
4426 EL_DC_STEELWALL_1_TOP,
4427 EL_DC_STEELWALL_1_BOTTOM,
4428 EL_DC_STEELWALL_1_HORIZONTAL,
4429 EL_DC_STEELWALL_1_VERTICAL,
4430 EL_DC_STEELWALL_1_TOPLEFT,
4431 EL_DC_STEELWALL_1_TOPRIGHT,
4432 EL_DC_STEELWALL_1_BOTTOMLEFT,
4433 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4434 EL_DC_STEELWALL_1_TOPLEFT_2,
4435 EL_DC_STEELWALL_1_TOPRIGHT_2,
4436 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4437 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4438 EL_DC_STEELWALL_2_LEFT,
4439 EL_DC_STEELWALL_2_RIGHT,
4440 EL_DC_STEELWALL_2_TOP,
4441 EL_DC_STEELWALL_2_BOTTOM,
4442 EL_DC_STEELWALL_2_HORIZONTAL,
4443 EL_DC_STEELWALL_2_VERTICAL,
4444 EL_DC_STEELWALL_2_MIDDLE,
4445 EL_DC_STEELWALL_2_SINGLE,
4446 EL_STEELWALL_SLIPPERY,
4451 EL_EMC_WALL_SLIPPERY_1,
4452 EL_EMC_WALL_SLIPPERY_2,
4453 EL_EMC_WALL_SLIPPERY_3,
4454 EL_EMC_WALL_SLIPPERY_4,
4475 static int ep_em_slippery_wall[] =
4480 static int ep_gfx_crumbled[] =
4491 static int ep_editor_cascade_active[] =
4493 EL_INTERNAL_CASCADE_BD_ACTIVE,
4494 EL_INTERNAL_CASCADE_EM_ACTIVE,
4495 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4496 EL_INTERNAL_CASCADE_RND_ACTIVE,
4497 EL_INTERNAL_CASCADE_SB_ACTIVE,
4498 EL_INTERNAL_CASCADE_SP_ACTIVE,
4499 EL_INTERNAL_CASCADE_DC_ACTIVE,
4500 EL_INTERNAL_CASCADE_DX_ACTIVE,
4501 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4502 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4503 EL_INTERNAL_CASCADE_CE_ACTIVE,
4504 EL_INTERNAL_CASCADE_GE_ACTIVE,
4505 EL_INTERNAL_CASCADE_REF_ACTIVE,
4506 EL_INTERNAL_CASCADE_USER_ACTIVE,
4507 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4512 static int ep_editor_cascade_inactive[] =
4514 EL_INTERNAL_CASCADE_BD,
4515 EL_INTERNAL_CASCADE_EM,
4516 EL_INTERNAL_CASCADE_EMC,
4517 EL_INTERNAL_CASCADE_RND,
4518 EL_INTERNAL_CASCADE_SB,
4519 EL_INTERNAL_CASCADE_SP,
4520 EL_INTERNAL_CASCADE_DC,
4521 EL_INTERNAL_CASCADE_DX,
4522 EL_INTERNAL_CASCADE_CHARS,
4523 EL_INTERNAL_CASCADE_STEEL_CHARS,
4524 EL_INTERNAL_CASCADE_CE,
4525 EL_INTERNAL_CASCADE_GE,
4526 EL_INTERNAL_CASCADE_REF,
4527 EL_INTERNAL_CASCADE_USER,
4528 EL_INTERNAL_CASCADE_DYNAMIC,
4533 static int ep_obsolete[] =
4537 EL_EM_KEY_1_FILE_OBSOLETE,
4538 EL_EM_KEY_2_FILE_OBSOLETE,
4539 EL_EM_KEY_3_FILE_OBSOLETE,
4540 EL_EM_KEY_4_FILE_OBSOLETE,
4541 EL_ENVELOPE_OBSOLETE,
4550 } element_properties[] =
4552 { ep_diggable, EP_DIGGABLE },
4553 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4554 { ep_dont_run_into, EP_DONT_RUN_INTO },
4555 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4556 { ep_dont_touch, EP_DONT_TOUCH },
4557 { ep_indestructible, EP_INDESTRUCTIBLE },
4558 { ep_slippery, EP_SLIPPERY },
4559 { ep_can_change, EP_CAN_CHANGE },
4560 { ep_can_move, EP_CAN_MOVE },
4561 { ep_can_fall, EP_CAN_FALL },
4562 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4563 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4564 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4565 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4566 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4567 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4568 { ep_walkable_over, EP_WALKABLE_OVER },
4569 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4570 { ep_walkable_under, EP_WALKABLE_UNDER },
4571 { ep_passable_over, EP_PASSABLE_OVER },
4572 { ep_passable_inside, EP_PASSABLE_INSIDE },
4573 { ep_passable_under, EP_PASSABLE_UNDER },
4574 { ep_droppable, EP_DROPPABLE },
4575 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4576 { ep_pushable, EP_PUSHABLE },
4577 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4578 { ep_protected, EP_PROTECTED },
4579 { ep_throwable, EP_THROWABLE },
4580 { ep_can_explode, EP_CAN_EXPLODE },
4581 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4583 { ep_player, EP_PLAYER },
4584 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4585 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4586 { ep_switchable, EP_SWITCHABLE },
4587 { ep_bd_element, EP_BD_ELEMENT },
4588 { ep_sp_element, EP_SP_ELEMENT },
4589 { ep_sb_element, EP_SB_ELEMENT },
4591 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4592 { ep_food_penguin, EP_FOOD_PENGUIN },
4593 { ep_food_pig, EP_FOOD_PIG },
4594 { ep_historic_wall, EP_HISTORIC_WALL },
4595 { ep_historic_solid, EP_HISTORIC_SOLID },
4596 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4597 { ep_belt, EP_BELT },
4598 { ep_belt_active, EP_BELT_ACTIVE },
4599 { ep_belt_switch, EP_BELT_SWITCH },
4600 { ep_tube, EP_TUBE },
4601 { ep_acid_pool, EP_ACID_POOL },
4602 { ep_keygate, EP_KEYGATE },
4603 { ep_amoeboid, EP_AMOEBOID },
4604 { ep_amoebalive, EP_AMOEBALIVE },
4605 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4606 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4607 { ep_can_grow, EP_CAN_GROW },
4608 { ep_active_bomb, EP_ACTIVE_BOMB },
4609 { ep_inactive, EP_INACTIVE },
4611 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4613 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4615 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4616 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4618 { ep_obsolete, EP_OBSOLETE },
4625 /* always start with reliable default values (element has no properties) */
4626 /* (but never initialize clipboard elements after the very first time) */
4627 /* (to be able to use clipboard elements between several levels) */
4628 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4629 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4630 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4631 SET_PROPERTY(i, j, FALSE);
4633 /* set all base element properties from above array definitions */
4634 for (i = 0; element_properties[i].elements != NULL; i++)
4635 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4636 SET_PROPERTY((element_properties[i].elements)[j],
4637 element_properties[i].property, TRUE);
4639 /* copy properties to some elements that are only stored in level file */
4640 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4641 for (j = 0; copy_properties[j][0] != -1; j++)
4642 if (HAS_PROPERTY(copy_properties[j][0], i))
4643 for (k = 1; k <= 4; k++)
4644 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4646 /* set static element properties that are not listed in array definitions */
4647 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4648 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4650 clipboard_elements_initialized = TRUE;
4653 void InitElementPropertiesEngine(int engine_version)
4655 static int no_wall_properties[] =
4658 EP_COLLECTIBLE_ONLY,
4660 EP_DONT_COLLIDE_WITH,
4663 EP_CAN_SMASH_PLAYER,
4664 EP_CAN_SMASH_ENEMIES,
4665 EP_CAN_SMASH_EVERYTHING,
4670 EP_FOOD_DARK_YAMYAM,
4686 /* important: after initialization in InitElementPropertiesStatic(), the
4687 elements are not again initialized to a default value; therefore all
4688 changes have to make sure that they leave the element with a defined
4689 property (which means that conditional property changes must be set to
4690 a reliable default value before) */
4692 /* resolve group elements */
4693 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4694 ResolveGroupElement(EL_GROUP_START + i);
4696 /* set all special, combined or engine dependent element properties */
4697 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4699 /* do not change (already initialized) clipboard elements here */
4700 if (IS_CLIPBOARD_ELEMENT(i))
4703 /* ---------- INACTIVE ------------------------------------------------- */
4704 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4705 i <= EL_CHAR_END) ||
4706 (i >= EL_STEEL_CHAR_START &&
4707 i <= EL_STEEL_CHAR_END)));
4709 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4710 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4711 IS_WALKABLE_INSIDE(i) ||
4712 IS_WALKABLE_UNDER(i)));
4714 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4715 IS_PASSABLE_INSIDE(i) ||
4716 IS_PASSABLE_UNDER(i)));
4718 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4719 IS_PASSABLE_OVER(i)));
4721 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4722 IS_PASSABLE_INSIDE(i)));
4724 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4725 IS_PASSABLE_UNDER(i)));
4727 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4730 /* ---------- COLLECTIBLE ---------------------------------------------- */
4731 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4735 /* ---------- SNAPPABLE ------------------------------------------------ */
4736 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4737 IS_COLLECTIBLE(i) ||
4741 /* ---------- WALL ----------------------------------------------------- */
4742 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4744 for (j = 0; no_wall_properties[j] != -1; j++)
4745 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4746 i >= EL_FIRST_RUNTIME_UNREAL)
4747 SET_PROPERTY(i, EP_WALL, FALSE);
4749 if (IS_HISTORIC_WALL(i))
4750 SET_PROPERTY(i, EP_WALL, TRUE);
4752 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4753 if (engine_version < VERSION_IDENT(2,2,0,0))
4754 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4756 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4758 !IS_COLLECTIBLE(i)));
4760 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4761 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4762 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4764 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4765 IS_INDESTRUCTIBLE(i)));
4767 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4769 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4770 else if (engine_version < VERSION_IDENT(2,2,0,0))
4771 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4773 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4777 if (IS_CUSTOM_ELEMENT(i))
4779 /* these are additional properties which are initially false when set */
4781 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4783 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4784 if (DONT_COLLIDE_WITH(i))
4785 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4787 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4788 if (CAN_SMASH_EVERYTHING(i))
4789 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4790 if (CAN_SMASH_ENEMIES(i))
4791 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4794 /* ---------- CAN_SMASH ------------------------------------------------ */
4795 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4796 CAN_SMASH_ENEMIES(i) ||
4797 CAN_SMASH_EVERYTHING(i)));
4799 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4800 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4801 EXPLODES_BY_FIRE(i)));
4803 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4804 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4805 EXPLODES_SMASHED(i)));
4807 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4808 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4809 EXPLODES_IMPACT(i)));
4811 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4812 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4814 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4815 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4816 i == EL_BLACK_ORB));
4818 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4819 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4821 IS_CUSTOM_ELEMENT(i)));
4823 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4824 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4825 i == EL_SP_ELECTRON));
4827 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4828 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4829 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4830 getMoveIntoAcidProperty(&level, i));
4832 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4833 if (MAYBE_DONT_COLLIDE_WITH(i))
4834 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4835 getDontCollideWithProperty(&level, i));
4837 /* ---------- SP_PORT -------------------------------------------------- */
4838 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4839 IS_PASSABLE_INSIDE(i)));
4841 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4842 for (j = 0; j < level.num_android_clone_elements; j++)
4843 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4845 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4847 /* ---------- CAN_CHANGE ----------------------------------------------- */
4848 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4849 for (j = 0; j < element_info[i].num_change_pages; j++)
4850 if (element_info[i].change_page[j].can_change)
4851 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4853 /* ---------- HAS_ACTION ----------------------------------------------- */
4854 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4855 for (j = 0; j < element_info[i].num_change_pages; j++)
4856 if (element_info[i].change_page[j].has_action)
4857 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4859 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4860 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4863 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4865 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4866 element_info[i].crumbled[ACTION_DEFAULT] !=
4867 element_info[i].graphic[ACTION_DEFAULT]);
4869 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
4870 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4871 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
4874 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4875 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4876 IS_EDITOR_CASCADE_INACTIVE(i)));
4879 /* dynamically adjust element properties according to game engine version */
4881 static int ep_em_slippery_wall[] =
4886 EL_EXPANDABLE_WALL_HORIZONTAL,
4887 EL_EXPANDABLE_WALL_VERTICAL,
4888 EL_EXPANDABLE_WALL_ANY,
4889 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4890 EL_EXPANDABLE_STEELWALL_VERTICAL,
4891 EL_EXPANDABLE_STEELWALL_ANY,
4892 EL_EXPANDABLE_STEELWALL_GROWING,
4896 static int ep_em_explodes_by_fire[] =
4899 EL_EM_DYNAMITE_ACTIVE,
4904 /* special EM style gems behaviour */
4905 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4906 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4907 level.em_slippery_gems);
4909 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4910 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4911 (level.em_slippery_gems &&
4912 engine_version > VERSION_IDENT(2,0,1,0)));
4914 /* special EM style explosion behaviour regarding chain reactions */
4915 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4916 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4917 level.em_explodes_by_fire);
4920 /* this is needed because some graphics depend on element properties */
4921 if (game_status == GAME_MODE_PLAYING)
4922 InitElementGraphicInfo();
4925 void InitElementPropertiesAfterLoading(int engine_version)
4929 /* set some other uninitialized values of custom elements in older levels */
4930 if (engine_version < VERSION_IDENT(3,1,0,0))
4932 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4934 int element = EL_CUSTOM_START + i;
4936 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4938 element_info[element].explosion_delay = 17;
4939 element_info[element].ignition_delay = 8;
4944 void InitElementPropertiesGfxElement()
4948 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4950 struct ElementInfo *ei = &element_info[i];
4952 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4956 static void InitGlobal()
4961 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4963 /* check if element_name_info entry defined for each element in "main.h" */
4964 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4965 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4967 element_info[i].token_name = element_name_info[i].token_name;
4968 element_info[i].class_name = element_name_info[i].class_name;
4969 element_info[i].editor_description= element_name_info[i].editor_description;
4972 printf("%04d: %s\n", i, element_name_info[i].token_name);
4976 /* create hash from image config list */
4977 image_config_hash = newSetupFileHash();
4978 for (i = 0; image_config[i].token != NULL; i++)
4979 setHashEntry(image_config_hash,
4980 image_config[i].token,
4981 image_config[i].value);
4983 /* create hash from element token list */
4984 element_token_hash = newSetupFileHash();
4985 for (i = 0; element_name_info[i].token_name != NULL; i++)
4986 setHashEntry(element_token_hash,
4987 element_name_info[i].token_name,
4990 /* create hash from graphic token list */
4991 graphic_token_hash = newSetupFileHash();
4992 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4993 if (strSuffix(image_config[i].value, ".png") ||
4994 strSuffix(image_config[i].value, ".pcx") ||
4995 strSuffix(image_config[i].value, ".wav") ||
4996 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4997 setHashEntry(graphic_token_hash,
4998 image_config[i].token,
4999 int2str(graphic++, 0));
5001 /* create hash from font token list */
5002 font_token_hash = newSetupFileHash();
5003 for (i = 0; font_info[i].token_name != NULL; i++)
5004 setHashEntry(font_token_hash,
5005 font_info[i].token_name,
5008 /* always start with reliable default values (all elements) */
5009 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5010 ActiveElement[i] = i;
5012 /* now add all entries that have an active state (active elements) */
5013 for (i = 0; element_with_active_state[i].element != -1; i++)
5015 int element = element_with_active_state[i].element;
5016 int element_active = element_with_active_state[i].element_active;
5018 ActiveElement[element] = element_active;
5021 /* always start with reliable default values (all buttons) */
5022 for (i = 0; i < NUM_IMAGE_FILES; i++)
5023 ActiveButton[i] = i;
5025 /* now add all entries that have an active state (active buttons) */
5026 for (i = 0; button_with_active_state[i].button != -1; i++)
5028 int button = button_with_active_state[i].button;
5029 int button_active = button_with_active_state[i].button_active;
5031 ActiveButton[button] = button_active;
5034 /* always start with reliable default values (all fonts) */
5035 for (i = 0; i < NUM_FONTS; i++)
5038 /* now add all entries that have an active state (active fonts) */
5039 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
5041 int font = font_with_active_state[i].font_nr;
5042 int font_active = font_with_active_state[i].font_nr_active;
5044 ActiveFont[font] = font_active;
5047 global.autoplay_leveldir = NULL;
5048 global.convert_leveldir = NULL;
5049 global.create_images_dir = NULL;
5051 global.frames_per_second = 0;
5052 global.fps_slowdown = FALSE;
5053 global.fps_slowdown_factor = 1;
5055 global.border_status = GAME_MODE_MAIN;
5057 global.fading_status = GAME_MODE_MAIN;
5058 global.fading_type = TYPE_ENTER_MENU;
5061 global.use_envelope_request = FALSE;
5064 void Execute_Command(char *command)
5068 if (strEqual(command, "print graphicsinfo.conf"))
5070 printf("# You can configure additional/alternative image files here.\n");
5071 printf("# (The entries below are default and therefore commented out.)\n");
5073 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
5075 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5078 for (i = 0; image_config[i].token != NULL; i++)
5079 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
5080 image_config[i].value));
5084 else if (strEqual(command, "print soundsinfo.conf"))
5086 printf("# You can configure additional/alternative sound files here.\n");
5087 printf("# (The entries below are default and therefore commented out.)\n");
5089 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
5091 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5094 for (i = 0; sound_config[i].token != NULL; i++)
5095 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
5096 sound_config[i].value));
5100 else if (strEqual(command, "print musicinfo.conf"))
5102 printf("# You can configure additional/alternative music files here.\n");
5103 printf("# (The entries below are default and therefore commented out.)\n");
5105 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
5107 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5110 for (i = 0; music_config[i].token != NULL; i++)
5111 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
5112 music_config[i].value));
5116 else if (strEqual(command, "print editorsetup.conf"))
5118 printf("# You can configure your personal editor element list here.\n");
5119 printf("# (The entries below are default and therefore commented out.)\n");
5122 /* this is needed to be able to check element list for cascade elements */
5123 InitElementPropertiesStatic();
5124 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5126 PrintEditorElementList();
5130 else if (strEqual(command, "print helpanim.conf"))
5132 printf("# You can configure different element help animations here.\n");
5133 printf("# (The entries below are default and therefore commented out.)\n");
5136 for (i = 0; helpanim_config[i].token != NULL; i++)
5138 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
5139 helpanim_config[i].value));
5141 if (strEqual(helpanim_config[i].token, "end"))
5147 else if (strEqual(command, "print helptext.conf"))
5149 printf("# You can configure different element help text here.\n");
5150 printf("# (The entries below are default and therefore commented out.)\n");
5153 for (i = 0; helptext_config[i].token != NULL; i++)
5154 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
5155 helptext_config[i].value));
5159 else if (strPrefix(command, "dump level "))
5161 char *filename = &command[11];
5163 if (!fileExists(filename))
5164 Error(ERR_EXIT, "cannot open file '%s'", filename);
5166 LoadLevelFromFilename(&level, filename);
5171 else if (strPrefix(command, "dump tape "))
5173 char *filename = &command[10];
5175 if (!fileExists(filename))
5176 Error(ERR_EXIT, "cannot open file '%s'", filename);
5178 LoadTapeFromFilename(filename);
5183 else if (strPrefix(command, "autoplay "))
5185 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
5187 while (*str_ptr != '\0') /* continue parsing string */
5189 /* cut leading whitespace from string, replace it by string terminator */
5190 while (*str_ptr == ' ' || *str_ptr == '\t')
5193 if (*str_ptr == '\0') /* end of string reached */
5196 if (global.autoplay_leveldir == NULL) /* read level set string */
5198 global.autoplay_leveldir = str_ptr;
5199 global.autoplay_all = TRUE; /* default: play all tapes */
5201 for (i = 0; i < MAX_TAPES_PER_SET; i++)
5202 global.autoplay_level[i] = FALSE;
5204 else /* read level number string */
5206 int level_nr = atoi(str_ptr); /* get level_nr value */
5208 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5209 global.autoplay_level[level_nr] = TRUE;
5211 global.autoplay_all = FALSE;
5214 /* advance string pointer to the next whitespace (or end of string) */
5215 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5219 else if (strPrefix(command, "convert "))
5221 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
5222 char *str_ptr = strchr(str_copy, ' ');
5224 global.convert_leveldir = str_copy;
5225 global.convert_level_nr = -1;
5227 if (str_ptr != NULL) /* level number follows */
5229 *str_ptr++ = '\0'; /* terminate leveldir string */
5230 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
5233 else if (strPrefix(command, "create images "))
5235 global.create_images_dir = getStringCopy(&command[14]);
5237 if (access(global.create_images_dir, W_OK) != 0)
5238 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
5239 global.create_images_dir);
5243 #if defined(TARGET_SDL2)
5244 else if (strEqual(command, "SDL_ListModes"))
5246 SDL_Init(SDL_INIT_VIDEO);
5248 int num_displays = SDL_GetNumVideoDisplays();
5250 // check if there are any displays available
5251 if (num_displays < 0)
5253 printf("No displays available: %s\n", SDL_GetError());
5258 for (i = 0; i < num_displays; i++)
5260 int num_modes = SDL_GetNumDisplayModes(i);
5263 printf("Available display modes for display %d:\n", i);
5265 // check if there are any display modes available for this display
5268 printf("No display modes available for display %d: %s\n",
5274 for (j = 0; j < num_modes; j++)
5276 SDL_DisplayMode mode;
5278 if (SDL_GetDisplayMode(i, j, &mode) < 0)
5280 printf("Cannot get display mode %d for display %d: %s\n",
5281 j, i, SDL_GetError());
5286 printf("- %d x %d\n", mode.w, mode.h);
5292 #elif defined(TARGET_SDL)
5293 else if (strEqual(command, "SDL_ListModes"))
5298 SDL_Init(SDL_INIT_VIDEO);
5300 /* get available fullscreen/hardware modes */
5301 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
5303 /* check if there are any modes available */
5306 printf("No modes available!\n");
5311 /* check if our resolution is restricted */
5312 if (modes == (SDL_Rect **)-1)
5314 printf("All resolutions available.\n");
5318 printf("Available display modes:\n");
5320 for (i = 0; modes[i]; i++)
5321 printf("- %d x %d\n", modes[i]->w, modes[i]->h);
5331 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
5335 static void InitSetup()
5337 LoadSetup(); /* global setup info */
5339 /* set some options from setup file */
5341 if (setup.options.verbose)
5342 options.verbose = TRUE;
5345 static void InitGameInfo()
5347 game.restart_level = FALSE;
5350 static void InitPlayerInfo()
5354 /* choose default local player */
5355 local_player = &stored_player[0];
5357 for (i = 0; i < MAX_PLAYERS; i++)
5358 stored_player[i].connected = FALSE;
5360 local_player->connected = TRUE;
5363 static void InitArtworkInfo()
5368 static char *get_string_in_brackets(char *string)
5370 char *string_in_brackets = checked_malloc(strlen(string) + 3);
5372 sprintf(string_in_brackets, "[%s]", string);
5374 return string_in_brackets;
5377 static char *get_level_id_suffix(int id_nr)
5379 char *id_suffix = checked_malloc(1 + 3 + 1);
5381 if (id_nr < 0 || id_nr > 999)
5384 sprintf(id_suffix, ".%03d", id_nr);
5390 static char *get_element_class_token(int element)
5392 char *element_class_name = element_info[element].class_name;
5393 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
5395 sprintf(element_class_token, "[%s]", element_class_name);
5397 return element_class_token;
5400 static char *get_action_class_token(int action)
5402 char *action_class_name = &element_action_info[action].suffix[1];
5403 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
5405 sprintf(action_class_token, "[%s]", action_class_name);
5407 return action_class_token;
5411 static void InitArtworkConfig()
5413 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
5414 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
5415 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
5416 static char *action_id_suffix[NUM_ACTIONS + 1];
5417 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5418 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5419 static char *level_id_suffix[MAX_LEVELS + 1];
5420 static char *dummy[1] = { NULL };
5421 static char *ignore_generic_tokens[] =
5427 static char **ignore_image_tokens;
5428 static char **ignore_sound_tokens;
5429 static char **ignore_music_tokens;
5430 int num_ignore_generic_tokens;
5431 int num_ignore_image_tokens;
5432 int num_ignore_sound_tokens;
5433 int num_ignore_music_tokens;
5436 /* dynamically determine list of generic tokens to be ignored */
5437 num_ignore_generic_tokens = 0;
5438 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5439 num_ignore_generic_tokens++;
5441 /* dynamically determine list of image tokens to be ignored */
5442 num_ignore_image_tokens = num_ignore_generic_tokens;
5443 for (i = 0; image_config_vars[i].token != NULL; i++)
5444 num_ignore_image_tokens++;
5445 ignore_image_tokens =
5446 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5447 for (i = 0; i < num_ignore_generic_tokens; i++)
5448 ignore_image_tokens[i] = ignore_generic_tokens[i];
5449 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5450 ignore_image_tokens[num_ignore_generic_tokens + i] =
5451 image_config_vars[i].token;
5452 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5454 /* dynamically determine list of sound tokens to be ignored */
5455 num_ignore_sound_tokens = num_ignore_generic_tokens;
5456 ignore_sound_tokens =
5457 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5458 for (i = 0; i < num_ignore_generic_tokens; i++)
5459 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5460 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5462 /* dynamically determine list of music tokens to be ignored */
5463 num_ignore_music_tokens = num_ignore_generic_tokens;
5464 ignore_music_tokens =
5465 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5466 for (i = 0; i < num_ignore_generic_tokens; i++)
5467 ignore_music_tokens[i] = ignore_generic_tokens[i];
5468 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5470 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5471 image_id_prefix[i] = element_info[i].token_name;
5472 for (i = 0; i < NUM_FONTS; i++)
5473 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5474 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
5476 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5477 sound_id_prefix[i] = element_info[i].token_name;
5478 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5479 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5480 get_string_in_brackets(element_info[i].class_name);
5481 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
5483 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5484 music_id_prefix[i] = music_prefix_info[i].prefix;
5485 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
5487 for (i = 0; i < NUM_ACTIONS; i++)
5488 action_id_suffix[i] = element_action_info[i].suffix;
5489 action_id_suffix[NUM_ACTIONS] = NULL;
5491 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5492 direction_id_suffix[i] = element_direction_info[i].suffix;
5493 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5495 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5496 special_id_suffix[i] = special_suffix_info[i].suffix;
5497 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5499 for (i = 0; i < MAX_LEVELS; i++)
5500 level_id_suffix[i] = get_level_id_suffix(i);
5501 level_id_suffix[MAX_LEVELS] = NULL;
5503 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5504 image_id_prefix, action_id_suffix, direction_id_suffix,
5505 special_id_suffix, ignore_image_tokens);
5506 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5507 sound_id_prefix, action_id_suffix, dummy,
5508 special_id_suffix, ignore_sound_tokens);
5509 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5510 music_id_prefix, special_id_suffix, level_id_suffix,
5511 dummy, ignore_music_tokens);
5514 static void InitMixer()
5521 void InitGfxBuffers()
5523 /* create additional image buffers for double-buffering and cross-fading */
5524 ReCreateBitmap(&bitmap_db_store, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5525 ReCreateBitmap(&bitmap_db_cross, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5526 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE, DEFAULT_DEPTH);
5527 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE, DEFAULT_DEPTH);
5529 ReCreateBitmap(&bitmap_db_door, 3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
5531 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE, DEFAULT_DEPTH);
5532 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE, DEFAULT_DEPTH);
5533 ReCreateBitmap(&bitmap_db_toons, FULL_SXSIZE, FULL_SYSIZE, DEFAULT_DEPTH);
5535 /* initialize screen properties */
5536 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5537 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5539 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5540 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5541 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5542 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5543 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5544 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5546 InitGfxBuffers_EM();
5547 InitGfxBuffers_SP();
5552 struct GraphicInfo *graphic_info_last = graphic_info;
5553 char *filename_font_initial = NULL;
5554 char *filename_anim_initial = NULL;
5555 Bitmap *bitmap_font_initial = NULL;
5559 /* determine settings for initial font (for displaying startup messages) */
5560 for (i = 0; image_config[i].token != NULL; i++)
5562 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5564 char font_token[128];
5567 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5568 len_font_token = strlen(font_token);
5570 if (strEqual(image_config[i].token, font_token))
5571 filename_font_initial = image_config[i].value;
5572 else if (strlen(image_config[i].token) > len_font_token &&
5573 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5575 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5576 font_initial[j].src_x = atoi(image_config[i].value);
5577 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5578 font_initial[j].src_y = atoi(image_config[i].value);
5579 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5580 font_initial[j].width = atoi(image_config[i].value);
5581 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5582 font_initial[j].height = atoi(image_config[i].value);
5587 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5589 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5590 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5593 if (filename_font_initial == NULL) /* should not happen */
5594 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5597 InitGfxCustomArtworkInfo();
5599 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5601 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5602 font_initial[j].bitmap = bitmap_font_initial;
5604 InitFontGraphicInfo();
5606 font_height = getFontHeight(FC_RED);
5609 DrawInitTextAlways(getWindowTitleString(), 20, FC_YELLOW);
5611 DrawInitTextAlways(getProgramInitString(), 20, FC_YELLOW);
5613 DrawInitTextAlways(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
5614 DrawInitTextAlways(PROGRAM_WEBSITE_STRING, WIN_YSIZE - 20 - font_height,
5617 DrawInitTextAlways("Loading graphics", 120, FC_GREEN);
5621 /* initialize busy animation with default values */
5622 int parameter[NUM_GFX_ARGS];
5623 for (i = 0; i < NUM_GFX_ARGS; i++)
5624 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5625 image_config_suffix[i].token,
5626 image_config_suffix[i].type);
5628 for (i = 0; i < NUM_GFX_ARGS; i++)
5629 printf("::: '%s' => %d\n", image_config_suffix[i].token, parameter[i]);
5633 /* determine settings for busy animation (when displaying startup messages) */
5634 for (i = 0; image_config[i].token != NULL; i++)
5636 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5637 int len_anim_token = strlen(anim_token);
5639 if (strEqual(image_config[i].token, anim_token))
5640 filename_anim_initial = image_config[i].value;
5641 else if (strlen(image_config[i].token) > len_anim_token &&
5642 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5645 for (j = 0; image_config_suffix[j].token != NULL; j++)
5647 if (strEqual(&image_config[i].token[len_anim_token],
5648 image_config_suffix[j].token))
5650 get_graphic_parameter_value(image_config[i].value,
5651 image_config_suffix[j].token,
5652 image_config_suffix[j].type);
5655 if (strEqual(&image_config[i].token[len_anim_token], ".x"))
5656 anim_initial.src_x = atoi(image_config[i].value);
5657 else if (strEqual(&image_config[i].token[len_anim_token], ".y"))
5658 anim_initial.src_y = atoi(image_config[i].value);
5659 else if (strEqual(&image_config[i].token[len_anim_token], ".width"))
5660 anim_initial.width = atoi(image_config[i].value);
5661 else if (strEqual(&image_config[i].token[len_anim_token], ".height"))
5662 anim_initial.height = atoi(image_config[i].value);
5663 else if (strEqual(&image_config[i].token[len_anim_token], ".frames"))
5664 anim_initial.anim_frames = atoi(image_config[i].value);
5665 else if (strEqual(&image_config[i].token[len_anim_token],
5666 ".frames_per_line"))
5667 anim_initial.anim_frames_per_line = atoi(image_config[i].value);
5668 else if (strEqual(&image_config[i].token[len_anim_token], ".delay"))
5669 anim_initial.anim_delay = atoi(image_config[i].value);
5674 #if defined(CREATE_SPECIAL_EDITION_RND_JUE)
5675 filename_anim_initial = "loading.pcx";
5677 parameter[GFX_ARG_X] = 0;
5678 parameter[GFX_ARG_Y] = 0;
5679 parameter[GFX_ARG_WIDTH] = 128;
5680 parameter[GFX_ARG_HEIGHT] = 40;
5681 parameter[GFX_ARG_FRAMES] = 32;
5682 parameter[GFX_ARG_DELAY] = 4;
5683 parameter[GFX_ARG_FRAMES_PER_LINE] = ARG_UNDEFINED_VALUE;
5686 if (filename_anim_initial == NULL) /* should not happen */
5687 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5689 anim_initial.bitmap = LoadCustomImage(filename_anim_initial);
5691 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
5693 set_graphic_parameters_ext(0, parameter, anim_initial.bitmap);
5696 printf("::: INIT_GFX: anim_frames_per_line == %d [%d / %d] [%d, %d]\n",
5697 graphic_info[0].anim_frames_per_line,
5698 get_scaled_graphic_width(0),
5699 graphic_info[0].width,
5700 getOriginalImageWidthFromImageID(0),
5701 graphic_info[0].scale_up_factor);
5704 graphic_info = graphic_info_last;
5706 init.busy.width = anim_initial.width;
5707 init.busy.height = anim_initial.height;
5709 InitMenuDesignSettings_Static();
5710 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5712 /* use copy of busy animation to prevent change while reloading artwork */
5717 void RedrawBackground()
5719 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
5720 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
5722 redraw_mask = REDRAW_ALL;
5725 void InitGfxBackground()
5729 fieldbuffer = bitmap_db_field;
5730 SetDrawtoField(DRAW_BACKBUFFER);
5733 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5737 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
5738 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
5741 for (x = 0; x < MAX_BUF_XSIZE; x++)
5742 for (y = 0; y < MAX_BUF_YSIZE; y++)
5745 redraw_mask = REDRAW_ALL;
5748 static void InitLevelInfo()
5750 LoadLevelInfo(); /* global level info */
5751 LoadLevelSetup_LastSeries(); /* last played series info */
5752 LoadLevelSetup_SeriesInfo(); /* last played level info */
5755 static void InitLevelArtworkInfo()
5757 LoadLevelArtworkInfo();
5760 static void InitImages()
5762 print_timestamp_init("InitImages");
5765 printf("::: leveldir_current->identifier == '%s'\n",
5766 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5767 printf("::: leveldir_current->graphics_path == '%s'\n",
5768 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5769 printf("::: leveldir_current->graphics_set == '%s'\n",
5770 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5771 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5772 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5775 setLevelArtworkDir(artwork.gfx_first);
5778 printf("::: leveldir_current->identifier == '%s'\n",
5779 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5780 printf("::: leveldir_current->graphics_path == '%s'\n",
5781 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5782 printf("::: leveldir_current->graphics_set == '%s'\n",
5783 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5784 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5785 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5789 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5790 leveldir_current->identifier,
5791 artwork.gfx_current_identifier,
5792 artwork.gfx_current->identifier,
5793 leveldir_current->graphics_set,
5794 leveldir_current->graphics_path);
5797 UPDATE_BUSY_STATE();
5799 ReloadCustomImages();
5800 print_timestamp_time("ReloadCustomImages");
5802 UPDATE_BUSY_STATE();
5804 LoadCustomElementDescriptions();
5805 print_timestamp_time("LoadCustomElementDescriptions");
5807 UPDATE_BUSY_STATE();
5809 LoadMenuDesignSettings();
5810 print_timestamp_time("LoadMenuDesignSettings");
5812 UPDATE_BUSY_STATE();
5814 ReinitializeGraphics();
5815 print_timestamp_time("ReinitializeGraphics");
5817 UPDATE_BUSY_STATE();
5819 print_timestamp_done("InitImages");
5822 static void InitSound(char *identifier)
5824 print_timestamp_init("InitSound");
5826 if (identifier == NULL)
5827 identifier = artwork.snd_current->identifier;
5829 /* set artwork path to send it to the sound server process */
5830 setLevelArtworkDir(artwork.snd_first);
5832 InitReloadCustomSounds(identifier);
5833 print_timestamp_time("InitReloadCustomSounds");
5835 ReinitializeSounds();
5836 print_timestamp_time("ReinitializeSounds");
5838 print_timestamp_done("InitSound");
5841 static void InitMusic(char *identifier)
5843 print_timestamp_init("InitMusic");
5845 if (identifier == NULL)
5846 identifier = artwork.mus_current->identifier;
5848 /* set artwork path to send it to the sound server process */
5849 setLevelArtworkDir(artwork.mus_first);
5851 InitReloadCustomMusic(identifier);
5852 print_timestamp_time("InitReloadCustomMusic");
5854 ReinitializeMusic();
5855 print_timestamp_time("ReinitializeMusic");
5857 print_timestamp_done("InitMusic");
5860 void InitNetworkServer()
5862 #if defined(NETWORK_AVALIABLE)
5866 if (!options.network)
5869 #if defined(NETWORK_AVALIABLE)
5870 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5872 if (!ConnectToServer(options.server_host, options.server_port))
5873 Error(ERR_EXIT, "cannot connect to network game server");
5875 SendToServer_PlayerName(setup.player_name);
5876 SendToServer_ProtocolVersion();
5879 SendToServer_NrWanted(nr_wanted);
5883 static boolean CheckArtworkConfigForCustomElements(char *filename)
5885 SetupFileHash *setup_file_hash;
5886 boolean redefined_ce_found = FALSE;
5888 /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */
5890 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5892 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5894 char *token = HASH_ITERATION_TOKEN(itr);
5896 if (strPrefix(token, "custom_"))
5898 redefined_ce_found = TRUE;
5903 END_HASH_ITERATION(setup_file_hash, itr)
5905 freeSetupFileHash(setup_file_hash);
5908 return redefined_ce_found;
5911 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5913 char *filename_base, *filename_local;
5914 boolean redefined_ce_found = FALSE;
5916 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5919 printf("::: leveldir_current->identifier == '%s'\n",
5920 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5921 printf("::: leveldir_current->graphics_path == '%s'\n",
5922 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5923 printf("::: leveldir_current->graphics_set == '%s'\n",
5924 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5925 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5926 leveldir_current == NULL ? "[NULL]" :
5927 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5930 /* first look for special artwork configured in level series config */
5931 filename_base = getCustomArtworkLevelConfigFilename(type);
5934 printf("::: filename_base == '%s'\n", filename_base);
5937 if (fileExists(filename_base))
5938 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5940 filename_local = getCustomArtworkConfigFilename(type);
5943 printf("::: filename_local == '%s'\n", filename_local);
5946 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5947 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5950 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5953 return redefined_ce_found;
5956 static void InitOverrideArtwork()
5958 boolean redefined_ce_found = FALSE;
5960 /* to check if this level set redefines any CEs, do not use overriding */
5961 gfx.override_level_graphics = FALSE;
5962 gfx.override_level_sounds = FALSE;
5963 gfx.override_level_music = FALSE;
5965 /* now check if this level set has definitions for custom elements */
5966 if (setup.override_level_graphics == AUTO ||
5967 setup.override_level_sounds == AUTO ||
5968 setup.override_level_music == AUTO)
5969 redefined_ce_found =
5970 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5971 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5972 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5975 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5978 if (redefined_ce_found)
5980 /* this level set has CE definitions: change "AUTO" to "FALSE" */
5981 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5982 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
5983 gfx.override_level_music = (setup.override_level_music == TRUE);
5987 /* this level set has no CE definitions: change "AUTO" to "TRUE" */
5988 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5989 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
5990 gfx.override_level_music = (setup.override_level_music != FALSE);
5994 printf("::: => %d, %d, %d\n",
5995 gfx.override_level_graphics,
5996 gfx.override_level_sounds,
5997 gfx.override_level_music);
6001 static char *getNewArtworkIdentifier(int type)
6003 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
6004 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
6005 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
6006 static boolean initialized[3] = { FALSE, FALSE, FALSE };
6007 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
6009 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
6011 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
6013 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
6014 char *leveldir_identifier = leveldir_current->identifier;
6016 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
6017 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
6019 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
6021 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
6022 char *artwork_current_identifier;
6023 char *artwork_new_identifier = NULL; /* default: nothing has changed */
6025 /* leveldir_current may be invalid (level group, parent link) */
6026 if (!validLevelSeries(leveldir_current))
6029 /* 1st step: determine artwork set to be activated in descending order:
6030 --------------------------------------------------------------------
6031 1. setup artwork (when configured to override everything else)
6032 2. artwork set configured in "levelinfo.conf" of current level set
6033 (artwork in level directory will have priority when loading later)
6034 3. artwork in level directory (stored in artwork sub-directory)
6035 4. setup artwork (currently configured in setup menu) */
6037 if (setup_override_artwork)
6038 artwork_current_identifier = setup_artwork_set;
6039 else if (leveldir_artwork_set != NULL)
6040 artwork_current_identifier = leveldir_artwork_set;
6041 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
6042 artwork_current_identifier = leveldir_identifier;
6044 artwork_current_identifier = setup_artwork_set;
6047 /* 2nd step: check if it is really needed to reload artwork set
6048 ------------------------------------------------------------ */
6051 if (type == ARTWORK_TYPE_GRAPHICS)
6052 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
6053 artwork_new_identifier,
6054 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
6055 artwork_current_identifier,
6056 leveldir_current->graphics_set,
6057 leveldir_current->identifier);
6060 /* ---------- reload if level set and also artwork set has changed ------- */
6061 if (leveldir_current_identifier[type] != leveldir_identifier &&
6062 (last_has_level_artwork_set[type] || has_level_artwork_set))
6063 artwork_new_identifier = artwork_current_identifier;
6065 leveldir_current_identifier[type] = leveldir_identifier;
6066 last_has_level_artwork_set[type] = has_level_artwork_set;
6069 if (type == ARTWORK_TYPE_GRAPHICS)
6070 printf("::: 1: '%s'\n", artwork_new_identifier);
6073 /* ---------- reload if "override artwork" setting has changed ----------- */
6074 if (last_override_level_artwork[type] != setup_override_artwork)
6075 artwork_new_identifier = artwork_current_identifier;
6077 last_override_level_artwork[type] = setup_override_artwork;
6080 if (type == ARTWORK_TYPE_GRAPHICS)
6081 printf("::: 2: '%s'\n", artwork_new_identifier);
6084 /* ---------- reload if current artwork identifier has changed ----------- */
6085 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
6086 artwork_current_identifier))
6087 artwork_new_identifier = artwork_current_identifier;
6089 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
6092 if (type == ARTWORK_TYPE_GRAPHICS)
6093 printf("::: 3: '%s'\n", artwork_new_identifier);
6096 /* ---------- do not reload directly after starting ---------------------- */
6097 if (!initialized[type])
6098 artwork_new_identifier = NULL;
6100 initialized[type] = TRUE;
6103 if (type == ARTWORK_TYPE_GRAPHICS)
6104 printf("::: 4: '%s'\n", artwork_new_identifier);
6108 if (type == ARTWORK_TYPE_GRAPHICS)
6109 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
6110 artwork.gfx_current_identifier, artwork_current_identifier,
6111 artwork.gfx_current->identifier, leveldir_current->graphics_set,
6112 artwork_new_identifier);
6115 return artwork_new_identifier;
6118 void ReloadCustomArtwork(int force_reload)
6120 int last_game_status = game_status; /* save current game status */
6121 char *gfx_new_identifier;
6122 char *snd_new_identifier;
6123 char *mus_new_identifier;
6124 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
6125 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
6126 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
6127 boolean reload_needed;
6129 InitOverrideArtwork();
6131 force_reload_gfx |= AdjustGraphicsForEMC();
6133 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
6134 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
6135 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
6137 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
6138 snd_new_identifier != NULL || force_reload_snd ||
6139 mus_new_identifier != NULL || force_reload_mus);
6144 print_timestamp_init("ReloadCustomArtwork");
6146 game_status = GAME_MODE_LOADING;
6148 FadeOut(REDRAW_ALL);
6151 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6153 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
6155 print_timestamp_time("ClearRectangle");
6158 printf("::: fading in ... %d\n", fading.fade_mode);
6162 printf("::: done\n");
6165 if (gfx_new_identifier != NULL || force_reload_gfx)
6168 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
6169 artwork.gfx_current_identifier,
6171 artwork.gfx_current->identifier,
6172 leveldir_current->graphics_set);
6176 print_timestamp_time("InitImages");
6179 if (snd_new_identifier != NULL || force_reload_snd)
6181 InitSound(snd_new_identifier);
6182 print_timestamp_time("InitSound");
6185 if (mus_new_identifier != NULL || force_reload_mus)
6187 InitMusic(mus_new_identifier);
6188 print_timestamp_time("InitMusic");
6191 game_status = last_game_status; /* restore current game status */
6193 init_last = init; /* switch to new busy animation */
6196 printf("::: ----------------DELAY 1 ...\n");
6201 printf("::: FadeOut @ ReloadCustomArtwork ...\n");
6203 FadeOut(REDRAW_ALL);
6205 printf("::: FadeOut @ ReloadCustomArtwork done\n");
6210 /* force redraw of (open or closed) door graphics */
6211 SetDoorState(DOOR_OPEN_ALL);
6212 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
6217 FadeSetEnterScreen();
6218 FadeSkipNextFadeOut();
6219 // FadeSetDisabled();
6224 fading = fading_none;
6229 redraw_mask = REDRAW_ALL;
6232 print_timestamp_done("ReloadCustomArtwork");
6234 LimitScreenUpdates(FALSE);
6237 void KeyboardAutoRepeatOffUnlessAutoplay()
6239 if (global.autoplay_leveldir == NULL)
6240 KeyboardAutoRepeatOff();
6243 void DisplayExitMessage(char *format, va_list ap)
6245 // check if draw buffer and fonts for exit message are already available
6246 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
6249 int font_1 = FC_RED;
6250 int font_2 = FC_YELLOW;
6251 int font_3 = FC_BLUE;
6252 int font_width = getFontWidth(font_2);
6253 int font_height = getFontHeight(font_2);
6256 int sxsize = WIN_XSIZE - 2 * sx;
6257 int sysize = WIN_YSIZE - 2 * sy;
6258 int line_length = sxsize / font_width;
6259 int max_lines = sysize / font_height;
6260 int num_lines_printed;
6264 gfx.sxsize = sxsize;
6265 gfx.sysize = sysize;
6269 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6271 DrawTextSCentered(sy, font_1, "Fatal error:");
6272 sy += 3 * font_height;;
6275 DrawTextBufferVA(sx, sy, format, ap, font_2,
6276 line_length, line_length, max_lines,
6277 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6278 sy += (num_lines_printed + 3) * font_height;
6280 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
6281 sy += 3 * font_height;
6284 DrawTextBuffer(sx, sy, program.error_filename, font_2,
6285 line_length, line_length, max_lines,
6286 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6288 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
6290 redraw_mask = REDRAW_ALL;
6294 /* deactivate toons on error message screen */
6295 setup.toons = FALSE;
6297 WaitForEventToContinue();
6301 /* ========================================================================= */
6303 /* ========================================================================= */
6307 print_timestamp_init("OpenAll");
6309 game_status = GAME_MODE_LOADING;
6315 InitGlobal(); /* initialize some global variables */
6317 print_timestamp_time("[init global stuff]");
6319 if (options.execute_command)
6320 Execute_Command(options.execute_command);
6322 if (options.serveronly)
6324 #if defined(PLATFORM_UNIX)
6325 NetworkServer(options.server_port, options.serveronly);
6327 Error(ERR_WARN, "networking only supported in Unix version");
6330 exit(0); /* never reached, server loops forever */
6335 print_timestamp_time("[init setup/config stuff (1)]");
6338 print_timestamp_time("[init setup/config stuff (2)]");
6340 print_timestamp_time("[init setup/config stuff (3)]");
6341 InitArtworkInfo(); /* needed before loading gfx, sound & music */
6342 print_timestamp_time("[init setup/config stuff (4)]");
6343 InitArtworkConfig(); /* needed before forking sound child process */
6344 print_timestamp_time("[init setup/config stuff (5)]");
6346 print_timestamp_time("[init setup/config stuff (6)]");
6352 InitRND(NEW_RANDOMIZE);
6353 InitSimpleRandom(NEW_RANDOMIZE);
6357 print_timestamp_time("[init setup/config stuff]");
6360 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
6362 InitEventFilter(FilterEvents);
6364 print_timestamp_time("[init video stuff]");
6366 InitElementPropertiesStatic();
6367 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
6368 InitElementPropertiesGfxElement();
6370 print_timestamp_time("[init element properties stuff]");
6374 print_timestamp_time("InitGfx");
6377 print_timestamp_time("InitLevelInfo");
6379 InitLevelArtworkInfo();
6380 print_timestamp_time("InitLevelArtworkInfo");
6382 InitOverrideArtwork(); /* needs to know current level directory */
6383 print_timestamp_time("InitOverrideArtwork");
6385 InitImages(); /* needs to know current level directory */
6386 print_timestamp_time("InitImages");
6388 InitSound(NULL); /* needs to know current level directory */
6389 print_timestamp_time("InitSound");
6391 InitMusic(NULL); /* needs to know current level directory */
6392 print_timestamp_time("InitMusic");
6394 InitGfxBackground();
6404 if (global.autoplay_leveldir)
6409 else if (global.convert_leveldir)
6414 else if (global.create_images_dir)
6416 CreateLevelSketchImages();
6420 game_status = GAME_MODE_MAIN;
6423 FadeSetEnterScreen();
6424 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
6425 FadeSkipNextFadeOut();
6426 // FadeSetDisabled();
6428 fading = fading_none;
6431 print_timestamp_time("[post-artwork]");
6433 print_timestamp_done("OpenAll");
6437 InitNetworkServer();
6440 Error(ERR_DEBUG, "::: SDL_GetBasePath() == '%s'",
6442 Error(ERR_DEBUG, "::: SDL_GetPrefPath() == '%s'",
6443 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
6444 #if defined(PLATFORM_ANDROID)
6445 Error(ERR_DEBUG, "::: SDL_AndroidGetInternalStoragePath() == '%s'",
6446 SDL_AndroidGetInternalStoragePath());
6447 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStoragePath() == '%s'",
6448 SDL_AndroidGetExternalStoragePath());
6449 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStorageState() == '%s'",
6450 (SDL_AndroidGetExternalStorageState() ==
6451 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "read" :
6452 SDL_AndroidGetExternalStorageState() ==
6453 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "write" : "not available"));
6458 void CloseAllAndExit(int exit_value)
6463 CloseAudio(); /* called after freeing sounds (needed for SDL) */
6475 #if defined(TARGET_SDL)
6476 #if defined(TARGET_SDL2)
6478 // set a flag to tell the network server thread to quit and wait for it
6479 // using SDL_WaitThread()
6481 if (network_server) /* terminate network server */
6482 SDL_KillThread(server_thread);
6486 CloseVideoDisplay();
6487 ClosePlatformDependentStuff();
6489 if (exit_value != 0)
6491 /* fall back to default level set (current set may have caused an error) */
6492 SaveLevelSetup_LastSeries_Deactivate();
6494 /* tell user where to find error log file which may contain more details */
6495 // (error notification now directly displayed on screen inside R'n'D
6496 // NotifyUserAboutErrorFile(); /* currently only works for Windows */