1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2006 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
14 #include "libgame/libgame.h"
29 #include "conf_e2g.c" /* include auto-generated data structure definitions */
30 #include "conf_esg.c" /* include auto-generated data structure definitions */
31 #include "conf_e2s.c" /* include auto-generated data structure definitions */
32 #include "conf_fnt.c" /* include auto-generated data structure definitions */
33 #include "conf_g2s.c" /* include auto-generated data structure definitions */
34 #include "conf_g2m.c" /* include auto-generated data structure definitions */
35 #include "conf_act.c" /* include auto-generated data structure definitions */
38 #define CONFIG_TOKEN_FONT_INITIAL "font.initial"
39 #define CONFIG_TOKEN_GLOBAL_BUSY "global.busy"
42 static struct FontBitmapInfo font_initial[NUM_INITIAL_FONTS];
43 static struct GraphicInfo anim_initial;
45 static int copy_properties[][5] =
49 EL_BUG_LEFT, EL_BUG_RIGHT,
50 EL_BUG_UP, EL_BUG_DOWN
54 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
55 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
59 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
60 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
64 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
65 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
69 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
70 EL_PACMAN_UP, EL_PACMAN_DOWN
74 EL_YAMYAM_LEFT, EL_YAMYAM_RIGHT,
75 EL_YAMYAM_UP, EL_YAMYAM_DOWN
79 EL_MOLE_LEFT, EL_MOLE_RIGHT,
80 EL_MOLE_UP, EL_MOLE_DOWN
91 struct GraphicInfo *graphic_info_last = graphic_info;
93 static unsigned int action_delay = 0;
94 unsigned int action_delay_value = GameFrameDelay;
95 int sync_frame = FrameCounter;
98 if (game_status != GAME_MODE_LOADING)
101 if (anim_initial.bitmap == NULL || window == NULL)
104 if (!DelayReached(&action_delay, action_delay_value))
109 static unsigned int last_counter = -1;
110 unsigned int current_counter = Counter();
111 unsigned int delay = current_counter - last_counter;
113 if (last_counter != -1 && delay > action_delay_value + 5)
114 printf("::: DrawInitAnim: DELAY TOO LONG: %ld\n", delay);
116 last_counter = current_counter;
120 x = ALIGNED_TEXT_XPOS(&init_last.busy);
121 y = ALIGNED_TEXT_YPOS(&init_last.busy);
123 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
127 static boolean done = FALSE;
130 printf("::: %d, %d, %d, %d => %d, %d [%d, %d] [%d, %d]\n",
131 init.busy.x, init.busy.y,
132 init.busy.align, init.busy.valign,
134 graphic_info[graphic].width,
135 graphic_info[graphic].height,
136 sync_frame, anim_initial.anim_delay);
142 if (sync_frame % anim_initial.anim_delay == 0)
147 int width = graphic_info[graphic].width;
148 int height = graphic_info[graphic].height;
149 int frame = getGraphicAnimationFrame(graphic, sync_frame);
151 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
152 BlitBitmap(src_bitmap, window, src_x, src_y, width, height, x, y);
154 /* !!! this can only draw TILEX/TILEY size animations !!! */
155 DrawGraphicAnimationExt(window, x, y, graphic, sync_frame, NO_MASKING);
159 graphic_info = graphic_info_last;
166 FreeLevelEditorGadgets();
175 static boolean gadgets_initialized = FALSE;
177 if (gadgets_initialized)
180 CreateLevelEditorGadgets();
184 CreateScreenGadgets();
186 InitGadgetsSoundCallback(PlaySoundActivating, PlaySoundSelecting);
188 gadgets_initialized = TRUE;
191 inline void InitElementSmallImagesScaledUp(int graphic)
194 struct FileInfo *fi = getImageListEntryFromImageID(graphic);
196 printf("::: '%s' -> '%s'\n", fi->token, fi->filename);
199 CreateImageWithSmallImages(graphic, graphic_info[graphic].scale_up_factor);
202 void InitElementSmallImages()
204 static int special_graphics[] =
206 IMG_EDITOR_ELEMENT_BORDER,
207 IMG_EDITOR_ELEMENT_BORDER_INPUT,
208 IMG_EDITOR_CASCADE_LIST,
209 IMG_EDITOR_CASCADE_LIST_ACTIVE,
212 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
213 int num_property_mappings = getImageListPropertyMappingSize();
216 /* initialize normal images from static configuration */
217 for (i = 0; element_to_graphic[i].element > -1; i++)
218 InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
220 /* initialize special images from static configuration */
221 for (i = 0; element_to_special_graphic[i].element > -1; i++)
222 InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
224 /* initialize images from dynamic configuration (may be elements or other) */
225 for (i = 0; i < num_property_mappings; i++)
226 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
228 /* initialize special images from above list (non-element images) */
229 for (i = 0; special_graphics[i] > -1; i++)
230 InitElementSmallImagesScaledUp(special_graphics[i]);
233 void InitScaledImages()
237 /* scale normal images from static configuration, if not already scaled */
238 for (i = 0; i < NUM_IMAGE_FILES; i++)
239 ScaleImage(i, graphic_info[i].scale_up_factor);
243 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
244 void SetBitmaps_EM(Bitmap **em_bitmap)
246 em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
247 em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].bitmap;
252 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
253 void SetBitmaps_SP(Bitmap **sp_bitmap)
255 *sp_bitmap = graphic_info[IMG_SP_OBJECTS].bitmap;
259 static int getFontBitmapID(int font_nr)
263 /* (special case: do not use special font for GAME_MODE_LOADING) */
264 if (game_status >= GAME_MODE_TITLE_INITIAL &&
265 game_status <= GAME_MODE_PSEUDO_PREVIEW)
266 special = game_status;
267 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
268 special = GFX_SPECIAL_ARG_MAIN;
270 else if (game_status == GAME_MODE_PLAYING)
271 special = GFX_SPECIAL_ARG_DOOR;
278 font_info[font_nr].token_name,
279 special_suffix_info[special].suffix);
284 return font_info[font_nr].special_bitmap_id[special];
289 static int getFontFromToken(char *token)
292 char *value = getHashEntry(font_token_hash, token);
299 /* !!! OPTIMIZE THIS BY USING HASH !!! */
300 for (i = 0; i < NUM_FONTS; i++)
301 if (strEqual(token, font_info[i].token_name))
305 /* if font not found, use reliable default value */
306 return FONT_INITIAL_1;
309 void InitFontGraphicInfo()
311 static struct FontBitmapInfo *font_bitmap_info = NULL;
312 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
313 int num_property_mappings = getImageListPropertyMappingSize();
314 int num_font_bitmaps = NUM_FONTS;
317 if (graphic_info == NULL) /* still at startup phase */
319 InitFontInfo(font_initial, NUM_INITIAL_FONTS,
320 getFontBitmapID, getFontFromToken);
325 /* ---------- initialize font graphic definitions ---------- */
327 /* always start with reliable default values (normal font graphics) */
328 for (i = 0; i < NUM_FONTS; i++)
329 font_info[i].graphic = IMG_FONT_INITIAL_1;
331 /* initialize normal font/graphic mapping from static configuration */
332 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
334 int font_nr = font_to_graphic[i].font_nr;
335 int special = font_to_graphic[i].special;
336 int graphic = font_to_graphic[i].graphic;
341 font_info[font_nr].graphic = graphic;
344 /* always start with reliable default values (special font graphics) */
345 for (i = 0; i < NUM_FONTS; i++)
347 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
349 font_info[i].special_graphic[j] = font_info[i].graphic;
350 font_info[i].special_bitmap_id[j] = i;
354 /* initialize special font/graphic mapping from static configuration */
355 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
357 int font_nr = font_to_graphic[i].font_nr;
358 int special = font_to_graphic[i].special;
359 int graphic = font_to_graphic[i].graphic;
360 int base_graphic = font2baseimg(font_nr);
362 if (IS_SPECIAL_GFX_ARG(special))
364 boolean base_redefined =
365 getImageListEntryFromImageID(base_graphic)->redefined;
366 boolean special_redefined =
367 getImageListEntryFromImageID(graphic)->redefined;
368 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
370 /* if the base font ("font.title_1", for example) has been redefined,
371 but not the special font ("font.title_1.LEVELS", for example), do not
372 use an existing (in this case considered obsolete) special font
373 anymore, but use the automatically determined default font */
374 /* special case: cloned special fonts must be explicitly redefined,
375 but are not automatically redefined by redefining base font */
376 if (base_redefined && !special_redefined && !special_cloned)
379 font_info[font_nr].special_graphic[special] = graphic;
380 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
385 /* initialize special font/graphic mapping from dynamic configuration */
386 for (i = 0; i < num_property_mappings; i++)
388 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
389 int special = property_mapping[i].ext3_index;
390 int graphic = property_mapping[i].artwork_index;
395 if (IS_SPECIAL_GFX_ARG(special))
397 font_info[font_nr].special_graphic[special] = graphic;
398 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
403 /* correct special font/graphic mapping for cloned fonts for downwards
404 compatibility of PREVIEW fonts -- this is only needed for implicit
405 redefinition of special font by redefined base font, and only if other
406 fonts are cloned from this special font (like in the "Zelda" level set) */
407 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
409 int font_nr = font_to_graphic[i].font_nr;
410 int special = font_to_graphic[i].special;
411 int graphic = font_to_graphic[i].graphic;
413 if (IS_SPECIAL_GFX_ARG(special))
415 boolean special_redefined =
416 getImageListEntryFromImageID(graphic)->redefined;
417 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
419 if (special_cloned && !special_redefined)
423 for (j = 0; font_to_graphic[j].font_nr > -1; j++)
425 int font_nr2 = font_to_graphic[j].font_nr;
426 int special2 = font_to_graphic[j].special;
427 int graphic2 = font_to_graphic[j].graphic;
429 if (IS_SPECIAL_GFX_ARG(special2) &&
430 graphic2 == graphic_info[graphic].clone_from)
432 font_info[font_nr].special_graphic[special] =
433 font_info[font_nr2].special_graphic[special2];
434 font_info[font_nr].special_bitmap_id[special] =
435 font_info[font_nr2].special_bitmap_id[special2];
442 /* reset non-redefined ".active" font graphics if normal font is redefined */
443 /* (this different treatment is needed because normal and active fonts are
444 independently defined ("active" is not a property of font definitions!) */
445 for (i = 0; i < NUM_FONTS; i++)
447 int font_nr_base = i;
448 int font_nr_active = FONT_ACTIVE(font_nr_base);
450 /* check only those fonts with exist as normal and ".active" variant */
451 if (font_nr_base != font_nr_active)
453 int base_graphic = font_info[font_nr_base].graphic;
454 int active_graphic = font_info[font_nr_active].graphic;
455 boolean base_redefined =
456 getImageListEntryFromImageID(base_graphic)->redefined;
457 boolean active_redefined =
458 getImageListEntryFromImageID(active_graphic)->redefined;
460 /* if the base font ("font.menu_1", for example) has been redefined,
461 but not the active font ("font.menu_1.active", for example), do not
462 use an existing (in this case considered obsolete) active font
463 anymore, but use the automatically determined default font */
464 if (base_redefined && !active_redefined)
465 font_info[font_nr_active].graphic = base_graphic;
467 /* now also check each "special" font (which may be the same as above) */
468 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
470 int base_graphic = font_info[font_nr_base].special_graphic[j];
471 int active_graphic = font_info[font_nr_active].special_graphic[j];
472 boolean base_redefined =
473 getImageListEntryFromImageID(base_graphic)->redefined;
474 boolean active_redefined =
475 getImageListEntryFromImageID(active_graphic)->redefined;
477 /* same as above, but check special graphic definitions, for example:
478 redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN" */
479 if (base_redefined && !active_redefined)
481 font_info[font_nr_active].special_graphic[j] =
482 font_info[font_nr_base].special_graphic[j];
483 font_info[font_nr_active].special_bitmap_id[j] =
484 font_info[font_nr_base].special_bitmap_id[j];
490 /* ---------- initialize font bitmap array ---------- */
492 if (font_bitmap_info != NULL)
493 FreeFontInfo(font_bitmap_info);
496 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
498 /* ---------- initialize font bitmap definitions ---------- */
500 for (i = 0; i < NUM_FONTS; i++)
502 if (i < NUM_INITIAL_FONTS)
504 font_bitmap_info[i] = font_initial[i];
508 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
510 int font_bitmap_id = font_info[i].special_bitmap_id[j];
511 int graphic = font_info[i].special_graphic[j];
513 /* set 'graphic_info' for font entries, if uninitialized (guessed) */
514 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
516 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
517 graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
520 /* copy font relevant information from graphics information */
521 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
522 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
523 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
524 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
525 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
527 font_bitmap_info[font_bitmap_id].draw_xoffset =
528 graphic_info[graphic].draw_xoffset;
529 font_bitmap_info[font_bitmap_id].draw_yoffset =
530 graphic_info[graphic].draw_yoffset;
532 font_bitmap_info[font_bitmap_id].num_chars =
533 graphic_info[graphic].anim_frames;
534 font_bitmap_info[font_bitmap_id].num_chars_per_line =
535 graphic_info[graphic].anim_frames_per_line;
539 InitFontInfo(font_bitmap_info, num_font_bitmaps,
540 getFontBitmapID, getFontFromToken);
543 void InitElementGraphicInfo()
545 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
546 int num_property_mappings = getImageListPropertyMappingSize();
549 if (graphic_info == NULL) /* still at startup phase */
552 /* set values to -1 to identify later as "uninitialized" values */
553 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
555 for (act = 0; act < NUM_ACTIONS; act++)
557 element_info[i].graphic[act] = -1;
558 element_info[i].crumbled[act] = -1;
560 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
562 element_info[i].direction_graphic[act][dir] = -1;
563 element_info[i].direction_crumbled[act][dir] = -1;
570 /* initialize normal element/graphic mapping from static configuration */
571 for (i = 0; element_to_graphic[i].element > -1; i++)
573 int element = element_to_graphic[i].element;
574 int action = element_to_graphic[i].action;
575 int direction = element_to_graphic[i].direction;
576 boolean crumbled = element_to_graphic[i].crumbled;
577 int graphic = element_to_graphic[i].graphic;
578 int base_graphic = el2baseimg(element);
580 if (graphic_info[graphic].bitmap == NULL)
583 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
586 boolean base_redefined =
587 getImageListEntryFromImageID(base_graphic)->redefined;
588 boolean act_dir_redefined =
589 getImageListEntryFromImageID(graphic)->redefined;
591 /* if the base graphic ("emerald", for example) has been redefined,
592 but not the action graphic ("emerald.falling", for example), do not
593 use an existing (in this case considered obsolete) action graphic
594 anymore, but use the automatically determined default graphic */
595 if (base_redefined && !act_dir_redefined)
600 action = ACTION_DEFAULT;
605 element_info[element].direction_crumbled[action][direction] = graphic;
607 element_info[element].crumbled[action] = graphic;
612 element_info[element].direction_graphic[action][direction] = graphic;
614 element_info[element].graphic[action] = graphic;
618 /* initialize normal element/graphic mapping from dynamic configuration */
619 for (i = 0; i < num_property_mappings; i++)
621 int element = property_mapping[i].base_index;
622 int action = property_mapping[i].ext1_index;
623 int direction = property_mapping[i].ext2_index;
624 int special = property_mapping[i].ext3_index;
625 int graphic = property_mapping[i].artwork_index;
626 boolean crumbled = FALSE;
629 if ((element == EL_EM_DYNAMITE ||
630 element == EL_EM_DYNAMITE_ACTIVE) &&
631 action == ACTION_ACTIVE &&
632 (special == GFX_SPECIAL_ARG_EDITOR ||
633 special == GFX_SPECIAL_ARG_PANEL))
634 printf("::: DYNAMIC: %d, %d, %d -> %d\n",
635 element, action, special, graphic);
638 if (special == GFX_SPECIAL_ARG_CRUMBLED)
644 if (graphic_info[graphic].bitmap == NULL)
647 if (element >= MAX_NUM_ELEMENTS || special != -1)
651 action = ACTION_DEFAULT;
656 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
657 element_info[element].direction_crumbled[action][dir] = -1;
660 element_info[element].direction_crumbled[action][direction] = graphic;
662 element_info[element].crumbled[action] = graphic;
667 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
668 element_info[element].direction_graphic[action][dir] = -1;
671 element_info[element].direction_graphic[action][direction] = graphic;
673 element_info[element].graphic[action] = graphic;
677 /* now copy all graphics that are defined to be cloned from other graphics */
678 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
680 int graphic = element_info[i].graphic[ACTION_DEFAULT];
681 int crumbled_like, diggable_like;
686 crumbled_like = graphic_info[graphic].crumbled_like;
687 diggable_like = graphic_info[graphic].diggable_like;
689 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
691 for (act = 0; act < NUM_ACTIONS; act++)
692 element_info[i].crumbled[act] =
693 element_info[crumbled_like].crumbled[act];
694 for (act = 0; act < NUM_ACTIONS; act++)
695 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
696 element_info[i].direction_crumbled[act][dir] =
697 element_info[crumbled_like].direction_crumbled[act][dir];
700 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
702 element_info[i].graphic[ACTION_DIGGING] =
703 element_info[diggable_like].graphic[ACTION_DIGGING];
704 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
705 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
706 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
711 /* set hardcoded definitions for some runtime elements without graphic */
712 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
716 /* set hardcoded definitions for some internal elements without graphic */
717 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
719 if (IS_EDITOR_CASCADE_INACTIVE(i))
720 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
721 else if (IS_EDITOR_CASCADE_ACTIVE(i))
722 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
726 /* now set all undefined/invalid graphics to -1 to set to default after it */
727 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
729 for (act = 0; act < NUM_ACTIONS; act++)
733 graphic = element_info[i].graphic[act];
734 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
735 element_info[i].graphic[act] = -1;
737 graphic = element_info[i].crumbled[act];
738 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
739 element_info[i].crumbled[act] = -1;
741 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
743 graphic = element_info[i].direction_graphic[act][dir];
744 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
745 element_info[i].direction_graphic[act][dir] = -1;
747 graphic = element_info[i].direction_crumbled[act][dir];
748 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
749 element_info[i].direction_crumbled[act][dir] = -1;
756 /* adjust graphics with 2nd tile for movement according to direction
757 (do this before correcting '-1' values to minimize calculations) */
758 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
760 for (act = 0; act < NUM_ACTIONS; act++)
762 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
764 int graphic = element_info[i].direction_graphic[act][dir];
765 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
767 if (act == ACTION_FALLING) /* special case */
768 graphic = element_info[i].graphic[act];
771 graphic_info[graphic].double_movement &&
772 graphic_info[graphic].swap_double_tiles != 0)
774 struct GraphicInfo *g = &graphic_info[graphic];
775 int src_x_front = g->src_x;
776 int src_y_front = g->src_y;
777 int src_x_back = g->src_x + g->offset2_x;
778 int src_y_back = g->src_y + g->offset2_y;
779 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
781 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
782 src_y_front < src_y_back);
783 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
784 boolean swap_movement_tiles_autodetected =
785 (!frames_are_ordered_diagonally &&
786 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
787 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
788 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
789 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
792 /* swap frontside and backside graphic tile coordinates, if needed */
793 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
795 /* get current (wrong) backside tile coordinates */
796 getFixedGraphicSourceExt(graphic, 0, &dummy,
797 &src_x_back, &src_y_back, TRUE);
799 /* set frontside tile coordinates to backside tile coordinates */
800 g->src_x = src_x_back;
801 g->src_y = src_y_back;
803 /* invert tile offset to point to new backside tile coordinates */
807 /* do not swap front and backside tiles again after correction */
808 g->swap_double_tiles = 0;
817 /* now set all '-1' values to element specific default values */
818 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
820 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
821 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
822 int default_direction_graphic[NUM_DIRECTIONS_FULL];
823 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
825 if (default_graphic == -1)
826 default_graphic = IMG_UNKNOWN;
828 if (default_crumbled == -1)
829 default_crumbled = default_graphic;
831 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
832 if (default_crumbled == -1)
833 default_crumbled = IMG_EMPTY;
836 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
838 default_direction_graphic[dir] =
839 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
840 default_direction_crumbled[dir] =
841 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
843 if (default_direction_graphic[dir] == -1)
844 default_direction_graphic[dir] = default_graphic;
846 if (default_direction_crumbled[dir] == -1)
847 default_direction_crumbled[dir] = default_direction_graphic[dir];
849 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
850 if (default_direction_crumbled[dir] == -1)
851 default_direction_crumbled[dir] = default_crumbled;
855 for (act = 0; act < NUM_ACTIONS; act++)
857 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
858 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
859 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
860 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
861 act == ACTION_TURNING_FROM_RIGHT ||
862 act == ACTION_TURNING_FROM_UP ||
863 act == ACTION_TURNING_FROM_DOWN);
865 /* generic default action graphic (defined by "[default]" directive) */
866 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
867 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
868 int default_remove_graphic = IMG_EMPTY;
870 if (act_remove && default_action_graphic != -1)
871 default_remove_graphic = default_action_graphic;
873 /* look for special default action graphic (classic game specific) */
874 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
875 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
876 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
877 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
878 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
879 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
881 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
882 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
883 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
884 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
885 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
886 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
889 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
890 /* !!! make this better !!! */
891 if (i == EL_EMPTY_SPACE)
893 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
894 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
898 if (default_action_graphic == -1)
899 default_action_graphic = default_graphic;
901 if (default_action_crumbled == -1)
902 default_action_crumbled = default_action_graphic;
904 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
905 if (default_action_crumbled == -1)
906 default_action_crumbled = default_crumbled;
909 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
911 /* use action graphic as the default direction graphic, if undefined */
912 int default_action_direction_graphic = element_info[i].graphic[act];
913 int default_action_direction_crumbled = element_info[i].crumbled[act];
915 /* no graphic for current action -- use default direction graphic */
916 if (default_action_direction_graphic == -1)
917 default_action_direction_graphic =
918 (act_remove ? default_remove_graphic :
920 element_info[i].direction_graphic[ACTION_TURNING][dir] :
921 default_action_graphic != default_graphic ?
922 default_action_graphic :
923 default_direction_graphic[dir]);
925 if (element_info[i].direction_graphic[act][dir] == -1)
926 element_info[i].direction_graphic[act][dir] =
927 default_action_direction_graphic;
930 if (default_action_direction_crumbled == -1)
931 default_action_direction_crumbled =
932 element_info[i].direction_graphic[act][dir];
934 if (default_action_direction_crumbled == -1)
935 default_action_direction_crumbled =
936 (act_remove ? default_remove_graphic :
938 element_info[i].direction_crumbled[ACTION_TURNING][dir] :
939 default_action_crumbled != default_crumbled ?
940 default_action_crumbled :
941 default_direction_crumbled[dir]);
944 if (element_info[i].direction_crumbled[act][dir] == -1)
945 element_info[i].direction_crumbled[act][dir] =
946 default_action_direction_crumbled;
949 /* no graphic for this specific action -- use default action graphic */
950 if (element_info[i].graphic[act] == -1)
951 element_info[i].graphic[act] =
952 (act_remove ? default_remove_graphic :
953 act_turning ? element_info[i].graphic[ACTION_TURNING] :
954 default_action_graphic);
956 if (element_info[i].crumbled[act] == -1)
957 element_info[i].crumbled[act] = element_info[i].graphic[act];
959 if (element_info[i].crumbled[act] == -1)
960 element_info[i].crumbled[act] =
961 (act_remove ? default_remove_graphic :
962 act_turning ? element_info[i].crumbled[ACTION_TURNING] :
963 default_action_crumbled);
971 /* !!! THIS ALSO CLEARS SPECIAL FLAGS (AND IS NOT NEEDED ANYWAY) !!! */
972 /* set animation mode to "none" for each graphic with only 1 frame */
973 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
975 for (act = 0; act < NUM_ACTIONS; act++)
977 int graphic = element_info[i].graphic[act];
978 int crumbled = element_info[i].crumbled[act];
980 if (graphic_info[graphic].anim_frames == 1)
981 graphic_info[graphic].anim_mode = ANIM_NONE;
982 if (graphic_info[crumbled].anim_frames == 1)
983 graphic_info[crumbled].anim_mode = ANIM_NONE;
985 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
987 graphic = element_info[i].direction_graphic[act][dir];
988 crumbled = element_info[i].direction_crumbled[act][dir];
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;
1001 if (options.verbose)
1003 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1004 if (element_info[i].graphic[ACTION_DEFAULT] == IMG_UNKNOWN &&
1006 Error(ERR_INFO, "warning: no graphic for element '%s' (%d)",
1007 element_info[i].token_name, i);
1013 void InitElementSpecialGraphicInfo()
1015 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
1016 int num_property_mappings = getImageListPropertyMappingSize();
1019 /* always start with reliable default values */
1020 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1021 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1022 element_info[i].special_graphic[j] =
1023 element_info[i].graphic[ACTION_DEFAULT];
1025 /* initialize special element/graphic mapping from static configuration */
1026 for (i = 0; element_to_special_graphic[i].element > -1; i++)
1028 int element = element_to_special_graphic[i].element;
1029 int special = element_to_special_graphic[i].special;
1030 int graphic = element_to_special_graphic[i].graphic;
1031 int base_graphic = el2baseimg(element);
1032 boolean base_redefined =
1033 getImageListEntryFromImageID(base_graphic)->redefined;
1034 boolean special_redefined =
1035 getImageListEntryFromImageID(graphic)->redefined;
1038 if ((element == EL_EM_DYNAMITE ||
1039 element == EL_EM_DYNAMITE_ACTIVE) &&
1040 (special == GFX_SPECIAL_ARG_EDITOR ||
1041 special == GFX_SPECIAL_ARG_PANEL))
1042 printf("::: SPECIAL STATIC: %d, %d -> %d\n",
1043 element, special, graphic);
1046 /* if the base graphic ("emerald", for example) has been redefined,
1047 but not the special graphic ("emerald.EDITOR", for example), do not
1048 use an existing (in this case considered obsolete) special graphic
1049 anymore, but use the automatically created (down-scaled) graphic */
1050 if (base_redefined && !special_redefined)
1053 element_info[element].special_graphic[special] = graphic;
1056 /* initialize special element/graphic mapping from dynamic configuration */
1057 for (i = 0; i < num_property_mappings; i++)
1059 int element = property_mapping[i].base_index;
1060 int action = property_mapping[i].ext1_index;
1061 int direction = property_mapping[i].ext2_index;
1062 int special = property_mapping[i].ext3_index;
1063 int graphic = property_mapping[i].artwork_index;
1066 if ((element == EL_EM_DYNAMITE ||
1067 element == EL_EM_DYNAMITE_ACTIVE ||
1068 element == EL_CONVEYOR_BELT_1_MIDDLE ||
1069 element == EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE) &&
1070 (special == GFX_SPECIAL_ARG_EDITOR ||
1071 special == GFX_SPECIAL_ARG_PANEL))
1072 printf("::: SPECIAL DYNAMIC: %d, %d -> %d [%d]\n",
1073 element, special, graphic, property_mapping[i].ext1_index);
1077 if (element == EL_CONVEYOR_BELT_1_MIDDLE &&
1078 action == ACTION_ACTIVE)
1080 element = EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE;
1086 if (element == EL_MAGIC_WALL &&
1087 action == ACTION_ACTIVE)
1089 element = EL_MAGIC_WALL_ACTIVE;
1095 /* for action ".active", replace element with active element, if exists */
1096 if (action == ACTION_ACTIVE && element != ELEMENT_ACTIVE(element))
1098 element = ELEMENT_ACTIVE(element);
1103 if (element >= MAX_NUM_ELEMENTS)
1106 /* do not change special graphic if action or direction was specified */
1107 if (action != -1 || direction != -1)
1110 if (IS_SPECIAL_GFX_ARG(special))
1111 element_info[element].special_graphic[special] = graphic;
1114 /* now set all undefined/invalid graphics to default */
1115 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1116 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1117 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
1118 element_info[i].special_graphic[j] =
1119 element_info[i].graphic[ACTION_DEFAULT];
1122 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
1124 if (type != TYPE_ELEMENT && type != TYPE_GRAPHIC)
1125 return get_parameter_value(value_raw, suffix, type);
1127 if (strEqual(value_raw, ARG_UNDEFINED))
1128 return ARG_UNDEFINED_VALUE;
1130 if (type == TYPE_ELEMENT)
1132 char *value = getHashEntry(element_token_hash, value_raw);
1134 return (value != NULL ? atoi(value) : EL_UNDEFINED);
1136 else if (type == TYPE_GRAPHIC)
1138 char *value = getHashEntry(graphic_token_hash, value_raw);
1140 return (value != NULL ? atoi(value) : IMG_UNDEFINED);
1146 static int get_scaled_graphic_width(int graphic)
1148 int original_width = getOriginalImageWidthFromImageID(graphic);
1149 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1151 return original_width * scale_up_factor;
1154 static int get_scaled_graphic_height(int graphic)
1156 int original_height = getOriginalImageHeightFromImageID(graphic);
1157 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1159 return original_height * scale_up_factor;
1162 static void set_graphic_parameters_ext(int graphic, int *parameter,
1165 struct GraphicInfo *g = &graphic_info[graphic];
1166 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1167 int anim_frames_per_line = 1;
1169 /* always start with reliable default values */
1170 g->src_image_width = 0;
1171 g->src_image_height = 0;
1174 g->width = TILEX; /* default for element graphics */
1175 g->height = TILEY; /* default for element graphics */
1176 g->offset_x = 0; /* one or both of these values ... */
1177 g->offset_y = 0; /* ... will be corrected later */
1178 g->offset2_x = 0; /* one or both of these values ... */
1179 g->offset2_y = 0; /* ... will be corrected later */
1180 g->swap_double_tiles = -1; /* auto-detect tile swapping */
1181 g->crumbled_like = -1; /* do not use clone element */
1182 g->diggable_like = -1; /* do not use clone element */
1183 g->border_size = TILEX / 8; /* "CRUMBLED" border size */
1184 g->scale_up_factor = 1; /* default: no scaling up */
1185 g->clone_from = -1; /* do not use clone graphic */
1186 g->anim_delay_fixed = 0;
1187 g->anim_delay_random = 0;
1188 g->post_delay_fixed = 0;
1189 g->post_delay_random = 0;
1190 g->fade_mode = FADE_MODE_DEFAULT;
1194 g->align = ALIGN_CENTER; /* default for title screens */
1195 g->valign = VALIGN_MIDDLE; /* default for title screens */
1196 g->sort_priority = 0; /* default for title screens */
1198 g->style = STYLE_DEFAULT;
1200 g->bitmap = src_bitmap;
1203 /* optional zoom factor for scaling up the image to a larger size */
1204 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1205 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1206 if (g->scale_up_factor < 1)
1207 g->scale_up_factor = 1; /* no scaling */
1211 if (g->use_image_size)
1213 /* set new default bitmap size (with scaling, but without small images) */
1214 g->width = get_scaled_graphic_width(graphic);
1215 g->height = get_scaled_graphic_height(graphic);
1219 /* optional x and y tile position of animation frame sequence */
1220 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1221 g->src_x = parameter[GFX_ARG_XPOS] * TILEX;
1222 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1223 g->src_y = parameter[GFX_ARG_YPOS] * TILEY;
1225 /* optional x and y pixel position of animation frame sequence */
1226 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1227 g->src_x = parameter[GFX_ARG_X];
1228 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1229 g->src_y = parameter[GFX_ARG_Y];
1231 /* optional width and height of each animation frame */
1232 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1233 g->width = parameter[GFX_ARG_WIDTH];
1234 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1235 g->height = parameter[GFX_ARG_HEIGHT];
1241 Error(ERR_INFO_LINE, "-");
1242 Error(ERR_WARN, "invalid value %d for '%s.width' (fallback done to %d)",
1243 g->width, getTokenFromImageID(graphic), TILEX);
1244 Error(ERR_INFO_LINE, "-");
1246 g->width = TILEX; /* will be checked to be inside bitmap later */
1251 Error(ERR_INFO_LINE, "-");
1252 Error(ERR_WARN, "invalid value %d for '%s.height' (fallback done to %d)",
1253 g->height, getTokenFromImageID(graphic), TILEY);
1254 Error(ERR_INFO_LINE, "-");
1256 g->height = TILEY; /* will be checked to be inside bitmap later */
1261 /* optional zoom factor for scaling up the image to a larger size */
1262 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1263 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1264 if (g->scale_up_factor < 1)
1265 g->scale_up_factor = 1; /* no scaling */
1270 /* get final bitmap size (with scaling, but without small images) */
1271 int src_image_width = get_scaled_graphic_width(graphic);
1272 int src_image_height = get_scaled_graphic_height(graphic);
1274 if (src_image_width == 0 || src_image_height == 0)
1276 /* only happens when loaded outside artwork system (like "global.busy") */
1277 src_image_width = src_bitmap->width;
1278 src_image_height = src_bitmap->height;
1281 anim_frames_per_row = src_image_width / g->width;
1282 anim_frames_per_col = src_image_height / g->height;
1284 g->src_image_width = src_image_width;
1285 g->src_image_height = src_image_height;
1288 /* correct x or y offset dependent of vertical or horizontal frame order */
1289 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1291 g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1292 parameter[GFX_ARG_OFFSET] : g->height);
1293 anim_frames_per_line = anim_frames_per_col;
1295 else /* frames are ordered horizontally */
1297 g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1298 parameter[GFX_ARG_OFFSET] : g->width);
1299 anim_frames_per_line = anim_frames_per_row;
1302 /* optionally, the x and y offset of frames can be specified directly */
1303 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1304 g->offset_x = parameter[GFX_ARG_XOFFSET];
1305 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1306 g->offset_y = parameter[GFX_ARG_YOFFSET];
1308 /* optionally, moving animations may have separate start and end graphics */
1309 g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1311 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1312 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1314 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1315 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1316 g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1317 parameter[GFX_ARG_2ND_OFFSET] : g->height);
1318 else /* frames are ordered horizontally */
1319 g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1320 parameter[GFX_ARG_2ND_OFFSET] : g->width);
1322 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1323 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1324 g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1325 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1326 g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1328 /* optionally, the second movement tile can be specified as start tile */
1329 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1330 g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1332 /* automatically determine correct number of frames, if not defined */
1333 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1334 g->anim_frames = parameter[GFX_ARG_FRAMES];
1335 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1336 g->anim_frames = anim_frames_per_row;
1337 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1338 g->anim_frames = anim_frames_per_col;
1342 if (g->anim_frames == 0) /* frames must be at least 1 */
1345 g->anim_frames_per_line =
1346 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1347 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1349 g->anim_delay = parameter[GFX_ARG_DELAY];
1350 if (g->anim_delay == 0) /* delay must be at least 1 */
1353 g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1355 if (g->anim_frames == 1)
1356 g->anim_mode = ANIM_NONE;
1359 /* automatically determine correct start frame, if not defined */
1360 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1361 g->anim_start_frame = 0;
1362 else if (g->anim_mode & ANIM_REVERSE)
1363 g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1365 g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1367 /* animation synchronized with global frame counter, not move position */
1368 g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1370 /* optional element for cloning crumble graphics */
1371 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1372 g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1374 /* optional element for cloning digging graphics */
1375 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1376 g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1378 /* optional border size for "crumbling" diggable graphics */
1379 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1380 g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1382 /* this is only used for player "boring" and "sleeping" actions */
1383 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1384 g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1385 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1386 g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1387 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1388 g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1389 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1390 g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1392 /* this is only used for toon animations */
1393 g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1394 g->step_delay = parameter[GFX_ARG_STEP_DELAY];
1396 /* this is only used for drawing font characters */
1397 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1398 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1400 /* this is only used for drawing envelope graphics */
1401 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1403 /* optional graphic for cloning all graphics settings */
1404 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1405 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1407 /* optional settings for drawing title screens and title messages */
1408 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1409 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1410 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1411 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1412 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1413 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1414 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1415 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1416 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1417 g->align = parameter[GFX_ARG_ALIGN];
1418 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1419 g->valign = parameter[GFX_ARG_VALIGN];
1420 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1421 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1423 if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
1424 g->class = parameter[GFX_ARG_CLASS];
1425 if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
1426 g->style = parameter[GFX_ARG_STYLE];
1428 /* this is only used for drawing menu buttons and text */
1429 g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
1430 g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
1431 g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
1432 g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
1435 static void set_graphic_parameters(int graphic)
1438 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1439 char **parameter_raw = image->parameter;
1440 Bitmap *src_bitmap = getBitmapFromImageID(graphic);
1441 int parameter[NUM_GFX_ARGS];
1444 /* if fallback to default artwork is done, also use the default parameters */
1445 if (image->fallback_to_default)
1446 parameter_raw = image->default_parameter;
1448 /* get integer values from string parameters */
1449 for (i = 0; i < NUM_GFX_ARGS; i++)
1450 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1451 image_config_suffix[i].token,
1452 image_config_suffix[i].type);
1454 set_graphic_parameters_ext(graphic, parameter, src_bitmap);
1458 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1459 char **parameter_raw = image->parameter;
1460 Bitmap *src_bitmap = getBitmapFromImageID(graphic);
1461 int parameter[NUM_GFX_ARGS];
1462 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1463 int anim_frames_per_line = 1;
1466 /* if fallback to default artwork is done, also use the default parameters */
1467 if (image->fallback_to_default)
1468 parameter_raw = image->default_parameter;
1470 /* get integer values from string parameters */
1471 for (i = 0; i < NUM_GFX_ARGS; i++)
1472 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1473 image_config_suffix[i].token,
1474 image_config_suffix[i].type);
1476 graphic_info[graphic].bitmap = src_bitmap;
1478 /* always start with reliable default values */
1479 graphic_info[graphic].src_image_width = 0;
1480 graphic_info[graphic].src_image_height = 0;
1481 graphic_info[graphic].src_x = 0;
1482 graphic_info[graphic].src_y = 0;
1483 graphic_info[graphic].width = TILEX; /* default for element graphics */
1484 graphic_info[graphic].height = TILEY; /* default for element graphics */
1485 graphic_info[graphic].offset_x = 0; /* one or both of these values ... */
1486 graphic_info[graphic].offset_y = 0; /* ... will be corrected later */
1487 graphic_info[graphic].offset2_x = 0; /* one or both of these values ... */
1488 graphic_info[graphic].offset2_y = 0; /* ... will be corrected later */
1489 graphic_info[graphic].swap_double_tiles = -1; /* auto-detect tile swapping */
1490 graphic_info[graphic].crumbled_like = -1; /* do not use clone element */
1491 graphic_info[graphic].diggable_like = -1; /* do not use clone element */
1492 graphic_info[graphic].border_size = TILEX / 8; /* "CRUMBLED" border size */
1493 graphic_info[graphic].scale_up_factor = 1; /* default: no scaling up */
1494 graphic_info[graphic].clone_from = -1; /* do not use clone graphic */
1495 graphic_info[graphic].anim_delay_fixed = 0;
1496 graphic_info[graphic].anim_delay_random = 0;
1497 graphic_info[graphic].post_delay_fixed = 0;
1498 graphic_info[graphic].post_delay_random = 0;
1499 graphic_info[graphic].fade_mode = FADE_MODE_DEFAULT;
1500 graphic_info[graphic].fade_delay = -1;
1501 graphic_info[graphic].post_delay = -1;
1502 graphic_info[graphic].auto_delay = -1;
1503 graphic_info[graphic].align = ALIGN_CENTER; /* default for title screens */
1504 graphic_info[graphic].valign = VALIGN_MIDDLE; /* default for title screens */
1505 graphic_info[graphic].sort_priority = 0; /* default for title screens */
1508 /* optional zoom factor for scaling up the image to a larger size */
1509 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1510 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1511 if (graphic_info[graphic].scale_up_factor < 1)
1512 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
1516 if (graphic_info[graphic].use_image_size)
1518 /* set new default bitmap size (with scaling, but without small images) */
1519 graphic_info[graphic].width = get_scaled_graphic_width(graphic);
1520 graphic_info[graphic].height = get_scaled_graphic_height(graphic);
1524 /* optional x and y tile position of animation frame sequence */
1525 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1526 graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
1527 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1528 graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
1530 /* optional x and y pixel position of animation frame sequence */
1531 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1532 graphic_info[graphic].src_x = parameter[GFX_ARG_X];
1533 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1534 graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
1536 /* optional width and height of each animation frame */
1537 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1538 graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
1539 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1540 graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
1543 /* optional zoom factor for scaling up the image to a larger size */
1544 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1545 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1546 if (graphic_info[graphic].scale_up_factor < 1)
1547 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
1552 /* get final bitmap size (with scaling, but without small images) */
1553 int src_image_width = get_scaled_graphic_width(graphic);
1554 int src_image_height = get_scaled_graphic_height(graphic);
1556 anim_frames_per_row = src_image_width / graphic_info[graphic].width;
1557 anim_frames_per_col = src_image_height / graphic_info[graphic].height;
1559 graphic_info[graphic].src_image_width = src_image_width;
1560 graphic_info[graphic].src_image_height = src_image_height;
1563 /* correct x or y offset dependent of vertical or horizontal frame order */
1564 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1566 graphic_info[graphic].offset_y =
1567 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1568 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
1569 anim_frames_per_line = anim_frames_per_col;
1571 else /* frames are ordered horizontally */
1573 graphic_info[graphic].offset_x =
1574 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1575 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
1576 anim_frames_per_line = anim_frames_per_row;
1579 /* optionally, the x and y offset of frames can be specified directly */
1580 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1581 graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
1582 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1583 graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
1585 /* optionally, moving animations may have separate start and end graphics */
1586 graphic_info[graphic].double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1588 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1589 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1591 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1592 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1593 graphic_info[graphic].offset2_y =
1594 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1595 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].height);
1596 else /* frames are ordered horizontally */
1597 graphic_info[graphic].offset2_x =
1598 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1599 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].width);
1601 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1602 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1603 graphic_info[graphic].offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1604 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1605 graphic_info[graphic].offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1607 /* optionally, the second movement tile can be specified as start tile */
1608 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1609 graphic_info[graphic].swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1611 /* automatically determine correct number of frames, if not defined */
1612 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1613 graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
1614 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1615 graphic_info[graphic].anim_frames = anim_frames_per_row;
1616 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1617 graphic_info[graphic].anim_frames = anim_frames_per_col;
1619 graphic_info[graphic].anim_frames = 1;
1621 if (graphic_info[graphic].anim_frames == 0) /* frames must be at least 1 */
1622 graphic_info[graphic].anim_frames = 1;
1624 graphic_info[graphic].anim_frames_per_line =
1625 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1626 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1628 graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
1629 if (graphic_info[graphic].anim_delay == 0) /* delay must be at least 1 */
1630 graphic_info[graphic].anim_delay = 1;
1632 graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
1634 if (graphic_info[graphic].anim_frames == 1)
1635 graphic_info[graphic].anim_mode = ANIM_NONE;
1638 /* automatically determine correct start frame, if not defined */
1639 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1640 graphic_info[graphic].anim_start_frame = 0;
1641 else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
1642 graphic_info[graphic].anim_start_frame =
1643 graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1645 graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
1647 /* animation synchronized with global frame counter, not move position */
1648 graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1650 /* optional element for cloning crumble graphics */
1651 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1652 graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1654 /* optional element for cloning digging graphics */
1655 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1656 graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1658 /* optional border size for "crumbling" diggable graphics */
1659 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1660 graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
1662 /* this is only used for player "boring" and "sleeping" actions */
1663 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1664 graphic_info[graphic].anim_delay_fixed =
1665 parameter[GFX_ARG_ANIM_DELAY_FIXED];
1666 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1667 graphic_info[graphic].anim_delay_random =
1668 parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1669 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1670 graphic_info[graphic].post_delay_fixed =
1671 parameter[GFX_ARG_POST_DELAY_FIXED];
1672 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1673 graphic_info[graphic].post_delay_random =
1674 parameter[GFX_ARG_POST_DELAY_RANDOM];
1676 /* this is only used for toon animations */
1677 graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
1678 graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY];
1680 /* this is only used for drawing font characters */
1681 graphic_info[graphic].draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1682 graphic_info[graphic].draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1684 /* this is only used for drawing envelope graphics */
1685 graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1687 /* optional graphic for cloning all graphics settings */
1688 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1689 graphic_info[graphic].clone_from = parameter[GFX_ARG_CLONE_FROM];
1691 /* optional settings for drawing title screens and title messages */
1692 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1693 graphic_info[graphic].fade_mode = parameter[GFX_ARG_FADE_MODE];
1694 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1695 graphic_info[graphic].fade_delay = parameter[GFX_ARG_FADE_DELAY];
1696 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1697 graphic_info[graphic].post_delay = parameter[GFX_ARG_POST_DELAY];
1698 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1699 graphic_info[graphic].auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1700 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1701 graphic_info[graphic].align = parameter[GFX_ARG_ALIGN];
1702 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1703 graphic_info[graphic].valign = parameter[GFX_ARG_VALIGN];
1704 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1705 graphic_info[graphic].sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1708 UPDATE_BUSY_STATE();
1711 static void set_cloned_graphic_parameters(int graphic)
1713 int fallback_graphic = IMG_CHAR_EXCLAM;
1714 int max_num_images = getImageListSize();
1715 int clone_graphic = graphic_info[graphic].clone_from;
1716 int num_references_followed = 1;
1718 while (graphic_info[clone_graphic].clone_from != -1 &&
1719 num_references_followed < max_num_images)
1721 clone_graphic = graphic_info[clone_graphic].clone_from;
1723 num_references_followed++;
1726 if (num_references_followed >= max_num_images)
1728 Error(ERR_INFO_LINE, "-");
1729 Error(ERR_INFO, "warning: error found in config file:");
1730 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1731 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1732 Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1733 Error(ERR_INFO, "custom graphic rejected for this element/action");
1735 if (graphic == fallback_graphic)
1736 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1738 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1739 Error(ERR_INFO_LINE, "-");
1741 graphic_info[graphic] = graphic_info[fallback_graphic];
1745 graphic_info[graphic] = graphic_info[clone_graphic];
1746 graphic_info[graphic].clone_from = clone_graphic;
1750 static void InitGraphicInfo()
1752 int fallback_graphic = IMG_CHAR_EXCLAM;
1753 int num_images = getImageListSize();
1756 /* use image size as default values for width and height for these images */
1757 static int full_size_graphics[] =
1762 IMG_BACKGROUND_ENVELOPE_1,
1763 IMG_BACKGROUND_ENVELOPE_2,
1764 IMG_BACKGROUND_ENVELOPE_3,
1765 IMG_BACKGROUND_ENVELOPE_4,
1766 IMG_BACKGROUND_REQUEST,
1769 IMG_BACKGROUND_TITLE_INITIAL,
1770 IMG_BACKGROUND_TITLE,
1771 IMG_BACKGROUND_MAIN,
1772 IMG_BACKGROUND_LEVELS,
1773 IMG_BACKGROUND_LEVELNR,
1774 IMG_BACKGROUND_SCORES,
1775 IMG_BACKGROUND_EDITOR,
1776 IMG_BACKGROUND_INFO,
1777 IMG_BACKGROUND_INFO_ELEMENTS,
1778 IMG_BACKGROUND_INFO_MUSIC,
1779 IMG_BACKGROUND_INFO_CREDITS,
1780 IMG_BACKGROUND_INFO_PROGRAM,
1781 IMG_BACKGROUND_INFO_VERSION,
1782 IMG_BACKGROUND_INFO_LEVELSET,
1783 IMG_BACKGROUND_SETUP,
1784 IMG_BACKGROUND_PLAYING,
1785 IMG_BACKGROUND_DOOR,
1786 IMG_BACKGROUND_TAPE,
1787 IMG_BACKGROUND_PANEL,
1788 IMG_BACKGROUND_PALETTE,
1789 IMG_BACKGROUND_TOOLBOX,
1791 IMG_TITLESCREEN_INITIAL_1,
1792 IMG_TITLESCREEN_INITIAL_2,
1793 IMG_TITLESCREEN_INITIAL_3,
1794 IMG_TITLESCREEN_INITIAL_4,
1795 IMG_TITLESCREEN_INITIAL_5,
1802 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1,
1803 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2,
1804 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3,
1805 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4,
1806 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5,
1807 IMG_BACKGROUND_TITLEMESSAGE_1,
1808 IMG_BACKGROUND_TITLEMESSAGE_2,
1809 IMG_BACKGROUND_TITLEMESSAGE_3,
1810 IMG_BACKGROUND_TITLEMESSAGE_4,
1811 IMG_BACKGROUND_TITLEMESSAGE_5,
1816 checked_free(graphic_info);
1818 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1821 /* initialize "use_image_size" flag with default value */
1822 for (i = 0; i < num_images; i++)
1823 graphic_info[i].use_image_size = FALSE;
1825 /* initialize "use_image_size" flag from static configuration above */
1826 for (i = 0; full_size_graphics[i] != -1; i++)
1827 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1830 /* first set all graphic paramaters ... */
1831 for (i = 0; i < num_images; i++)
1832 set_graphic_parameters(i);
1834 /* ... then copy these parameters for cloned graphics */
1835 for (i = 0; i < num_images; i++)
1836 if (graphic_info[i].clone_from != -1)
1837 set_cloned_graphic_parameters(i);
1839 for (i = 0; i < num_images; i++)
1844 int first_frame, last_frame;
1845 int src_bitmap_width, src_bitmap_height;
1847 /* now check if no animation frames are outside of the loaded image */
1849 if (graphic_info[i].bitmap == NULL)
1850 continue; /* skip check for optional images that are undefined */
1852 /* get image size (this can differ from the standard element tile size!) */
1853 width = graphic_info[i].width;
1854 height = graphic_info[i].height;
1856 /* get final bitmap size (with scaling, but without small images) */
1857 src_bitmap_width = graphic_info[i].src_image_width;
1858 src_bitmap_height = graphic_info[i].src_image_height;
1860 /* check if first animation frame is inside specified bitmap */
1863 getFixedGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1866 /* this avoids calculating wrong start position for out-of-bounds frame */
1867 src_x = graphic_info[i].src_x;
1868 src_y = graphic_info[i].src_y;
1871 if (src_x < 0 || src_y < 0 ||
1872 src_x + width > src_bitmap_width ||
1873 src_y + height > src_bitmap_height)
1875 Error(ERR_INFO_LINE, "-");
1876 Error(ERR_INFO, "warning: error found in config file:");
1877 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1878 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1879 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1881 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1882 src_x, src_y, src_bitmap_width, src_bitmap_height);
1883 Error(ERR_INFO, "custom graphic rejected for this element/action");
1885 if (i == fallback_graphic)
1886 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1888 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1889 Error(ERR_INFO_LINE, "-");
1891 graphic_info[i] = graphic_info[fallback_graphic];
1894 /* check if last animation frame is inside specified bitmap */
1896 last_frame = graphic_info[i].anim_frames - 1;
1897 getFixedGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1899 if (src_x < 0 || src_y < 0 ||
1900 src_x + width > src_bitmap_width ||
1901 src_y + height > src_bitmap_height)
1903 Error(ERR_INFO_LINE, "-");
1904 Error(ERR_INFO, "warning: error found in config file:");
1905 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1906 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1907 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1909 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1910 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1911 Error(ERR_INFO, "::: %d, %d", width, height);
1912 Error(ERR_INFO, "custom graphic rejected for this element/action");
1914 if (i == fallback_graphic)
1915 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1917 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1918 Error(ERR_INFO_LINE, "-");
1920 graphic_info[i] = graphic_info[fallback_graphic];
1925 static void InitGraphicCompatibilityInfo()
1927 struct FileInfo *fi_global_door =
1928 getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1929 int num_images = getImageListSize();
1932 /* the following compatibility handling is needed for the following case:
1933 versions up to 3.3.0.0 used one large bitmap "global.door" for various
1934 graphics mainly used for door and panel graphics, like editor, tape and
1935 in-game buttons with hard-coded bitmap positions and button sizes; as
1936 these graphics now have individual definitions, redefining "global.door"
1937 to change all these graphics at once like before does not work anymore
1938 (because all those individual definitions still have their default values);
1939 to solve this, remap all those individual definitions that are not
1940 redefined to the new bitmap of "global.door" if it was redefined */
1942 /* special compatibility handling if image "global.door" was redefined */
1943 if (fi_global_door->redefined)
1945 for (i = 0; i < num_images; i++)
1947 struct FileInfo *fi = getImageListEntryFromImageID(i);
1949 /* process only those images that still use the default settings */
1952 /* process all images which default to same image as "global.door" */
1953 if (strEqual(fi->default_filename, fi_global_door->default_filename))
1955 // printf("::: special treatment needed for token '%s'\n", fi->token);
1957 graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
1964 InitGraphicCompatibilityInfo_Doors();
1971 int *width, *height;
1976 { IMG_DOOR_1_WING_LEFT, &door_1.width, &door_1.height, FALSE },
1977 { IMG_DOOR_1_WING_RIGHT, &door_1.width, &door_1.height, TRUE },
1978 { IMG_DOOR_2_WING_LEFT, &door_2.width, &door_2.height, FALSE },
1979 { IMG_DOOR_2_WING_RIGHT, &door_2.width, &door_2.height, TRUE },
1981 { 0, NULL, NULL, FALSE }
1984 for (i = 0; doors[i].graphic != 0; i++)
1986 int graphic = doors[i].graphic;
1987 int *width = doors[i].width;
1988 int *height = doors[i].height;
1989 boolean right_wing = doors[i].right_wing;
1991 struct FileInfo *fi = getImageListEntryFromImageID(graphic);
1992 struct GraphicInfo *g = &graphic_info[graphic];
1998 // correct start position for right wing of "standard" door graphic
2000 g->src_x += g->width - *width;
2006 g->height = *height;
2012 for (i = 0; i < num_images; i++)
2014 struct FileInfo *fi = getImageListEntryFromImageID(i);
2016 if (i == IMG_GLOBAL_DOOR)
2018 printf("::: %s, %s, %d\n",
2019 fi->default_filename,
2027 static void InitElementSoundInfo()
2029 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
2030 int num_property_mappings = getSoundListPropertyMappingSize();
2033 /* set values to -1 to identify later as "uninitialized" values */
2034 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2035 for (act = 0; act < NUM_ACTIONS; act++)
2036 element_info[i].sound[act] = -1;
2038 /* initialize element/sound mapping from static configuration */
2039 for (i = 0; element_to_sound[i].element > -1; i++)
2041 int element = element_to_sound[i].element;
2042 int action = element_to_sound[i].action;
2043 int sound = element_to_sound[i].sound;
2044 boolean is_class = element_to_sound[i].is_class;
2047 action = ACTION_DEFAULT;
2050 element_info[element].sound[action] = sound;
2052 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2053 if (strEqual(element_info[j].class_name,
2054 element_info[element].class_name))
2055 element_info[j].sound[action] = sound;
2058 /* initialize element class/sound mapping from dynamic configuration */
2059 for (i = 0; i < num_property_mappings; i++)
2061 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
2062 int action = property_mapping[i].ext1_index;
2063 int sound = property_mapping[i].artwork_index;
2065 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
2069 action = ACTION_DEFAULT;
2071 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2072 if (strEqual(element_info[j].class_name,
2073 element_info[element_class].class_name))
2074 element_info[j].sound[action] = sound;
2077 /* initialize element/sound mapping from dynamic configuration */
2078 for (i = 0; i < num_property_mappings; i++)
2080 int element = property_mapping[i].base_index;
2081 int action = property_mapping[i].ext1_index;
2082 int sound = property_mapping[i].artwork_index;
2084 if (element >= MAX_NUM_ELEMENTS)
2088 action = ACTION_DEFAULT;
2090 element_info[element].sound[action] = sound;
2093 /* now set all '-1' values to element specific default values */
2094 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2096 for (act = 0; act < NUM_ACTIONS; act++)
2098 /* generic default action sound (defined by "[default]" directive) */
2099 int default_action_sound = element_info[EL_DEFAULT].sound[act];
2101 /* look for special default action sound (classic game specific) */
2102 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
2103 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
2104 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
2105 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
2106 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
2107 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
2109 /* !!! there's no such thing as a "default action sound" !!! */
2111 /* look for element specific default sound (independent from action) */
2112 if (element_info[i].sound[ACTION_DEFAULT] != -1)
2113 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
2117 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
2118 /* !!! make this better !!! */
2119 if (i == EL_EMPTY_SPACE)
2120 default_action_sound = element_info[EL_DEFAULT].sound[act];
2123 /* no sound for this specific action -- use default action sound */
2124 if (element_info[i].sound[act] == -1)
2125 element_info[i].sound[act] = default_action_sound;
2129 /* copy sound settings to some elements that are only stored in level file
2130 in native R'n'D levels, but are used by game engine in native EM levels */
2131 for (i = 0; copy_properties[i][0] != -1; i++)
2132 for (j = 1; j <= 4; j++)
2133 for (act = 0; act < NUM_ACTIONS; act++)
2134 element_info[copy_properties[i][j]].sound[act] =
2135 element_info[copy_properties[i][0]].sound[act];
2138 static void InitGameModeSoundInfo()
2142 /* set values to -1 to identify later as "uninitialized" values */
2143 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2146 /* initialize gamemode/sound mapping from static configuration */
2147 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
2149 int gamemode = gamemode_to_sound[i].gamemode;
2150 int sound = gamemode_to_sound[i].sound;
2153 gamemode = GAME_MODE_DEFAULT;
2155 menu.sound[gamemode] = sound;
2158 /* now set all '-1' values to levelset specific default values */
2159 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2160 if (menu.sound[i] == -1)
2161 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
2164 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2165 if (menu.sound[i] != -1)
2166 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
2170 static void set_sound_parameters(int sound, char **parameter_raw)
2172 int parameter[NUM_SND_ARGS];
2175 /* get integer values from string parameters */
2176 for (i = 0; i < NUM_SND_ARGS; i++)
2178 get_parameter_value(parameter_raw[i],
2179 sound_config_suffix[i].token,
2180 sound_config_suffix[i].type);
2182 /* explicit loop mode setting in configuration overrides default value */
2183 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2184 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
2186 /* sound volume to change the original volume when loading the sound file */
2187 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
2189 /* sound priority to give certain sounds a higher or lower priority */
2190 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
2193 static void InitSoundInfo()
2195 int *sound_effect_properties;
2196 int num_sounds = getSoundListSize();
2199 checked_free(sound_info);
2201 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
2202 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
2204 /* initialize sound effect for all elements to "no sound" */
2205 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2206 for (j = 0; j < NUM_ACTIONS; j++)
2207 element_info[i].sound[j] = SND_UNDEFINED;
2209 for (i = 0; i < num_sounds; i++)
2211 struct FileInfo *sound = getSoundListEntry(i);
2212 int len_effect_text = strlen(sound->token);
2214 sound_effect_properties[i] = ACTION_OTHER;
2215 sound_info[i].loop = FALSE; /* default: play sound only once */
2218 printf("::: sound %d: '%s'\n", i, sound->token);
2221 /* determine all loop sounds and identify certain sound classes */
2223 for (j = 0; element_action_info[j].suffix; j++)
2225 int len_action_text = strlen(element_action_info[j].suffix);
2227 if (len_action_text < len_effect_text &&
2228 strEqual(&sound->token[len_effect_text - len_action_text],
2229 element_action_info[j].suffix))
2231 sound_effect_properties[i] = element_action_info[j].value;
2232 sound_info[i].loop = element_action_info[j].is_loop_sound;
2238 /* associate elements and some selected sound actions */
2240 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2242 if (element_info[j].class_name)
2244 int len_class_text = strlen(element_info[j].class_name);
2246 if (len_class_text + 1 < len_effect_text &&
2247 strncmp(sound->token,
2248 element_info[j].class_name, len_class_text) == 0 &&
2249 sound->token[len_class_text] == '.')
2251 int sound_action_value = sound_effect_properties[i];
2253 element_info[j].sound[sound_action_value] = i;
2258 set_sound_parameters(i, sound->parameter);
2261 free(sound_effect_properties);
2264 static void InitGameModeMusicInfo()
2266 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
2267 int num_property_mappings = getMusicListPropertyMappingSize();
2268 int default_levelset_music = -1;
2271 /* set values to -1 to identify later as "uninitialized" values */
2272 for (i = 0; i < MAX_LEVELS; i++)
2273 levelset.music[i] = -1;
2274 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2277 /* initialize gamemode/music mapping from static configuration */
2278 for (i = 0; gamemode_to_music[i].music > -1; i++)
2280 int gamemode = gamemode_to_music[i].gamemode;
2281 int music = gamemode_to_music[i].music;
2284 printf("::: gamemode == %d, music == %d\n", gamemode, music);
2288 gamemode = GAME_MODE_DEFAULT;
2290 menu.music[gamemode] = music;
2293 /* initialize gamemode/music mapping from dynamic configuration */
2294 for (i = 0; i < num_property_mappings; i++)
2296 int prefix = property_mapping[i].base_index;
2297 int gamemode = property_mapping[i].ext1_index;
2298 int level = property_mapping[i].ext2_index;
2299 int music = property_mapping[i].artwork_index;
2302 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
2303 prefix, gamemode, level, music);
2306 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
2310 gamemode = GAME_MODE_DEFAULT;
2312 /* level specific music only allowed for in-game music */
2313 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
2314 gamemode = GAME_MODE_PLAYING;
2319 default_levelset_music = music;
2322 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
2323 levelset.music[level] = music;
2324 if (gamemode != GAME_MODE_PLAYING)
2325 menu.music[gamemode] = music;
2328 /* now set all '-1' values to menu specific default values */
2329 /* (undefined values of "levelset.music[]" might stay at "-1" to
2330 allow dynamic selection of music files from music directory!) */
2331 for (i = 0; i < MAX_LEVELS; i++)
2332 if (levelset.music[i] == -1)
2333 levelset.music[i] = default_levelset_music;
2334 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2335 if (menu.music[i] == -1)
2336 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
2339 for (i = 0; i < MAX_LEVELS; i++)
2340 if (levelset.music[i] != -1)
2341 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
2342 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2343 if (menu.music[i] != -1)
2344 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
2348 static void set_music_parameters(int music, char **parameter_raw)
2350 int parameter[NUM_MUS_ARGS];
2353 /* get integer values from string parameters */
2354 for (i = 0; i < NUM_MUS_ARGS; i++)
2356 get_parameter_value(parameter_raw[i],
2357 music_config_suffix[i].token,
2358 music_config_suffix[i].type);
2360 /* explicit loop mode setting in configuration overrides default value */
2361 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2362 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
2365 static void InitMusicInfo()
2367 int num_music = getMusicListSize();
2370 checked_free(music_info);
2372 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
2374 for (i = 0; i < num_music; i++)
2376 struct FileInfo *music = getMusicListEntry(i);
2377 int len_music_text = strlen(music->token);
2379 music_info[i].loop = TRUE; /* default: play music in loop mode */
2381 /* determine all loop music */
2383 for (j = 0; music_prefix_info[j].prefix; j++)
2385 int len_prefix_text = strlen(music_prefix_info[j].prefix);
2387 if (len_prefix_text < len_music_text &&
2388 strncmp(music->token,
2389 music_prefix_info[j].prefix, len_prefix_text) == 0)
2391 music_info[i].loop = music_prefix_info[j].is_loop_music;
2397 set_music_parameters(i, music->parameter);
2401 static void ReinitializeGraphics()
2403 print_timestamp_init("ReinitializeGraphics");
2405 InitGraphicInfo(); /* graphic properties mapping */
2406 print_timestamp_time("InitGraphicInfo");
2407 InitElementGraphicInfo(); /* element game graphic mapping */
2408 print_timestamp_time("InitElementGraphicInfo");
2409 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
2410 print_timestamp_time("InitElementSpecialGraphicInfo");
2412 InitElementSmallImages(); /* scale elements to all needed sizes */
2413 print_timestamp_time("InitElementSmallImages");
2414 InitScaledImages(); /* scale all other images, if needed */
2415 print_timestamp_time("InitScaledImages");
2416 InitFontGraphicInfo(); /* initialize text drawing functions */
2417 print_timestamp_time("InitFontGraphicInfo");
2419 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
2420 print_timestamp_time("InitGraphicInfo_EM");
2422 InitGraphicCompatibilityInfo();
2423 print_timestamp_time("InitGraphicCompatibilityInfo");
2425 SetMainBackgroundImage(IMG_BACKGROUND);
2426 print_timestamp_time("SetMainBackgroundImage");
2427 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2428 print_timestamp_time("SetDoorBackgroundImage");
2431 print_timestamp_time("InitGadgets");
2433 print_timestamp_time("InitToons");
2435 print_timestamp_time("InitDoors");
2437 print_timestamp_done("ReinitializeGraphics");
2440 static void ReinitializeSounds()
2442 InitSoundInfo(); /* sound properties mapping */
2443 InitElementSoundInfo(); /* element game sound mapping */
2444 InitGameModeSoundInfo(); /* game mode sound mapping */
2446 InitPlayLevelSound(); /* internal game sound settings */
2449 static void ReinitializeMusic()
2451 InitMusicInfo(); /* music properties mapping */
2452 InitGameModeMusicInfo(); /* game mode music mapping */
2455 static int get_special_property_bit(int element, int property_bit_nr)
2457 struct PropertyBitInfo
2463 static struct PropertyBitInfo pb_can_move_into_acid[] =
2465 /* the player may be able fall into acid when gravity is activated */
2470 { EL_SP_MURPHY, 0 },
2471 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2473 /* all elements that can move may be able to also move into acid */
2476 { EL_BUG_RIGHT, 1 },
2479 { EL_SPACESHIP, 2 },
2480 { EL_SPACESHIP_LEFT, 2 },
2481 { EL_SPACESHIP_RIGHT, 2 },
2482 { EL_SPACESHIP_UP, 2 },
2483 { EL_SPACESHIP_DOWN, 2 },
2484 { EL_BD_BUTTERFLY, 3 },
2485 { EL_BD_BUTTERFLY_LEFT, 3 },
2486 { EL_BD_BUTTERFLY_RIGHT, 3 },
2487 { EL_BD_BUTTERFLY_UP, 3 },
2488 { EL_BD_BUTTERFLY_DOWN, 3 },
2489 { EL_BD_FIREFLY, 4 },
2490 { EL_BD_FIREFLY_LEFT, 4 },
2491 { EL_BD_FIREFLY_RIGHT, 4 },
2492 { EL_BD_FIREFLY_UP, 4 },
2493 { EL_BD_FIREFLY_DOWN, 4 },
2495 { EL_YAMYAM_LEFT, 5 },
2496 { EL_YAMYAM_RIGHT, 5 },
2497 { EL_YAMYAM_UP, 5 },
2498 { EL_YAMYAM_DOWN, 5 },
2499 { EL_DARK_YAMYAM, 6 },
2502 { EL_PACMAN_LEFT, 8 },
2503 { EL_PACMAN_RIGHT, 8 },
2504 { EL_PACMAN_UP, 8 },
2505 { EL_PACMAN_DOWN, 8 },
2507 { EL_MOLE_LEFT, 9 },
2508 { EL_MOLE_RIGHT, 9 },
2510 { EL_MOLE_DOWN, 9 },
2514 { EL_SATELLITE, 13 },
2515 { EL_SP_SNIKSNAK, 14 },
2516 { EL_SP_ELECTRON, 15 },
2519 { EL_EMC_ANDROID, 18 },
2524 static struct PropertyBitInfo pb_dont_collide_with[] =
2526 { EL_SP_SNIKSNAK, 0 },
2527 { EL_SP_ELECTRON, 1 },
2535 struct PropertyBitInfo *pb_info;
2538 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2539 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2544 struct PropertyBitInfo *pb_info = NULL;
2547 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2548 if (pb_definition[i].bit_nr == property_bit_nr)
2549 pb_info = pb_definition[i].pb_info;
2551 if (pb_info == NULL)
2554 for (i = 0; pb_info[i].element != -1; i++)
2555 if (pb_info[i].element == element)
2556 return pb_info[i].bit_nr;
2561 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2562 boolean property_value)
2564 int bit_nr = get_special_property_bit(element, property_bit_nr);
2569 *bitfield |= (1 << bit_nr);
2571 *bitfield &= ~(1 << bit_nr);
2575 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2577 int bit_nr = get_special_property_bit(element, property_bit_nr);
2580 return ((*bitfield & (1 << bit_nr)) != 0);
2585 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2587 static int group_nr;
2588 static struct ElementGroupInfo *group;
2589 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2592 if (actual_group == NULL) /* not yet initialized */
2595 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
2597 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2598 group_element - EL_GROUP_START + 1);
2600 /* replace element which caused too deep recursion by question mark */
2601 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2606 if (recursion_depth == 0) /* initialization */
2608 group = actual_group;
2609 group_nr = GROUP_NR(group_element);
2611 group->num_elements_resolved = 0;
2612 group->choice_pos = 0;
2614 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2615 element_info[i].in_group[group_nr] = FALSE;
2618 for (i = 0; i < actual_group->num_elements; i++)
2620 int element = actual_group->element[i];
2622 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2625 if (IS_GROUP_ELEMENT(element))
2626 ResolveGroupElementExt(element, recursion_depth + 1);
2629 group->element_resolved[group->num_elements_resolved++] = element;
2630 element_info[element].in_group[group_nr] = TRUE;
2635 void ResolveGroupElement(int group_element)
2637 ResolveGroupElementExt(group_element, 0);
2640 void InitElementPropertiesStatic()
2642 static boolean clipboard_elements_initialized = FALSE;
2644 static int ep_diggable[] =
2649 EL_SP_BUGGY_BASE_ACTIVATING,
2652 EL_INVISIBLE_SAND_ACTIVE,
2655 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2656 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2661 EL_SP_BUGGY_BASE_ACTIVE,
2668 static int ep_collectible_only[] =
2690 EL_DYNABOMB_INCREASE_NUMBER,
2691 EL_DYNABOMB_INCREASE_SIZE,
2692 EL_DYNABOMB_INCREASE_POWER,
2710 /* !!! handle separately !!! */
2711 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2717 static int ep_dont_run_into[] =
2719 /* same elements as in 'ep_dont_touch' */
2725 /* same elements as in 'ep_dont_collide_with' */
2737 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2742 EL_SP_BUGGY_BASE_ACTIVE,
2749 static int ep_dont_collide_with[] =
2751 /* same elements as in 'ep_dont_touch' */
2768 static int ep_dont_touch[] =
2778 static int ep_indestructible[] =
2782 EL_ACID_POOL_TOPLEFT,
2783 EL_ACID_POOL_TOPRIGHT,
2784 EL_ACID_POOL_BOTTOMLEFT,
2785 EL_ACID_POOL_BOTTOM,
2786 EL_ACID_POOL_BOTTOMRIGHT,
2787 EL_SP_HARDWARE_GRAY,
2788 EL_SP_HARDWARE_GREEN,
2789 EL_SP_HARDWARE_BLUE,
2791 EL_SP_HARDWARE_YELLOW,
2792 EL_SP_HARDWARE_BASE_1,
2793 EL_SP_HARDWARE_BASE_2,
2794 EL_SP_HARDWARE_BASE_3,
2795 EL_SP_HARDWARE_BASE_4,
2796 EL_SP_HARDWARE_BASE_5,
2797 EL_SP_HARDWARE_BASE_6,
2798 EL_INVISIBLE_STEELWALL,
2799 EL_INVISIBLE_STEELWALL_ACTIVE,
2800 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2801 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2802 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2803 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2804 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2805 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2806 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2807 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2808 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2809 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2810 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2811 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2813 EL_LIGHT_SWITCH_ACTIVE,
2814 EL_SIGN_EXCLAMATION,
2815 EL_SIGN_RADIOACTIVITY,
2822 EL_SIGN_ENTRY_FORBIDDEN,
2823 EL_SIGN_EMERGENCY_EXIT,
2831 EL_STEEL_EXIT_CLOSED,
2833 EL_STEEL_EXIT_OPENING,
2834 EL_STEEL_EXIT_CLOSING,
2835 EL_EM_STEEL_EXIT_CLOSED,
2836 EL_EM_STEEL_EXIT_OPEN,
2837 EL_EM_STEEL_EXIT_OPENING,
2838 EL_EM_STEEL_EXIT_CLOSING,
2839 EL_DC_STEELWALL_1_LEFT,
2840 EL_DC_STEELWALL_1_RIGHT,
2841 EL_DC_STEELWALL_1_TOP,
2842 EL_DC_STEELWALL_1_BOTTOM,
2843 EL_DC_STEELWALL_1_HORIZONTAL,
2844 EL_DC_STEELWALL_1_VERTICAL,
2845 EL_DC_STEELWALL_1_TOPLEFT,
2846 EL_DC_STEELWALL_1_TOPRIGHT,
2847 EL_DC_STEELWALL_1_BOTTOMLEFT,
2848 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2849 EL_DC_STEELWALL_1_TOPLEFT_2,
2850 EL_DC_STEELWALL_1_TOPRIGHT_2,
2851 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2852 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2853 EL_DC_STEELWALL_2_LEFT,
2854 EL_DC_STEELWALL_2_RIGHT,
2855 EL_DC_STEELWALL_2_TOP,
2856 EL_DC_STEELWALL_2_BOTTOM,
2857 EL_DC_STEELWALL_2_HORIZONTAL,
2858 EL_DC_STEELWALL_2_VERTICAL,
2859 EL_DC_STEELWALL_2_MIDDLE,
2860 EL_DC_STEELWALL_2_SINGLE,
2861 EL_STEELWALL_SLIPPERY,
2875 EL_GATE_1_GRAY_ACTIVE,
2876 EL_GATE_2_GRAY_ACTIVE,
2877 EL_GATE_3_GRAY_ACTIVE,
2878 EL_GATE_4_GRAY_ACTIVE,
2887 EL_EM_GATE_1_GRAY_ACTIVE,
2888 EL_EM_GATE_2_GRAY_ACTIVE,
2889 EL_EM_GATE_3_GRAY_ACTIVE,
2890 EL_EM_GATE_4_GRAY_ACTIVE,
2899 EL_EMC_GATE_5_GRAY_ACTIVE,
2900 EL_EMC_GATE_6_GRAY_ACTIVE,
2901 EL_EMC_GATE_7_GRAY_ACTIVE,
2902 EL_EMC_GATE_8_GRAY_ACTIVE,
2904 EL_DC_GATE_WHITE_GRAY,
2905 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2906 EL_DC_GATE_FAKE_GRAY,
2908 EL_SWITCHGATE_OPENING,
2909 EL_SWITCHGATE_CLOSED,
2910 EL_SWITCHGATE_CLOSING,
2912 EL_DC_SWITCHGATE_SWITCH_UP,
2913 EL_DC_SWITCHGATE_SWITCH_DOWN,
2916 EL_TIMEGATE_OPENING,
2918 EL_TIMEGATE_CLOSING,
2920 EL_DC_TIMEGATE_SWITCH,
2921 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2926 EL_TUBE_VERTICAL_LEFT,
2927 EL_TUBE_VERTICAL_RIGHT,
2928 EL_TUBE_HORIZONTAL_UP,
2929 EL_TUBE_HORIZONTAL_DOWN,
2934 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2935 EL_EXPANDABLE_STEELWALL_VERTICAL,
2936 EL_EXPANDABLE_STEELWALL_ANY,
2941 static int ep_slippery[] =
2955 EL_ROBOT_WHEEL_ACTIVE,
2961 EL_ACID_POOL_TOPLEFT,
2962 EL_ACID_POOL_TOPRIGHT,
2972 EL_STEELWALL_SLIPPERY,
2975 EL_EMC_WALL_SLIPPERY_1,
2976 EL_EMC_WALL_SLIPPERY_2,
2977 EL_EMC_WALL_SLIPPERY_3,
2978 EL_EMC_WALL_SLIPPERY_4,
2980 EL_EMC_MAGIC_BALL_ACTIVE,
2985 static int ep_can_change[] =
2990 static int ep_can_move[] =
2992 /* same elements as in 'pb_can_move_into_acid' */
3015 static int ep_can_fall[] =
3029 EL_QUICKSAND_FAST_FULL,
3031 EL_BD_MAGIC_WALL_FULL,
3032 EL_DC_MAGIC_WALL_FULL,
3046 static int ep_can_smash_player[] =
3072 static int ep_can_smash_enemies[] =
3081 static int ep_can_smash_everything[] =
3090 static int ep_explodes_by_fire[] =
3092 /* same elements as in 'ep_explodes_impact' */
3097 /* same elements as in 'ep_explodes_smashed' */
3107 EL_EM_DYNAMITE_ACTIVE,
3108 EL_DYNABOMB_PLAYER_1_ACTIVE,
3109 EL_DYNABOMB_PLAYER_2_ACTIVE,
3110 EL_DYNABOMB_PLAYER_3_ACTIVE,
3111 EL_DYNABOMB_PLAYER_4_ACTIVE,
3112 EL_DYNABOMB_INCREASE_NUMBER,
3113 EL_DYNABOMB_INCREASE_SIZE,
3114 EL_DYNABOMB_INCREASE_POWER,
3115 EL_SP_DISK_RED_ACTIVE,
3129 static int ep_explodes_smashed[] =
3131 /* same elements as in 'ep_explodes_impact' */
3145 static int ep_explodes_impact[] =
3154 static int ep_walkable_over[] =
3158 EL_SOKOBAN_FIELD_EMPTY,
3167 EL_EM_STEEL_EXIT_OPEN,
3169 EL_EM_STEEL_EXIT_OPENING,
3179 EL_GATE_1_GRAY_ACTIVE,
3180 EL_GATE_2_GRAY_ACTIVE,
3181 EL_GATE_3_GRAY_ACTIVE,
3182 EL_GATE_4_GRAY_ACTIVE,
3190 static int ep_walkable_inside[] =
3195 EL_TUBE_VERTICAL_LEFT,
3196 EL_TUBE_VERTICAL_RIGHT,
3197 EL_TUBE_HORIZONTAL_UP,
3198 EL_TUBE_HORIZONTAL_DOWN,
3207 static int ep_walkable_under[] =
3212 static int ep_passable_over[] =
3222 EL_EM_GATE_1_GRAY_ACTIVE,
3223 EL_EM_GATE_2_GRAY_ACTIVE,
3224 EL_EM_GATE_3_GRAY_ACTIVE,
3225 EL_EM_GATE_4_GRAY_ACTIVE,
3234 EL_EMC_GATE_5_GRAY_ACTIVE,
3235 EL_EMC_GATE_6_GRAY_ACTIVE,
3236 EL_EMC_GATE_7_GRAY_ACTIVE,
3237 EL_EMC_GATE_8_GRAY_ACTIVE,
3239 EL_DC_GATE_WHITE_GRAY,
3240 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3247 static int ep_passable_inside[] =
3253 EL_SP_PORT_HORIZONTAL,
3254 EL_SP_PORT_VERTICAL,
3256 EL_SP_GRAVITY_PORT_LEFT,
3257 EL_SP_GRAVITY_PORT_RIGHT,
3258 EL_SP_GRAVITY_PORT_UP,
3259 EL_SP_GRAVITY_PORT_DOWN,
3260 EL_SP_GRAVITY_ON_PORT_LEFT,
3261 EL_SP_GRAVITY_ON_PORT_RIGHT,
3262 EL_SP_GRAVITY_ON_PORT_UP,
3263 EL_SP_GRAVITY_ON_PORT_DOWN,
3264 EL_SP_GRAVITY_OFF_PORT_LEFT,
3265 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3266 EL_SP_GRAVITY_OFF_PORT_UP,
3267 EL_SP_GRAVITY_OFF_PORT_DOWN,
3272 static int ep_passable_under[] =
3277 static int ep_droppable[] =
3282 static int ep_explodes_1x1_old[] =
3287 static int ep_pushable[] =
3299 EL_SOKOBAN_FIELD_FULL,
3308 static int ep_explodes_cross_old[] =
3313 static int ep_protected[] =
3315 /* same elements as in 'ep_walkable_inside' */
3319 EL_TUBE_VERTICAL_LEFT,
3320 EL_TUBE_VERTICAL_RIGHT,
3321 EL_TUBE_HORIZONTAL_UP,
3322 EL_TUBE_HORIZONTAL_DOWN,
3328 /* same elements as in 'ep_passable_over' */
3337 EL_EM_GATE_1_GRAY_ACTIVE,
3338 EL_EM_GATE_2_GRAY_ACTIVE,
3339 EL_EM_GATE_3_GRAY_ACTIVE,
3340 EL_EM_GATE_4_GRAY_ACTIVE,
3349 EL_EMC_GATE_5_GRAY_ACTIVE,
3350 EL_EMC_GATE_6_GRAY_ACTIVE,
3351 EL_EMC_GATE_7_GRAY_ACTIVE,
3352 EL_EMC_GATE_8_GRAY_ACTIVE,
3354 EL_DC_GATE_WHITE_GRAY,
3355 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3359 /* same elements as in 'ep_passable_inside' */
3364 EL_SP_PORT_HORIZONTAL,
3365 EL_SP_PORT_VERTICAL,
3367 EL_SP_GRAVITY_PORT_LEFT,
3368 EL_SP_GRAVITY_PORT_RIGHT,
3369 EL_SP_GRAVITY_PORT_UP,
3370 EL_SP_GRAVITY_PORT_DOWN,
3371 EL_SP_GRAVITY_ON_PORT_LEFT,
3372 EL_SP_GRAVITY_ON_PORT_RIGHT,
3373 EL_SP_GRAVITY_ON_PORT_UP,
3374 EL_SP_GRAVITY_ON_PORT_DOWN,
3375 EL_SP_GRAVITY_OFF_PORT_LEFT,
3376 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3377 EL_SP_GRAVITY_OFF_PORT_UP,
3378 EL_SP_GRAVITY_OFF_PORT_DOWN,
3383 static int ep_throwable[] =
3388 static int ep_can_explode[] =
3390 /* same elements as in 'ep_explodes_impact' */
3395 /* same elements as in 'ep_explodes_smashed' */
3401 /* elements that can explode by explosion or by dragonfire */
3405 EL_EM_DYNAMITE_ACTIVE,
3406 EL_DYNABOMB_PLAYER_1_ACTIVE,
3407 EL_DYNABOMB_PLAYER_2_ACTIVE,
3408 EL_DYNABOMB_PLAYER_3_ACTIVE,
3409 EL_DYNABOMB_PLAYER_4_ACTIVE,
3410 EL_DYNABOMB_INCREASE_NUMBER,
3411 EL_DYNABOMB_INCREASE_SIZE,
3412 EL_DYNABOMB_INCREASE_POWER,
3413 EL_SP_DISK_RED_ACTIVE,
3421 /* elements that can explode only by explosion */
3427 static int ep_gravity_reachable[] =
3433 EL_INVISIBLE_SAND_ACTIVE,
3438 EL_SP_PORT_HORIZONTAL,
3439 EL_SP_PORT_VERTICAL,
3441 EL_SP_GRAVITY_PORT_LEFT,
3442 EL_SP_GRAVITY_PORT_RIGHT,
3443 EL_SP_GRAVITY_PORT_UP,
3444 EL_SP_GRAVITY_PORT_DOWN,
3445 EL_SP_GRAVITY_ON_PORT_LEFT,
3446 EL_SP_GRAVITY_ON_PORT_RIGHT,
3447 EL_SP_GRAVITY_ON_PORT_UP,
3448 EL_SP_GRAVITY_ON_PORT_DOWN,
3449 EL_SP_GRAVITY_OFF_PORT_LEFT,
3450 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3451 EL_SP_GRAVITY_OFF_PORT_UP,
3452 EL_SP_GRAVITY_OFF_PORT_DOWN,
3458 static int ep_player[] =
3465 EL_SOKOBAN_FIELD_PLAYER,
3471 static int ep_can_pass_magic_wall[] =
3485 static int ep_can_pass_dc_magic_wall[] =
3501 static int ep_switchable[] =
3505 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3506 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3507 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3508 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3509 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3510 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3511 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3512 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3513 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3514 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3515 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3516 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3517 EL_SWITCHGATE_SWITCH_UP,
3518 EL_SWITCHGATE_SWITCH_DOWN,
3519 EL_DC_SWITCHGATE_SWITCH_UP,
3520 EL_DC_SWITCHGATE_SWITCH_DOWN,
3522 EL_LIGHT_SWITCH_ACTIVE,
3524 EL_DC_TIMEGATE_SWITCH,
3525 EL_BALLOON_SWITCH_LEFT,
3526 EL_BALLOON_SWITCH_RIGHT,
3527 EL_BALLOON_SWITCH_UP,
3528 EL_BALLOON_SWITCH_DOWN,
3529 EL_BALLOON_SWITCH_ANY,
3530 EL_BALLOON_SWITCH_NONE,
3533 EL_EMC_MAGIC_BALL_SWITCH,
3534 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3539 static int ep_bd_element[] =
3573 static int ep_sp_element[] =
3575 /* should always be valid */
3578 /* standard classic Supaplex elements */
3585 EL_SP_HARDWARE_GRAY,
3593 EL_SP_GRAVITY_PORT_RIGHT,
3594 EL_SP_GRAVITY_PORT_DOWN,
3595 EL_SP_GRAVITY_PORT_LEFT,
3596 EL_SP_GRAVITY_PORT_UP,
3601 EL_SP_PORT_VERTICAL,
3602 EL_SP_PORT_HORIZONTAL,
3608 EL_SP_HARDWARE_BASE_1,
3609 EL_SP_HARDWARE_GREEN,
3610 EL_SP_HARDWARE_BLUE,
3612 EL_SP_HARDWARE_YELLOW,
3613 EL_SP_HARDWARE_BASE_2,
3614 EL_SP_HARDWARE_BASE_3,
3615 EL_SP_HARDWARE_BASE_4,
3616 EL_SP_HARDWARE_BASE_5,
3617 EL_SP_HARDWARE_BASE_6,
3621 /* additional elements that appeared in newer Supaplex levels */
3624 /* additional gravity port elements (not switching, but setting gravity) */
3625 EL_SP_GRAVITY_ON_PORT_LEFT,
3626 EL_SP_GRAVITY_ON_PORT_RIGHT,
3627 EL_SP_GRAVITY_ON_PORT_UP,
3628 EL_SP_GRAVITY_ON_PORT_DOWN,
3629 EL_SP_GRAVITY_OFF_PORT_LEFT,
3630 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3631 EL_SP_GRAVITY_OFF_PORT_UP,
3632 EL_SP_GRAVITY_OFF_PORT_DOWN,
3634 /* more than one Murphy in a level results in an inactive clone */
3637 /* runtime Supaplex elements */
3638 EL_SP_DISK_RED_ACTIVE,
3639 EL_SP_TERMINAL_ACTIVE,
3640 EL_SP_BUGGY_BASE_ACTIVATING,
3641 EL_SP_BUGGY_BASE_ACTIVE,
3648 static int ep_sb_element[] =
3653 EL_SOKOBAN_FIELD_EMPTY,
3654 EL_SOKOBAN_FIELD_FULL,
3655 EL_SOKOBAN_FIELD_PLAYER,
3660 EL_INVISIBLE_STEELWALL,
3665 static int ep_gem[] =
3677 static int ep_food_dark_yamyam[] =
3705 static int ep_food_penguin[] =
3719 static int ep_food_pig[] =
3731 static int ep_historic_wall[] =
3742 EL_GATE_1_GRAY_ACTIVE,
3743 EL_GATE_2_GRAY_ACTIVE,
3744 EL_GATE_3_GRAY_ACTIVE,
3745 EL_GATE_4_GRAY_ACTIVE,
3754 EL_EM_GATE_1_GRAY_ACTIVE,
3755 EL_EM_GATE_2_GRAY_ACTIVE,
3756 EL_EM_GATE_3_GRAY_ACTIVE,
3757 EL_EM_GATE_4_GRAY_ACTIVE,
3764 EL_EXPANDABLE_WALL_HORIZONTAL,
3765 EL_EXPANDABLE_WALL_VERTICAL,
3766 EL_EXPANDABLE_WALL_ANY,
3767 EL_EXPANDABLE_WALL_GROWING,
3768 EL_BD_EXPANDABLE_WALL,
3775 EL_SP_HARDWARE_GRAY,
3776 EL_SP_HARDWARE_GREEN,
3777 EL_SP_HARDWARE_BLUE,
3779 EL_SP_HARDWARE_YELLOW,
3780 EL_SP_HARDWARE_BASE_1,
3781 EL_SP_HARDWARE_BASE_2,
3782 EL_SP_HARDWARE_BASE_3,
3783 EL_SP_HARDWARE_BASE_4,
3784 EL_SP_HARDWARE_BASE_5,
3785 EL_SP_HARDWARE_BASE_6,
3787 EL_SP_TERMINAL_ACTIVE,
3790 EL_INVISIBLE_STEELWALL,
3791 EL_INVISIBLE_STEELWALL_ACTIVE,
3793 EL_INVISIBLE_WALL_ACTIVE,
3794 EL_STEELWALL_SLIPPERY,
3811 static int ep_historic_solid[] =
3815 EL_EXPANDABLE_WALL_HORIZONTAL,
3816 EL_EXPANDABLE_WALL_VERTICAL,
3817 EL_EXPANDABLE_WALL_ANY,
3818 EL_BD_EXPANDABLE_WALL,
3831 EL_QUICKSAND_FILLING,
3832 EL_QUICKSAND_EMPTYING,
3834 EL_MAGIC_WALL_ACTIVE,
3835 EL_MAGIC_WALL_EMPTYING,
3836 EL_MAGIC_WALL_FILLING,
3840 EL_BD_MAGIC_WALL_ACTIVE,
3841 EL_BD_MAGIC_WALL_EMPTYING,
3842 EL_BD_MAGIC_WALL_FULL,
3843 EL_BD_MAGIC_WALL_FILLING,
3844 EL_BD_MAGIC_WALL_DEAD,
3853 EL_SP_TERMINAL_ACTIVE,
3857 EL_INVISIBLE_WALL_ACTIVE,
3858 EL_SWITCHGATE_SWITCH_UP,
3859 EL_SWITCHGATE_SWITCH_DOWN,
3860 EL_DC_SWITCHGATE_SWITCH_UP,
3861 EL_DC_SWITCHGATE_SWITCH_DOWN,
3863 EL_TIMEGATE_SWITCH_ACTIVE,
3864 EL_DC_TIMEGATE_SWITCH,
3865 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3877 /* the following elements are a direct copy of "indestructible" elements,
3878 except "EL_ACID", which is "indestructible", but not "solid"! */
3883 EL_ACID_POOL_TOPLEFT,
3884 EL_ACID_POOL_TOPRIGHT,
3885 EL_ACID_POOL_BOTTOMLEFT,
3886 EL_ACID_POOL_BOTTOM,
3887 EL_ACID_POOL_BOTTOMRIGHT,
3888 EL_SP_HARDWARE_GRAY,
3889 EL_SP_HARDWARE_GREEN,
3890 EL_SP_HARDWARE_BLUE,
3892 EL_SP_HARDWARE_YELLOW,
3893 EL_SP_HARDWARE_BASE_1,
3894 EL_SP_HARDWARE_BASE_2,
3895 EL_SP_HARDWARE_BASE_3,
3896 EL_SP_HARDWARE_BASE_4,
3897 EL_SP_HARDWARE_BASE_5,
3898 EL_SP_HARDWARE_BASE_6,
3899 EL_INVISIBLE_STEELWALL,
3900 EL_INVISIBLE_STEELWALL_ACTIVE,
3901 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3902 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3903 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3904 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3905 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3906 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3907 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3908 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3909 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3910 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3911 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3912 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3914 EL_LIGHT_SWITCH_ACTIVE,
3915 EL_SIGN_EXCLAMATION,
3916 EL_SIGN_RADIOACTIVITY,
3923 EL_SIGN_ENTRY_FORBIDDEN,
3924 EL_SIGN_EMERGENCY_EXIT,
3932 EL_STEEL_EXIT_CLOSED,
3934 EL_DC_STEELWALL_1_LEFT,
3935 EL_DC_STEELWALL_1_RIGHT,
3936 EL_DC_STEELWALL_1_TOP,
3937 EL_DC_STEELWALL_1_BOTTOM,
3938 EL_DC_STEELWALL_1_HORIZONTAL,
3939 EL_DC_STEELWALL_1_VERTICAL,
3940 EL_DC_STEELWALL_1_TOPLEFT,
3941 EL_DC_STEELWALL_1_TOPRIGHT,
3942 EL_DC_STEELWALL_1_BOTTOMLEFT,
3943 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3944 EL_DC_STEELWALL_1_TOPLEFT_2,
3945 EL_DC_STEELWALL_1_TOPRIGHT_2,
3946 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3947 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3948 EL_DC_STEELWALL_2_LEFT,
3949 EL_DC_STEELWALL_2_RIGHT,
3950 EL_DC_STEELWALL_2_TOP,
3951 EL_DC_STEELWALL_2_BOTTOM,
3952 EL_DC_STEELWALL_2_HORIZONTAL,
3953 EL_DC_STEELWALL_2_VERTICAL,
3954 EL_DC_STEELWALL_2_MIDDLE,
3955 EL_DC_STEELWALL_2_SINGLE,
3956 EL_STEELWALL_SLIPPERY,
3970 EL_GATE_1_GRAY_ACTIVE,
3971 EL_GATE_2_GRAY_ACTIVE,
3972 EL_GATE_3_GRAY_ACTIVE,
3973 EL_GATE_4_GRAY_ACTIVE,
3982 EL_EM_GATE_1_GRAY_ACTIVE,
3983 EL_EM_GATE_2_GRAY_ACTIVE,
3984 EL_EM_GATE_3_GRAY_ACTIVE,
3985 EL_EM_GATE_4_GRAY_ACTIVE,
3987 EL_SWITCHGATE_OPENING,
3988 EL_SWITCHGATE_CLOSED,
3989 EL_SWITCHGATE_CLOSING,
3991 EL_TIMEGATE_OPENING,
3993 EL_TIMEGATE_CLOSING,
3997 EL_TUBE_VERTICAL_LEFT,
3998 EL_TUBE_VERTICAL_RIGHT,
3999 EL_TUBE_HORIZONTAL_UP,
4000 EL_TUBE_HORIZONTAL_DOWN,
4009 static int ep_classic_enemy[] =
4026 static int ep_belt[] =
4028 EL_CONVEYOR_BELT_1_LEFT,
4029 EL_CONVEYOR_BELT_1_MIDDLE,
4030 EL_CONVEYOR_BELT_1_RIGHT,
4031 EL_CONVEYOR_BELT_2_LEFT,
4032 EL_CONVEYOR_BELT_2_MIDDLE,
4033 EL_CONVEYOR_BELT_2_RIGHT,
4034 EL_CONVEYOR_BELT_3_LEFT,
4035 EL_CONVEYOR_BELT_3_MIDDLE,
4036 EL_CONVEYOR_BELT_3_RIGHT,
4037 EL_CONVEYOR_BELT_4_LEFT,
4038 EL_CONVEYOR_BELT_4_MIDDLE,
4039 EL_CONVEYOR_BELT_4_RIGHT,
4044 static int ep_belt_active[] =
4046 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
4047 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
4048 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
4049 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
4050 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
4051 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
4052 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
4053 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
4054 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
4055 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
4056 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
4057 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
4062 static int ep_belt_switch[] =
4064 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4065 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4066 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4067 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4068 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4069 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4070 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4071 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4072 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4073 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4074 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4075 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4080 static int ep_tube[] =
4087 EL_TUBE_HORIZONTAL_UP,
4088 EL_TUBE_HORIZONTAL_DOWN,
4090 EL_TUBE_VERTICAL_LEFT,
4091 EL_TUBE_VERTICAL_RIGHT,
4097 static int ep_acid_pool[] =
4099 EL_ACID_POOL_TOPLEFT,
4100 EL_ACID_POOL_TOPRIGHT,
4101 EL_ACID_POOL_BOTTOMLEFT,
4102 EL_ACID_POOL_BOTTOM,
4103 EL_ACID_POOL_BOTTOMRIGHT,
4108 static int ep_keygate[] =
4118 EL_GATE_1_GRAY_ACTIVE,
4119 EL_GATE_2_GRAY_ACTIVE,
4120 EL_GATE_3_GRAY_ACTIVE,
4121 EL_GATE_4_GRAY_ACTIVE,
4130 EL_EM_GATE_1_GRAY_ACTIVE,
4131 EL_EM_GATE_2_GRAY_ACTIVE,
4132 EL_EM_GATE_3_GRAY_ACTIVE,
4133 EL_EM_GATE_4_GRAY_ACTIVE,
4142 EL_EMC_GATE_5_GRAY_ACTIVE,
4143 EL_EMC_GATE_6_GRAY_ACTIVE,
4144 EL_EMC_GATE_7_GRAY_ACTIVE,
4145 EL_EMC_GATE_8_GRAY_ACTIVE,
4147 EL_DC_GATE_WHITE_GRAY,
4148 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4153 static int ep_amoeboid[] =
4165 static int ep_amoebalive[] =
4176 static int ep_has_editor_content[] =
4182 EL_SOKOBAN_FIELD_PLAYER,
4199 static int ep_can_turn_each_move[] =
4201 /* !!! do something with this one !!! */
4205 static int ep_can_grow[] =
4219 static int ep_active_bomb[] =
4222 EL_EM_DYNAMITE_ACTIVE,
4223 EL_DYNABOMB_PLAYER_1_ACTIVE,
4224 EL_DYNABOMB_PLAYER_2_ACTIVE,
4225 EL_DYNABOMB_PLAYER_3_ACTIVE,
4226 EL_DYNABOMB_PLAYER_4_ACTIVE,
4227 EL_SP_DISK_RED_ACTIVE,
4232 static int ep_inactive[] =
4242 EL_QUICKSAND_FAST_EMPTY,
4265 EL_GATE_1_GRAY_ACTIVE,
4266 EL_GATE_2_GRAY_ACTIVE,
4267 EL_GATE_3_GRAY_ACTIVE,
4268 EL_GATE_4_GRAY_ACTIVE,
4277 EL_EM_GATE_1_GRAY_ACTIVE,
4278 EL_EM_GATE_2_GRAY_ACTIVE,
4279 EL_EM_GATE_3_GRAY_ACTIVE,
4280 EL_EM_GATE_4_GRAY_ACTIVE,
4289 EL_EMC_GATE_5_GRAY_ACTIVE,
4290 EL_EMC_GATE_6_GRAY_ACTIVE,
4291 EL_EMC_GATE_7_GRAY_ACTIVE,
4292 EL_EMC_GATE_8_GRAY_ACTIVE,
4294 EL_DC_GATE_WHITE_GRAY,
4295 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4296 EL_DC_GATE_FAKE_GRAY,
4299 EL_INVISIBLE_STEELWALL,
4307 EL_WALL_EMERALD_YELLOW,
4308 EL_DYNABOMB_INCREASE_NUMBER,
4309 EL_DYNABOMB_INCREASE_SIZE,
4310 EL_DYNABOMB_INCREASE_POWER,
4314 EL_SOKOBAN_FIELD_EMPTY,
4315 EL_SOKOBAN_FIELD_FULL,
4316 EL_WALL_EMERALD_RED,
4317 EL_WALL_EMERALD_PURPLE,
4318 EL_ACID_POOL_TOPLEFT,
4319 EL_ACID_POOL_TOPRIGHT,
4320 EL_ACID_POOL_BOTTOMLEFT,
4321 EL_ACID_POOL_BOTTOM,
4322 EL_ACID_POOL_BOTTOMRIGHT,
4326 EL_BD_MAGIC_WALL_DEAD,
4328 EL_DC_MAGIC_WALL_DEAD,
4329 EL_AMOEBA_TO_DIAMOND,
4337 EL_SP_GRAVITY_PORT_RIGHT,
4338 EL_SP_GRAVITY_PORT_DOWN,
4339 EL_SP_GRAVITY_PORT_LEFT,
4340 EL_SP_GRAVITY_PORT_UP,
4341 EL_SP_PORT_HORIZONTAL,
4342 EL_SP_PORT_VERTICAL,
4353 EL_SP_HARDWARE_GRAY,
4354 EL_SP_HARDWARE_GREEN,
4355 EL_SP_HARDWARE_BLUE,
4357 EL_SP_HARDWARE_YELLOW,
4358 EL_SP_HARDWARE_BASE_1,
4359 EL_SP_HARDWARE_BASE_2,
4360 EL_SP_HARDWARE_BASE_3,
4361 EL_SP_HARDWARE_BASE_4,
4362 EL_SP_HARDWARE_BASE_5,
4363 EL_SP_HARDWARE_BASE_6,
4364 EL_SP_GRAVITY_ON_PORT_LEFT,
4365 EL_SP_GRAVITY_ON_PORT_RIGHT,
4366 EL_SP_GRAVITY_ON_PORT_UP,
4367 EL_SP_GRAVITY_ON_PORT_DOWN,
4368 EL_SP_GRAVITY_OFF_PORT_LEFT,
4369 EL_SP_GRAVITY_OFF_PORT_RIGHT,
4370 EL_SP_GRAVITY_OFF_PORT_UP,
4371 EL_SP_GRAVITY_OFF_PORT_DOWN,
4372 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4373 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4374 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4375 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4376 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4377 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4378 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4379 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4380 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4381 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4382 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4383 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4384 EL_SIGN_EXCLAMATION,
4385 EL_SIGN_RADIOACTIVITY,
4392 EL_SIGN_ENTRY_FORBIDDEN,
4393 EL_SIGN_EMERGENCY_EXIT,
4401 EL_DC_STEELWALL_1_LEFT,
4402 EL_DC_STEELWALL_1_RIGHT,
4403 EL_DC_STEELWALL_1_TOP,
4404 EL_DC_STEELWALL_1_BOTTOM,
4405 EL_DC_STEELWALL_1_HORIZONTAL,
4406 EL_DC_STEELWALL_1_VERTICAL,
4407 EL_DC_STEELWALL_1_TOPLEFT,
4408 EL_DC_STEELWALL_1_TOPRIGHT,
4409 EL_DC_STEELWALL_1_BOTTOMLEFT,
4410 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4411 EL_DC_STEELWALL_1_TOPLEFT_2,
4412 EL_DC_STEELWALL_1_TOPRIGHT_2,
4413 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4414 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4415 EL_DC_STEELWALL_2_LEFT,
4416 EL_DC_STEELWALL_2_RIGHT,
4417 EL_DC_STEELWALL_2_TOP,
4418 EL_DC_STEELWALL_2_BOTTOM,
4419 EL_DC_STEELWALL_2_HORIZONTAL,
4420 EL_DC_STEELWALL_2_VERTICAL,
4421 EL_DC_STEELWALL_2_MIDDLE,
4422 EL_DC_STEELWALL_2_SINGLE,
4423 EL_STEELWALL_SLIPPERY,
4428 EL_EMC_WALL_SLIPPERY_1,
4429 EL_EMC_WALL_SLIPPERY_2,
4430 EL_EMC_WALL_SLIPPERY_3,
4431 EL_EMC_WALL_SLIPPERY_4,
4452 static int ep_em_slippery_wall[] =
4457 static int ep_gfx_crumbled[] =
4468 static int ep_editor_cascade_active[] =
4470 EL_INTERNAL_CASCADE_BD_ACTIVE,
4471 EL_INTERNAL_CASCADE_EM_ACTIVE,
4472 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4473 EL_INTERNAL_CASCADE_RND_ACTIVE,
4474 EL_INTERNAL_CASCADE_SB_ACTIVE,
4475 EL_INTERNAL_CASCADE_SP_ACTIVE,
4476 EL_INTERNAL_CASCADE_DC_ACTIVE,
4477 EL_INTERNAL_CASCADE_DX_ACTIVE,
4478 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4479 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4480 EL_INTERNAL_CASCADE_CE_ACTIVE,
4481 EL_INTERNAL_CASCADE_GE_ACTIVE,
4482 EL_INTERNAL_CASCADE_REF_ACTIVE,
4483 EL_INTERNAL_CASCADE_USER_ACTIVE,
4484 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4489 static int ep_editor_cascade_inactive[] =
4491 EL_INTERNAL_CASCADE_BD,
4492 EL_INTERNAL_CASCADE_EM,
4493 EL_INTERNAL_CASCADE_EMC,
4494 EL_INTERNAL_CASCADE_RND,
4495 EL_INTERNAL_CASCADE_SB,
4496 EL_INTERNAL_CASCADE_SP,
4497 EL_INTERNAL_CASCADE_DC,
4498 EL_INTERNAL_CASCADE_DX,
4499 EL_INTERNAL_CASCADE_CHARS,
4500 EL_INTERNAL_CASCADE_STEEL_CHARS,
4501 EL_INTERNAL_CASCADE_CE,
4502 EL_INTERNAL_CASCADE_GE,
4503 EL_INTERNAL_CASCADE_REF,
4504 EL_INTERNAL_CASCADE_USER,
4505 EL_INTERNAL_CASCADE_DYNAMIC,
4510 static int ep_obsolete[] =
4514 EL_EM_KEY_1_FILE_OBSOLETE,
4515 EL_EM_KEY_2_FILE_OBSOLETE,
4516 EL_EM_KEY_3_FILE_OBSOLETE,
4517 EL_EM_KEY_4_FILE_OBSOLETE,
4518 EL_ENVELOPE_OBSOLETE,
4527 } element_properties[] =
4529 { ep_diggable, EP_DIGGABLE },
4530 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4531 { ep_dont_run_into, EP_DONT_RUN_INTO },
4532 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4533 { ep_dont_touch, EP_DONT_TOUCH },
4534 { ep_indestructible, EP_INDESTRUCTIBLE },
4535 { ep_slippery, EP_SLIPPERY },
4536 { ep_can_change, EP_CAN_CHANGE },
4537 { ep_can_move, EP_CAN_MOVE },
4538 { ep_can_fall, EP_CAN_FALL },
4539 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4540 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4541 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4542 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4543 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4544 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4545 { ep_walkable_over, EP_WALKABLE_OVER },
4546 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4547 { ep_walkable_under, EP_WALKABLE_UNDER },
4548 { ep_passable_over, EP_PASSABLE_OVER },
4549 { ep_passable_inside, EP_PASSABLE_INSIDE },
4550 { ep_passable_under, EP_PASSABLE_UNDER },
4551 { ep_droppable, EP_DROPPABLE },
4552 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4553 { ep_pushable, EP_PUSHABLE },
4554 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4555 { ep_protected, EP_PROTECTED },
4556 { ep_throwable, EP_THROWABLE },
4557 { ep_can_explode, EP_CAN_EXPLODE },
4558 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4560 { ep_player, EP_PLAYER },
4561 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4562 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4563 { ep_switchable, EP_SWITCHABLE },
4564 { ep_bd_element, EP_BD_ELEMENT },
4565 { ep_sp_element, EP_SP_ELEMENT },
4566 { ep_sb_element, EP_SB_ELEMENT },
4568 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4569 { ep_food_penguin, EP_FOOD_PENGUIN },
4570 { ep_food_pig, EP_FOOD_PIG },
4571 { ep_historic_wall, EP_HISTORIC_WALL },
4572 { ep_historic_solid, EP_HISTORIC_SOLID },
4573 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4574 { ep_belt, EP_BELT },
4575 { ep_belt_active, EP_BELT_ACTIVE },
4576 { ep_belt_switch, EP_BELT_SWITCH },
4577 { ep_tube, EP_TUBE },
4578 { ep_acid_pool, EP_ACID_POOL },
4579 { ep_keygate, EP_KEYGATE },
4580 { ep_amoeboid, EP_AMOEBOID },
4581 { ep_amoebalive, EP_AMOEBALIVE },
4582 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4583 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4584 { ep_can_grow, EP_CAN_GROW },
4585 { ep_active_bomb, EP_ACTIVE_BOMB },
4586 { ep_inactive, EP_INACTIVE },
4588 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4590 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4592 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4593 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4595 { ep_obsolete, EP_OBSOLETE },
4602 /* always start with reliable default values (element has no properties) */
4603 /* (but never initialize clipboard elements after the very first time) */
4604 /* (to be able to use clipboard elements between several levels) */
4605 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4606 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4607 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4608 SET_PROPERTY(i, j, FALSE);
4610 /* set all base element properties from above array definitions */
4611 for (i = 0; element_properties[i].elements != NULL; i++)
4612 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4613 SET_PROPERTY((element_properties[i].elements)[j],
4614 element_properties[i].property, TRUE);
4616 /* copy properties to some elements that are only stored in level file */
4617 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4618 for (j = 0; copy_properties[j][0] != -1; j++)
4619 if (HAS_PROPERTY(copy_properties[j][0], i))
4620 for (k = 1; k <= 4; k++)
4621 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4623 /* set static element properties that are not listed in array definitions */
4624 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4625 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4627 clipboard_elements_initialized = TRUE;
4630 void InitElementPropertiesEngine(int engine_version)
4632 static int no_wall_properties[] =
4635 EP_COLLECTIBLE_ONLY,
4637 EP_DONT_COLLIDE_WITH,
4640 EP_CAN_SMASH_PLAYER,
4641 EP_CAN_SMASH_ENEMIES,
4642 EP_CAN_SMASH_EVERYTHING,
4647 EP_FOOD_DARK_YAMYAM,
4663 /* important: after initialization in InitElementPropertiesStatic(), the
4664 elements are not again initialized to a default value; therefore all
4665 changes have to make sure that they leave the element with a defined
4666 property (which means that conditional property changes must be set to
4667 a reliable default value before) */
4669 /* resolve group elements */
4670 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4671 ResolveGroupElement(EL_GROUP_START + i);
4673 /* set all special, combined or engine dependent element properties */
4674 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4676 /* do not change (already initialized) clipboard elements here */
4677 if (IS_CLIPBOARD_ELEMENT(i))
4680 /* ---------- INACTIVE ------------------------------------------------- */
4681 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4682 i <= EL_CHAR_END) ||
4683 (i >= EL_STEEL_CHAR_START &&
4684 i <= EL_STEEL_CHAR_END)));
4686 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4687 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4688 IS_WALKABLE_INSIDE(i) ||
4689 IS_WALKABLE_UNDER(i)));
4691 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4692 IS_PASSABLE_INSIDE(i) ||
4693 IS_PASSABLE_UNDER(i)));
4695 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4696 IS_PASSABLE_OVER(i)));
4698 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4699 IS_PASSABLE_INSIDE(i)));
4701 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4702 IS_PASSABLE_UNDER(i)));
4704 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4707 /* ---------- COLLECTIBLE ---------------------------------------------- */
4708 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4712 /* ---------- SNAPPABLE ------------------------------------------------ */
4713 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4714 IS_COLLECTIBLE(i) ||
4718 /* ---------- WALL ----------------------------------------------------- */
4719 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4721 for (j = 0; no_wall_properties[j] != -1; j++)
4722 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4723 i >= EL_FIRST_RUNTIME_UNREAL)
4724 SET_PROPERTY(i, EP_WALL, FALSE);
4726 if (IS_HISTORIC_WALL(i))
4727 SET_PROPERTY(i, EP_WALL, TRUE);
4729 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4730 if (engine_version < VERSION_IDENT(2,2,0,0))
4731 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4733 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4735 !IS_COLLECTIBLE(i)));
4737 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4738 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4739 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4741 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4742 IS_INDESTRUCTIBLE(i)));
4744 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4746 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4747 else if (engine_version < VERSION_IDENT(2,2,0,0))
4748 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4750 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4754 if (IS_CUSTOM_ELEMENT(i))
4756 /* these are additional properties which are initially false when set */
4758 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4760 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4761 if (DONT_COLLIDE_WITH(i))
4762 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4764 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4765 if (CAN_SMASH_EVERYTHING(i))
4766 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4767 if (CAN_SMASH_ENEMIES(i))
4768 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4771 /* ---------- CAN_SMASH ------------------------------------------------ */
4772 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4773 CAN_SMASH_ENEMIES(i) ||
4774 CAN_SMASH_EVERYTHING(i)));
4776 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4777 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4778 EXPLODES_BY_FIRE(i)));
4780 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4781 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4782 EXPLODES_SMASHED(i)));
4784 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4785 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4786 EXPLODES_IMPACT(i)));
4788 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4789 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4791 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4792 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4793 i == EL_BLACK_ORB));
4795 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4796 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4798 IS_CUSTOM_ELEMENT(i)));
4800 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4801 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4802 i == EL_SP_ELECTRON));
4804 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4805 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4806 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4807 getMoveIntoAcidProperty(&level, i));
4809 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4810 if (MAYBE_DONT_COLLIDE_WITH(i))
4811 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4812 getDontCollideWithProperty(&level, i));
4814 /* ---------- SP_PORT -------------------------------------------------- */
4815 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4816 IS_PASSABLE_INSIDE(i)));
4818 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4819 for (j = 0; j < level.num_android_clone_elements; j++)
4820 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4822 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4824 /* ---------- CAN_CHANGE ----------------------------------------------- */
4825 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4826 for (j = 0; j < element_info[i].num_change_pages; j++)
4827 if (element_info[i].change_page[j].can_change)
4828 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4830 /* ---------- HAS_ACTION ----------------------------------------------- */
4831 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4832 for (j = 0; j < element_info[i].num_change_pages; j++)
4833 if (element_info[i].change_page[j].has_action)
4834 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4836 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4837 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4840 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4842 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4843 element_info[i].crumbled[ACTION_DEFAULT] !=
4844 element_info[i].graphic[ACTION_DEFAULT]);
4846 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
4847 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4848 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
4851 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4852 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4853 IS_EDITOR_CASCADE_INACTIVE(i)));
4856 /* dynamically adjust element properties according to game engine version */
4858 static int ep_em_slippery_wall[] =
4863 EL_EXPANDABLE_WALL_HORIZONTAL,
4864 EL_EXPANDABLE_WALL_VERTICAL,
4865 EL_EXPANDABLE_WALL_ANY,
4866 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4867 EL_EXPANDABLE_STEELWALL_VERTICAL,
4868 EL_EXPANDABLE_STEELWALL_ANY,
4869 EL_EXPANDABLE_STEELWALL_GROWING,
4873 static int ep_em_explodes_by_fire[] =
4876 EL_EM_DYNAMITE_ACTIVE,
4881 /* special EM style gems behaviour */
4882 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4883 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4884 level.em_slippery_gems);
4886 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4887 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4888 (level.em_slippery_gems &&
4889 engine_version > VERSION_IDENT(2,0,1,0)));
4891 /* special EM style explosion behaviour regarding chain reactions */
4892 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4893 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4894 level.em_explodes_by_fire);
4897 /* this is needed because some graphics depend on element properties */
4898 if (game_status == GAME_MODE_PLAYING)
4899 InitElementGraphicInfo();
4902 void InitElementPropertiesAfterLoading(int engine_version)
4906 /* set some other uninitialized values of custom elements in older levels */
4907 if (engine_version < VERSION_IDENT(3,1,0,0))
4909 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4911 int element = EL_CUSTOM_START + i;
4913 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4915 element_info[element].explosion_delay = 17;
4916 element_info[element].ignition_delay = 8;
4921 void InitElementPropertiesGfxElement()
4925 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4927 struct ElementInfo *ei = &element_info[i];
4929 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4933 static void InitGlobal()
4938 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4940 /* check if element_name_info entry defined for each element in "main.h" */
4941 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4942 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4944 element_info[i].token_name = element_name_info[i].token_name;
4945 element_info[i].class_name = element_name_info[i].class_name;
4946 element_info[i].editor_description= element_name_info[i].editor_description;
4949 printf("%04d: %s\n", i, element_name_info[i].token_name);
4953 /* create hash from image config list */
4954 image_config_hash = newSetupFileHash();
4955 for (i = 0; image_config[i].token != NULL; i++)
4956 setHashEntry(image_config_hash,
4957 image_config[i].token,
4958 image_config[i].value);
4960 /* create hash from element token list */
4961 element_token_hash = newSetupFileHash();
4962 for (i = 0; element_name_info[i].token_name != NULL; i++)
4963 setHashEntry(element_token_hash,
4964 element_name_info[i].token_name,
4967 /* create hash from graphic token list */
4968 graphic_token_hash = newSetupFileHash();
4969 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4970 if (strSuffix(image_config[i].value, ".png") ||
4971 strSuffix(image_config[i].value, ".pcx") ||
4972 strSuffix(image_config[i].value, ".wav") ||
4973 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4974 setHashEntry(graphic_token_hash,
4975 image_config[i].token,
4976 int2str(graphic++, 0));
4978 /* create hash from font token list */
4979 font_token_hash = newSetupFileHash();
4980 for (i = 0; font_info[i].token_name != NULL; i++)
4981 setHashEntry(font_token_hash,
4982 font_info[i].token_name,
4985 /* always start with reliable default values (all elements) */
4986 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4987 ActiveElement[i] = i;
4989 /* now add all entries that have an active state (active elements) */
4990 for (i = 0; element_with_active_state[i].element != -1; i++)
4992 int element = element_with_active_state[i].element;
4993 int element_active = element_with_active_state[i].element_active;
4995 ActiveElement[element] = element_active;
4998 /* always start with reliable default values (all buttons) */
4999 for (i = 0; i < NUM_IMAGE_FILES; i++)
5000 ActiveButton[i] = i;
5002 /* now add all entries that have an active state (active buttons) */
5003 for (i = 0; button_with_active_state[i].button != -1; i++)
5005 int button = button_with_active_state[i].button;
5006 int button_active = button_with_active_state[i].button_active;
5008 ActiveButton[button] = button_active;
5011 /* always start with reliable default values (all fonts) */
5012 for (i = 0; i < NUM_FONTS; i++)
5015 /* now add all entries that have an active state (active fonts) */
5016 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
5018 int font = font_with_active_state[i].font_nr;
5019 int font_active = font_with_active_state[i].font_nr_active;
5021 ActiveFont[font] = font_active;
5024 global.autoplay_leveldir = NULL;
5025 global.convert_leveldir = NULL;
5026 global.create_images_dir = NULL;
5028 global.frames_per_second = 0;
5029 global.fps_slowdown = FALSE;
5030 global.fps_slowdown_factor = 1;
5032 global.border_status = GAME_MODE_MAIN;
5034 global.fading_status = GAME_MODE_MAIN;
5035 global.fading_type = TYPE_ENTER_MENU;
5038 global.use_envelope_request = FALSE;
5041 void Execute_Command(char *command)
5045 if (strEqual(command, "print graphicsinfo.conf"))
5047 printf("# You can configure additional/alternative image files here.\n");
5048 printf("# (The entries below are default and therefore commented out.)\n");
5050 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
5052 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5055 for (i = 0; image_config[i].token != NULL; i++)
5056 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
5057 image_config[i].value));
5061 else if (strEqual(command, "print soundsinfo.conf"))
5063 printf("# You can configure additional/alternative sound files here.\n");
5064 printf("# (The entries below are default and therefore commented out.)\n");
5066 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
5068 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5071 for (i = 0; sound_config[i].token != NULL; i++)
5072 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
5073 sound_config[i].value));
5077 else if (strEqual(command, "print musicinfo.conf"))
5079 printf("# You can configure additional/alternative music files here.\n");
5080 printf("# (The entries below are default and therefore commented out.)\n");
5082 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
5084 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5087 for (i = 0; music_config[i].token != NULL; i++)
5088 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
5089 music_config[i].value));
5093 else if (strEqual(command, "print editorsetup.conf"))
5095 printf("# You can configure your personal editor element list here.\n");
5096 printf("# (The entries below are default and therefore commented out.)\n");
5099 /* this is needed to be able to check element list for cascade elements */
5100 InitElementPropertiesStatic();
5101 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5103 PrintEditorElementList();
5107 else if (strEqual(command, "print helpanim.conf"))
5109 printf("# You can configure different element help animations here.\n");
5110 printf("# (The entries below are default and therefore commented out.)\n");
5113 for (i = 0; helpanim_config[i].token != NULL; i++)
5115 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
5116 helpanim_config[i].value));
5118 if (strEqual(helpanim_config[i].token, "end"))
5124 else if (strEqual(command, "print helptext.conf"))
5126 printf("# You can configure different element help text here.\n");
5127 printf("# (The entries below are default and therefore commented out.)\n");
5130 for (i = 0; helptext_config[i].token != NULL; i++)
5131 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
5132 helptext_config[i].value));
5136 else if (strPrefix(command, "dump level "))
5138 char *filename = &command[11];
5140 if (!fileExists(filename))
5141 Error(ERR_EXIT, "cannot open file '%s'", filename);
5143 LoadLevelFromFilename(&level, filename);
5148 else if (strPrefix(command, "dump tape "))
5150 char *filename = &command[10];
5152 if (!fileExists(filename))
5153 Error(ERR_EXIT, "cannot open file '%s'", filename);
5155 LoadTapeFromFilename(filename);
5160 else if (strPrefix(command, "autoplay "))
5162 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
5164 while (*str_ptr != '\0') /* continue parsing string */
5166 /* cut leading whitespace from string, replace it by string terminator */
5167 while (*str_ptr == ' ' || *str_ptr == '\t')
5170 if (*str_ptr == '\0') /* end of string reached */
5173 if (global.autoplay_leveldir == NULL) /* read level set string */
5175 global.autoplay_leveldir = str_ptr;
5176 global.autoplay_all = TRUE; /* default: play all tapes */
5178 for (i = 0; i < MAX_TAPES_PER_SET; i++)
5179 global.autoplay_level[i] = FALSE;
5181 else /* read level number string */
5183 int level_nr = atoi(str_ptr); /* get level_nr value */
5185 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5186 global.autoplay_level[level_nr] = TRUE;
5188 global.autoplay_all = FALSE;
5191 /* advance string pointer to the next whitespace (or end of string) */
5192 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5196 else if (strPrefix(command, "convert "))
5198 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
5199 char *str_ptr = strchr(str_copy, ' ');
5201 global.convert_leveldir = str_copy;
5202 global.convert_level_nr = -1;
5204 if (str_ptr != NULL) /* level number follows */
5206 *str_ptr++ = '\0'; /* terminate leveldir string */
5207 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
5210 else if (strPrefix(command, "create images "))
5212 global.create_images_dir = getStringCopy(&command[14]);
5214 if (access(global.create_images_dir, W_OK) != 0)
5215 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
5216 global.create_images_dir);
5220 #if defined(TARGET_SDL2)
5221 else if (strEqual(command, "SDL_ListModes"))
5223 SDL_Init(SDL_INIT_VIDEO);
5225 int num_displays = SDL_GetNumVideoDisplays();
5227 // check if there are any displays available
5228 if (num_displays < 0)
5230 printf("No displays available: %s\n", SDL_GetError());
5235 for (i = 0; i < num_displays; i++)
5237 int num_modes = SDL_GetNumDisplayModes(i);
5240 printf("Available display modes for display %d:\n", i);
5242 // check if there are any display modes available for this display
5245 printf("No display modes available for display %d: %s\n",
5251 for (j = 0; j < num_modes; j++)
5253 SDL_DisplayMode mode;
5255 if (SDL_GetDisplayMode(i, j, &mode) < 0)
5257 printf("Cannot get display mode %d for display %d: %s\n",
5258 j, i, SDL_GetError());
5263 printf("- %d x %d\n", mode.w, mode.h);
5269 #elif defined(TARGET_SDL)
5270 else if (strEqual(command, "SDL_ListModes"))
5275 SDL_Init(SDL_INIT_VIDEO);
5277 /* get available fullscreen/hardware modes */
5278 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
5280 /* check if there are any modes available */
5283 printf("No modes available!\n");
5288 /* check if our resolution is restricted */
5289 if (modes == (SDL_Rect **)-1)
5291 printf("All resolutions available.\n");
5295 printf("Available display modes:\n");
5297 for (i = 0; modes[i]; i++)
5298 printf("- %d x %d\n", modes[i]->w, modes[i]->h);
5308 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
5312 static void InitSetup()
5314 LoadSetup(); /* global setup info */
5316 /* set some options from setup file */
5318 if (setup.options.verbose)
5319 options.verbose = TRUE;
5322 static void InitGameInfo()
5324 game.restart_level = FALSE;
5327 static void InitPlayerInfo()
5331 /* choose default local player */
5332 local_player = &stored_player[0];
5334 for (i = 0; i < MAX_PLAYERS; i++)
5335 stored_player[i].connected = FALSE;
5337 local_player->connected = TRUE;
5340 static void InitArtworkInfo()
5345 static char *get_string_in_brackets(char *string)
5347 char *string_in_brackets = checked_malloc(strlen(string) + 3);
5349 sprintf(string_in_brackets, "[%s]", string);
5351 return string_in_brackets;
5354 static char *get_level_id_suffix(int id_nr)
5356 char *id_suffix = checked_malloc(1 + 3 + 1);
5358 if (id_nr < 0 || id_nr > 999)
5361 sprintf(id_suffix, ".%03d", id_nr);
5367 static char *get_element_class_token(int element)
5369 char *element_class_name = element_info[element].class_name;
5370 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
5372 sprintf(element_class_token, "[%s]", element_class_name);
5374 return element_class_token;
5377 static char *get_action_class_token(int action)
5379 char *action_class_name = &element_action_info[action].suffix[1];
5380 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
5382 sprintf(action_class_token, "[%s]", action_class_name);
5384 return action_class_token;
5388 static void InitArtworkConfig()
5390 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
5391 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
5392 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
5393 static char *action_id_suffix[NUM_ACTIONS + 1];
5394 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5395 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5396 static char *level_id_suffix[MAX_LEVELS + 1];
5397 static char *dummy[1] = { NULL };
5398 static char *ignore_generic_tokens[] =
5404 static char **ignore_image_tokens;
5405 static char **ignore_sound_tokens;
5406 static char **ignore_music_tokens;
5407 int num_ignore_generic_tokens;
5408 int num_ignore_image_tokens;
5409 int num_ignore_sound_tokens;
5410 int num_ignore_music_tokens;
5413 /* dynamically determine list of generic tokens to be ignored */
5414 num_ignore_generic_tokens = 0;
5415 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5416 num_ignore_generic_tokens++;
5418 /* dynamically determine list of image tokens to be ignored */
5419 num_ignore_image_tokens = num_ignore_generic_tokens;
5420 for (i = 0; image_config_vars[i].token != NULL; i++)
5421 num_ignore_image_tokens++;
5422 ignore_image_tokens =
5423 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5424 for (i = 0; i < num_ignore_generic_tokens; i++)
5425 ignore_image_tokens[i] = ignore_generic_tokens[i];
5426 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5427 ignore_image_tokens[num_ignore_generic_tokens + i] =
5428 image_config_vars[i].token;
5429 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5431 /* dynamically determine list of sound tokens to be ignored */
5432 num_ignore_sound_tokens = num_ignore_generic_tokens;
5433 ignore_sound_tokens =
5434 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5435 for (i = 0; i < num_ignore_generic_tokens; i++)
5436 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5437 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5439 /* dynamically determine list of music tokens to be ignored */
5440 num_ignore_music_tokens = num_ignore_generic_tokens;
5441 ignore_music_tokens =
5442 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5443 for (i = 0; i < num_ignore_generic_tokens; i++)
5444 ignore_music_tokens[i] = ignore_generic_tokens[i];
5445 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5447 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5448 image_id_prefix[i] = element_info[i].token_name;
5449 for (i = 0; i < NUM_FONTS; i++)
5450 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5451 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
5453 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5454 sound_id_prefix[i] = element_info[i].token_name;
5455 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5456 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5457 get_string_in_brackets(element_info[i].class_name);
5458 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
5460 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5461 music_id_prefix[i] = music_prefix_info[i].prefix;
5462 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
5464 for (i = 0; i < NUM_ACTIONS; i++)
5465 action_id_suffix[i] = element_action_info[i].suffix;
5466 action_id_suffix[NUM_ACTIONS] = NULL;
5468 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5469 direction_id_suffix[i] = element_direction_info[i].suffix;
5470 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5472 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5473 special_id_suffix[i] = special_suffix_info[i].suffix;
5474 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5476 for (i = 0; i < MAX_LEVELS; i++)
5477 level_id_suffix[i] = get_level_id_suffix(i);
5478 level_id_suffix[MAX_LEVELS] = NULL;
5480 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5481 image_id_prefix, action_id_suffix, direction_id_suffix,
5482 special_id_suffix, ignore_image_tokens);
5483 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5484 sound_id_prefix, action_id_suffix, dummy,
5485 special_id_suffix, ignore_sound_tokens);
5486 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5487 music_id_prefix, special_id_suffix, level_id_suffix,
5488 dummy, ignore_music_tokens);
5491 static void InitMixer()
5498 void InitGfxBuffers()
5500 /* create additional image buffers for double-buffering and cross-fading */
5501 ReCreateBitmap(&bitmap_db_store, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5502 ReCreateBitmap(&bitmap_db_cross, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5503 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE, DEFAULT_DEPTH);
5504 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE, DEFAULT_DEPTH);
5506 ReCreateBitmap(&bitmap_db_door, 3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
5508 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE, DEFAULT_DEPTH);
5509 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE, DEFAULT_DEPTH);
5510 ReCreateBitmap(&bitmap_db_toons, FULL_SXSIZE, FULL_SYSIZE, DEFAULT_DEPTH);
5512 /* initialize screen properties */
5513 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5514 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5516 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5517 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5518 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5519 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5520 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5521 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5523 InitGfxBuffers_EM();
5524 InitGfxBuffers_SP();
5529 struct GraphicInfo *graphic_info_last = graphic_info;
5530 char *filename_font_initial = NULL;
5531 char *filename_anim_initial = NULL;
5532 Bitmap *bitmap_font_initial = NULL;
5536 /* determine settings for initial font (for displaying startup messages) */
5537 for (i = 0; image_config[i].token != NULL; i++)
5539 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5541 char font_token[128];
5544 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5545 len_font_token = strlen(font_token);
5547 if (strEqual(image_config[i].token, font_token))
5548 filename_font_initial = image_config[i].value;
5549 else if (strlen(image_config[i].token) > len_font_token &&
5550 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5552 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5553 font_initial[j].src_x = atoi(image_config[i].value);
5554 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5555 font_initial[j].src_y = atoi(image_config[i].value);
5556 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5557 font_initial[j].width = atoi(image_config[i].value);
5558 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5559 font_initial[j].height = atoi(image_config[i].value);
5564 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5566 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5567 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5570 if (filename_font_initial == NULL) /* should not happen */
5571 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5574 InitGfxCustomArtworkInfo();
5576 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5578 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5579 font_initial[j].bitmap = bitmap_font_initial;
5581 InitFontGraphicInfo();
5583 font_height = getFontHeight(FC_RED);
5586 DrawInitTextAlways(getWindowTitleString(), 20, FC_YELLOW);
5588 DrawInitTextAlways(getProgramInitString(), 20, FC_YELLOW);
5590 DrawInitTextAlways(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
5591 DrawInitTextAlways(PROGRAM_WEBSITE_STRING, WIN_YSIZE - 20 - font_height,
5594 DrawInitTextAlways("Loading graphics", 120, FC_GREEN);
5598 /* initialize busy animation with default values */
5599 int parameter[NUM_GFX_ARGS];
5600 for (i = 0; i < NUM_GFX_ARGS; i++)
5601 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5602 image_config_suffix[i].token,
5603 image_config_suffix[i].type);
5605 for (i = 0; i < NUM_GFX_ARGS; i++)
5606 printf("::: '%s' => %d\n", image_config_suffix[i].token, parameter[i]);
5610 /* determine settings for busy animation (when displaying startup messages) */
5611 for (i = 0; image_config[i].token != NULL; i++)
5613 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5614 int len_anim_token = strlen(anim_token);
5616 if (strEqual(image_config[i].token, anim_token))
5617 filename_anim_initial = image_config[i].value;
5618 else if (strlen(image_config[i].token) > len_anim_token &&
5619 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5622 for (j = 0; image_config_suffix[j].token != NULL; j++)
5624 if (strEqual(&image_config[i].token[len_anim_token],
5625 image_config_suffix[j].token))
5627 get_graphic_parameter_value(image_config[i].value,
5628 image_config_suffix[j].token,
5629 image_config_suffix[j].type);
5632 if (strEqual(&image_config[i].token[len_anim_token], ".x"))
5633 anim_initial.src_x = atoi(image_config[i].value);
5634 else if (strEqual(&image_config[i].token[len_anim_token], ".y"))
5635 anim_initial.src_y = atoi(image_config[i].value);
5636 else if (strEqual(&image_config[i].token[len_anim_token], ".width"))
5637 anim_initial.width = atoi(image_config[i].value);
5638 else if (strEqual(&image_config[i].token[len_anim_token], ".height"))
5639 anim_initial.height = atoi(image_config[i].value);
5640 else if (strEqual(&image_config[i].token[len_anim_token], ".frames"))
5641 anim_initial.anim_frames = atoi(image_config[i].value);
5642 else if (strEqual(&image_config[i].token[len_anim_token],
5643 ".frames_per_line"))
5644 anim_initial.anim_frames_per_line = atoi(image_config[i].value);
5645 else if (strEqual(&image_config[i].token[len_anim_token], ".delay"))
5646 anim_initial.anim_delay = atoi(image_config[i].value);
5651 #if defined(CREATE_SPECIAL_EDITION_RND_JUE)
5652 filename_anim_initial = "loading.pcx";
5654 parameter[GFX_ARG_X] = 0;
5655 parameter[GFX_ARG_Y] = 0;
5656 parameter[GFX_ARG_WIDTH] = 128;
5657 parameter[GFX_ARG_HEIGHT] = 40;
5658 parameter[GFX_ARG_FRAMES] = 32;
5659 parameter[GFX_ARG_DELAY] = 4;
5660 parameter[GFX_ARG_FRAMES_PER_LINE] = ARG_UNDEFINED_VALUE;
5663 if (filename_anim_initial == NULL) /* should not happen */
5664 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5666 anim_initial.bitmap = LoadCustomImage(filename_anim_initial);
5668 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
5670 set_graphic_parameters_ext(0, parameter, anim_initial.bitmap);
5673 printf("::: INIT_GFX: anim_frames_per_line == %d [%d / %d] [%d, %d]\n",
5674 graphic_info[0].anim_frames_per_line,
5675 get_scaled_graphic_width(0),
5676 graphic_info[0].width,
5677 getOriginalImageWidthFromImageID(0),
5678 graphic_info[0].scale_up_factor);
5681 graphic_info = graphic_info_last;
5683 init.busy.width = anim_initial.width;
5684 init.busy.height = anim_initial.height;
5686 InitMenuDesignSettings_Static();
5687 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5689 /* use copy of busy animation to prevent change while reloading artwork */
5694 void RedrawBackground()
5696 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
5697 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
5699 redraw_mask = REDRAW_ALL;
5702 void InitGfxBackground()
5706 fieldbuffer = bitmap_db_field;
5707 SetDrawtoField(DRAW_BACKBUFFER);
5710 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5714 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
5715 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
5718 for (x = 0; x < MAX_BUF_XSIZE; x++)
5719 for (y = 0; y < MAX_BUF_YSIZE; y++)
5722 redraw_mask = REDRAW_ALL;
5725 static void InitLevelInfo()
5727 LoadLevelInfo(); /* global level info */
5728 LoadLevelSetup_LastSeries(); /* last played series info */
5729 LoadLevelSetup_SeriesInfo(); /* last played level info */
5732 static void InitLevelArtworkInfo()
5734 LoadLevelArtworkInfo();
5737 static void InitImages()
5739 print_timestamp_init("InitImages");
5742 printf("::: leveldir_current->identifier == '%s'\n",
5743 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5744 printf("::: leveldir_current->graphics_path == '%s'\n",
5745 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5746 printf("::: leveldir_current->graphics_set == '%s'\n",
5747 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5748 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5749 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5752 setLevelArtworkDir(artwork.gfx_first);
5755 printf("::: leveldir_current->identifier == '%s'\n",
5756 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5757 printf("::: leveldir_current->graphics_path == '%s'\n",
5758 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5759 printf("::: leveldir_current->graphics_set == '%s'\n",
5760 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5761 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5762 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5766 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5767 leveldir_current->identifier,
5768 artwork.gfx_current_identifier,
5769 artwork.gfx_current->identifier,
5770 leveldir_current->graphics_set,
5771 leveldir_current->graphics_path);
5774 UPDATE_BUSY_STATE();
5776 ReloadCustomImages();
5777 print_timestamp_time("ReloadCustomImages");
5779 UPDATE_BUSY_STATE();
5781 LoadCustomElementDescriptions();
5782 print_timestamp_time("LoadCustomElementDescriptions");
5784 UPDATE_BUSY_STATE();
5786 LoadMenuDesignSettings();
5787 print_timestamp_time("LoadMenuDesignSettings");
5789 UPDATE_BUSY_STATE();
5791 ReinitializeGraphics();
5792 print_timestamp_time("ReinitializeGraphics");
5794 UPDATE_BUSY_STATE();
5796 print_timestamp_done("InitImages");
5799 static void InitSound(char *identifier)
5801 print_timestamp_init("InitSound");
5803 if (identifier == NULL)
5804 identifier = artwork.snd_current->identifier;
5806 /* set artwork path to send it to the sound server process */
5807 setLevelArtworkDir(artwork.snd_first);
5809 InitReloadCustomSounds(identifier);
5810 print_timestamp_time("InitReloadCustomSounds");
5812 ReinitializeSounds();
5813 print_timestamp_time("ReinitializeSounds");
5815 print_timestamp_done("InitSound");
5818 static void InitMusic(char *identifier)
5820 print_timestamp_init("InitMusic");
5822 if (identifier == NULL)
5823 identifier = artwork.mus_current->identifier;
5825 /* set artwork path to send it to the sound server process */
5826 setLevelArtworkDir(artwork.mus_first);
5828 InitReloadCustomMusic(identifier);
5829 print_timestamp_time("InitReloadCustomMusic");
5831 ReinitializeMusic();
5832 print_timestamp_time("ReinitializeMusic");
5834 print_timestamp_done("InitMusic");
5837 void InitNetworkServer()
5839 #if defined(NETWORK_AVALIABLE)
5843 if (!options.network)
5846 #if defined(NETWORK_AVALIABLE)
5847 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5849 if (!ConnectToServer(options.server_host, options.server_port))
5850 Error(ERR_EXIT, "cannot connect to network game server");
5852 SendToServer_PlayerName(setup.player_name);
5853 SendToServer_ProtocolVersion();
5856 SendToServer_NrWanted(nr_wanted);
5860 static boolean CheckArtworkConfigForCustomElements(char *filename)
5862 SetupFileHash *setup_file_hash;
5863 boolean redefined_ce_found = FALSE;
5865 /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */
5867 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5869 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5871 char *token = HASH_ITERATION_TOKEN(itr);
5873 if (strPrefix(token, "custom_"))
5875 redefined_ce_found = TRUE;
5880 END_HASH_ITERATION(setup_file_hash, itr)
5882 freeSetupFileHash(setup_file_hash);
5885 return redefined_ce_found;
5888 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5890 char *filename_base, *filename_local;
5891 boolean redefined_ce_found = FALSE;
5893 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5896 printf("::: leveldir_current->identifier == '%s'\n",
5897 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5898 printf("::: leveldir_current->graphics_path == '%s'\n",
5899 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5900 printf("::: leveldir_current->graphics_set == '%s'\n",
5901 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5902 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5903 leveldir_current == NULL ? "[NULL]" :
5904 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5907 /* first look for special artwork configured in level series config */
5908 filename_base = getCustomArtworkLevelConfigFilename(type);
5911 printf("::: filename_base == '%s'\n", filename_base);
5914 if (fileExists(filename_base))
5915 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5917 filename_local = getCustomArtworkConfigFilename(type);
5920 printf("::: filename_local == '%s'\n", filename_local);
5923 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5924 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5927 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5930 return redefined_ce_found;
5933 static void InitOverrideArtwork()
5935 boolean redefined_ce_found = FALSE;
5937 /* to check if this level set redefines any CEs, do not use overriding */
5938 gfx.override_level_graphics = FALSE;
5939 gfx.override_level_sounds = FALSE;
5940 gfx.override_level_music = FALSE;
5942 /* now check if this level set has definitions for custom elements */
5943 if (setup.override_level_graphics == AUTO ||
5944 setup.override_level_sounds == AUTO ||
5945 setup.override_level_music == AUTO)
5946 redefined_ce_found =
5947 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5948 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5949 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5952 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5955 if (redefined_ce_found)
5957 /* this level set has CE definitions: change "AUTO" to "FALSE" */
5958 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5959 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
5960 gfx.override_level_music = (setup.override_level_music == TRUE);
5964 /* this level set has no CE definitions: change "AUTO" to "TRUE" */
5965 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5966 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
5967 gfx.override_level_music = (setup.override_level_music != FALSE);
5971 printf("::: => %d, %d, %d\n",
5972 gfx.override_level_graphics,
5973 gfx.override_level_sounds,
5974 gfx.override_level_music);
5978 static char *getNewArtworkIdentifier(int type)
5980 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5981 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5982 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5983 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5984 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5986 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5988 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
5990 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5991 char *leveldir_identifier = leveldir_current->identifier;
5993 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
5994 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5996 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
5998 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5999 char *artwork_current_identifier;
6000 char *artwork_new_identifier = NULL; /* default: nothing has changed */
6002 /* leveldir_current may be invalid (level group, parent link) */
6003 if (!validLevelSeries(leveldir_current))
6006 /* 1st step: determine artwork set to be activated in descending order:
6007 --------------------------------------------------------------------
6008 1. setup artwork (when configured to override everything else)
6009 2. artwork set configured in "levelinfo.conf" of current level set
6010 (artwork in level directory will have priority when loading later)
6011 3. artwork in level directory (stored in artwork sub-directory)
6012 4. setup artwork (currently configured in setup menu) */
6014 if (setup_override_artwork)
6015 artwork_current_identifier = setup_artwork_set;
6016 else if (leveldir_artwork_set != NULL)
6017 artwork_current_identifier = leveldir_artwork_set;
6018 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
6019 artwork_current_identifier = leveldir_identifier;
6021 artwork_current_identifier = setup_artwork_set;
6024 /* 2nd step: check if it is really needed to reload artwork set
6025 ------------------------------------------------------------ */
6028 if (type == ARTWORK_TYPE_GRAPHICS)
6029 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
6030 artwork_new_identifier,
6031 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
6032 artwork_current_identifier,
6033 leveldir_current->graphics_set,
6034 leveldir_current->identifier);
6037 /* ---------- reload if level set and also artwork set has changed ------- */
6038 if (leveldir_current_identifier[type] != leveldir_identifier &&
6039 (last_has_level_artwork_set[type] || has_level_artwork_set))
6040 artwork_new_identifier = artwork_current_identifier;
6042 leveldir_current_identifier[type] = leveldir_identifier;
6043 last_has_level_artwork_set[type] = has_level_artwork_set;
6046 if (type == ARTWORK_TYPE_GRAPHICS)
6047 printf("::: 1: '%s'\n", artwork_new_identifier);
6050 /* ---------- reload if "override artwork" setting has changed ----------- */
6051 if (last_override_level_artwork[type] != setup_override_artwork)
6052 artwork_new_identifier = artwork_current_identifier;
6054 last_override_level_artwork[type] = setup_override_artwork;
6057 if (type == ARTWORK_TYPE_GRAPHICS)
6058 printf("::: 2: '%s'\n", artwork_new_identifier);
6061 /* ---------- reload if current artwork identifier has changed ----------- */
6062 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
6063 artwork_current_identifier))
6064 artwork_new_identifier = artwork_current_identifier;
6066 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
6069 if (type == ARTWORK_TYPE_GRAPHICS)
6070 printf("::: 3: '%s'\n", artwork_new_identifier);
6073 /* ---------- do not reload directly after starting ---------------------- */
6074 if (!initialized[type])
6075 artwork_new_identifier = NULL;
6077 initialized[type] = TRUE;
6080 if (type == ARTWORK_TYPE_GRAPHICS)
6081 printf("::: 4: '%s'\n", artwork_new_identifier);
6085 if (type == ARTWORK_TYPE_GRAPHICS)
6086 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
6087 artwork.gfx_current_identifier, artwork_current_identifier,
6088 artwork.gfx_current->identifier, leveldir_current->graphics_set,
6089 artwork_new_identifier);
6092 return artwork_new_identifier;
6095 void ReloadCustomArtwork(int force_reload)
6097 int last_game_status = game_status; /* save current game status */
6098 char *gfx_new_identifier;
6099 char *snd_new_identifier;
6100 char *mus_new_identifier;
6101 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
6102 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
6103 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
6104 boolean reload_needed;
6106 InitOverrideArtwork();
6108 force_reload_gfx |= AdjustGraphicsForEMC();
6110 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
6111 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
6112 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
6114 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
6115 snd_new_identifier != NULL || force_reload_snd ||
6116 mus_new_identifier != NULL || force_reload_mus);
6121 print_timestamp_init("ReloadCustomArtwork");
6123 game_status = GAME_MODE_LOADING;
6125 FadeOut(REDRAW_ALL);
6128 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6130 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
6132 print_timestamp_time("ClearRectangle");
6135 printf("::: fading in ... %d\n", fading.fade_mode);
6139 printf("::: done\n");
6142 if (gfx_new_identifier != NULL || force_reload_gfx)
6145 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
6146 artwork.gfx_current_identifier,
6148 artwork.gfx_current->identifier,
6149 leveldir_current->graphics_set);
6153 print_timestamp_time("InitImages");
6156 if (snd_new_identifier != NULL || force_reload_snd)
6158 InitSound(snd_new_identifier);
6159 print_timestamp_time("InitSound");
6162 if (mus_new_identifier != NULL || force_reload_mus)
6164 InitMusic(mus_new_identifier);
6165 print_timestamp_time("InitMusic");
6168 game_status = last_game_status; /* restore current game status */
6170 init_last = init; /* switch to new busy animation */
6173 printf("::: ----------------DELAY 1 ...\n");
6178 printf("::: FadeOut @ ReloadCustomArtwork ...\n");
6180 FadeOut(REDRAW_ALL);
6182 printf("::: FadeOut @ ReloadCustomArtwork done\n");
6187 /* force redraw of (open or closed) door graphics */
6188 SetDoorState(DOOR_OPEN_ALL);
6189 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
6194 FadeSetEnterScreen();
6195 FadeSkipNextFadeOut();
6196 // FadeSetDisabled();
6201 fading = fading_none;
6206 redraw_mask = REDRAW_ALL;
6209 print_timestamp_done("ReloadCustomArtwork");
6211 LimitScreenUpdates(FALSE);
6214 void KeyboardAutoRepeatOffUnlessAutoplay()
6216 if (global.autoplay_leveldir == NULL)
6217 KeyboardAutoRepeatOff();
6220 void DisplayExitMessage(char *format, va_list ap)
6222 // check if draw buffer and fonts for exit message are already available
6223 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
6226 int font_1 = FC_RED;
6227 int font_2 = FC_YELLOW;
6228 int font_3 = FC_BLUE;
6229 int font_width = getFontWidth(font_2);
6230 int font_height = getFontHeight(font_2);
6233 int sxsize = WIN_XSIZE - 2 * sx;
6234 int sysize = WIN_YSIZE - 2 * sy;
6235 int line_length = sxsize / font_width;
6236 int max_lines = sysize / font_height;
6237 int num_lines_printed;
6241 gfx.sxsize = sxsize;
6242 gfx.sysize = sysize;
6246 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6248 DrawTextSCentered(sy, font_1, "Fatal error:");
6249 sy += 3 * font_height;;
6252 DrawTextBufferVA(sx, sy, format, ap, font_2,
6253 line_length, line_length, max_lines,
6254 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6255 sy += (num_lines_printed + 3) * font_height;
6257 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
6258 sy += 3 * font_height;
6261 DrawTextBuffer(sx, sy, program.error_filename, font_2,
6262 line_length, line_length, max_lines,
6263 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6265 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
6267 redraw_mask = REDRAW_ALL;
6271 /* deactivate toons on error message screen */
6272 setup.toons = FALSE;
6274 WaitForEventToContinue();
6278 /* ========================================================================= */
6280 /* ========================================================================= */
6284 print_timestamp_init("OpenAll");
6286 game_status = GAME_MODE_LOADING;
6292 InitGlobal(); /* initialize some global variables */
6294 print_timestamp_time("[init global stuff]");
6296 if (options.execute_command)
6297 Execute_Command(options.execute_command);
6299 if (options.serveronly)
6301 #if defined(PLATFORM_UNIX)
6302 NetworkServer(options.server_port, options.serveronly);
6304 Error(ERR_WARN, "networking only supported in Unix version");
6307 exit(0); /* never reached, server loops forever */
6312 print_timestamp_time("[init setup/config stuff (1)]");
6315 print_timestamp_time("[init setup/config stuff (2)]");
6317 print_timestamp_time("[init setup/config stuff (3)]");
6318 InitArtworkInfo(); /* needed before loading gfx, sound & music */
6319 print_timestamp_time("[init setup/config stuff (4)]");
6320 InitArtworkConfig(); /* needed before forking sound child process */
6321 print_timestamp_time("[init setup/config stuff (5)]");
6323 print_timestamp_time("[init setup/config stuff (6)]");
6329 InitRND(NEW_RANDOMIZE);
6330 InitSimpleRandom(NEW_RANDOMIZE);
6334 print_timestamp_time("[init setup/config stuff]");
6337 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
6339 InitEventFilter(FilterEvents);
6341 print_timestamp_time("[init video stuff]");
6343 InitElementPropertiesStatic();
6344 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
6345 InitElementPropertiesGfxElement();
6347 print_timestamp_time("[init element properties stuff]");
6351 print_timestamp_time("InitGfx");
6354 print_timestamp_time("InitLevelInfo");
6356 InitLevelArtworkInfo();
6357 print_timestamp_time("InitLevelArtworkInfo");
6359 InitOverrideArtwork(); /* needs to know current level directory */
6360 print_timestamp_time("InitOverrideArtwork");
6362 InitImages(); /* needs to know current level directory */
6363 print_timestamp_time("InitImages");
6365 InitSound(NULL); /* needs to know current level directory */
6366 print_timestamp_time("InitSound");
6368 InitMusic(NULL); /* needs to know current level directory */
6369 print_timestamp_time("InitMusic");
6371 InitGfxBackground();
6381 if (global.autoplay_leveldir)
6386 else if (global.convert_leveldir)
6391 else if (global.create_images_dir)
6393 CreateLevelSketchImages();
6397 game_status = GAME_MODE_MAIN;
6400 FadeSetEnterScreen();
6401 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
6402 FadeSkipNextFadeOut();
6403 // FadeSetDisabled();
6405 fading = fading_none;
6408 print_timestamp_time("[post-artwork]");
6410 print_timestamp_done("OpenAll");
6414 InitNetworkServer();
6417 Error(ERR_DEBUG, "::: SDL_GetBasePath() == '%s'",
6419 Error(ERR_DEBUG, "::: SDL_GetPrefPath() == '%s'",
6420 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
6421 #if defined(PLATFORM_ANDROID)
6422 Error(ERR_DEBUG, "::: SDL_AndroidGetInternalStoragePath() == '%s'",
6423 SDL_AndroidGetInternalStoragePath());
6424 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStoragePath() == '%s'",
6425 SDL_AndroidGetExternalStoragePath());
6426 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStorageState() == '%s'",
6427 (SDL_AndroidGetExternalStorageState() ==
6428 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "read" :
6429 SDL_AndroidGetExternalStorageState() ==
6430 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "write" : "not available"));
6435 void CloseAllAndExit(int exit_value)
6440 CloseAudio(); /* called after freeing sounds (needed for SDL) */
6452 #if defined(TARGET_SDL)
6453 #if defined(TARGET_SDL2)
6455 // set a flag to tell the network server thread to quit and wait for it
6456 // using SDL_WaitThread()
6458 if (network_server) /* terminate network server */
6459 SDL_KillThread(server_thread);
6463 CloseVideoDisplay();
6464 ClosePlatformDependentStuff();
6466 if (exit_value != 0)
6468 /* fall back to default level set (current set may have caused an error) */
6469 SaveLevelSetup_LastSeries_Deactivate();
6471 /* tell user where to find error log file which may contain more details */
6472 // (error notification now directly displayed on screen inside R'n'D
6473 // NotifyUserAboutErrorFile(); /* currently only works for Windows */