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 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1757 static boolean clipmasks_initialized = FALSE;
1759 XGCValues clip_gc_values;
1760 unsigned int clip_gc_valuemask;
1761 GC copy_clipmask_gc = None;
1764 /* use image size as default values for width and height for these images */
1765 static int full_size_graphics[] =
1770 IMG_BACKGROUND_ENVELOPE_1,
1771 IMG_BACKGROUND_ENVELOPE_2,
1772 IMG_BACKGROUND_ENVELOPE_3,
1773 IMG_BACKGROUND_ENVELOPE_4,
1776 IMG_BACKGROUND_TITLE_INITIAL,
1777 IMG_BACKGROUND_TITLE,
1778 IMG_BACKGROUND_MAIN,
1779 IMG_BACKGROUND_LEVELS,
1780 IMG_BACKGROUND_LEVELNR,
1781 IMG_BACKGROUND_SCORES,
1782 IMG_BACKGROUND_EDITOR,
1783 IMG_BACKGROUND_INFO,
1784 IMG_BACKGROUND_INFO_ELEMENTS,
1785 IMG_BACKGROUND_INFO_MUSIC,
1786 IMG_BACKGROUND_INFO_CREDITS,
1787 IMG_BACKGROUND_INFO_PROGRAM,
1788 IMG_BACKGROUND_INFO_LEVELSET,
1789 IMG_BACKGROUND_SETUP,
1790 IMG_BACKGROUND_DOOR,
1791 IMG_BACKGROUND_TAPE,
1792 IMG_BACKGROUND_PANEL,
1794 IMG_TITLESCREEN_INITIAL_1,
1795 IMG_TITLESCREEN_INITIAL_2,
1796 IMG_TITLESCREEN_INITIAL_3,
1797 IMG_TITLESCREEN_INITIAL_4,
1798 IMG_TITLESCREEN_INITIAL_5,
1808 checked_free(graphic_info);
1810 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1813 /* initialize "use_image_size" flag with default value */
1814 for (i = 0; i < num_images; i++)
1815 graphic_info[i].use_image_size = FALSE;
1817 /* initialize "use_image_size" flag from static configuration above */
1818 for (i = 0; full_size_graphics[i] != -1; i++)
1819 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1822 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1823 if (clipmasks_initialized)
1825 for (i = 0; i < num_images; i++)
1827 if (graphic_info[i].clip_mask)
1828 XFreePixmap(display, graphic_info[i].clip_mask);
1829 if (graphic_info[i].clip_gc)
1830 XFreeGC(display, graphic_info[i].clip_gc);
1832 graphic_info[i].clip_mask = None;
1833 graphic_info[i].clip_gc = None;
1838 /* first set all graphic paramaters ... */
1839 for (i = 0; i < num_images; i++)
1840 set_graphic_parameters(i);
1842 /* ... then copy these parameters for cloned graphics */
1843 for (i = 0; i < num_images; i++)
1844 if (graphic_info[i].clone_from != -1)
1845 set_cloned_graphic_parameters(i);
1847 for (i = 0; i < num_images; i++)
1852 int first_frame, last_frame;
1853 int src_bitmap_width, src_bitmap_height;
1855 /* now check if no animation frames are outside of the loaded image */
1857 if (graphic_info[i].bitmap == NULL)
1858 continue; /* skip check for optional images that are undefined */
1860 /* get image size (this can differ from the standard element tile size!) */
1861 width = graphic_info[i].width;
1862 height = graphic_info[i].height;
1864 /* get final bitmap size (with scaling, but without small images) */
1865 src_bitmap_width = graphic_info[i].src_image_width;
1866 src_bitmap_height = graphic_info[i].src_image_height;
1868 /* check if first animation frame is inside specified bitmap */
1871 getFixedGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1874 /* this avoids calculating wrong start position for out-of-bounds frame */
1875 src_x = graphic_info[i].src_x;
1876 src_y = graphic_info[i].src_y;
1879 if (src_x < 0 || src_y < 0 ||
1880 src_x + width > src_bitmap_width ||
1881 src_y + height > src_bitmap_height)
1883 Error(ERR_INFO_LINE, "-");
1884 Error(ERR_INFO, "warning: error found in config file:");
1885 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1886 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1887 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1889 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1890 src_x, src_y, src_bitmap_width, src_bitmap_height);
1891 Error(ERR_INFO, "custom graphic rejected for this element/action");
1893 if (i == fallback_graphic)
1894 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1896 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1897 Error(ERR_INFO_LINE, "-");
1899 graphic_info[i] = graphic_info[fallback_graphic];
1902 /* check if last animation frame is inside specified bitmap */
1904 last_frame = graphic_info[i].anim_frames - 1;
1905 getFixedGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1907 if (src_x < 0 || src_y < 0 ||
1908 src_x + width > src_bitmap_width ||
1909 src_y + height > src_bitmap_height)
1911 Error(ERR_INFO_LINE, "-");
1912 Error(ERR_INFO, "warning: error found in config file:");
1913 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1914 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1915 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1917 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1918 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1919 Error(ERR_INFO, "::: %d, %d", width, height);
1920 Error(ERR_INFO, "custom graphic rejected for this element/action");
1922 if (i == fallback_graphic)
1923 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1925 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1926 Error(ERR_INFO_LINE, "-");
1928 graphic_info[i] = graphic_info[fallback_graphic];
1931 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1932 /* currently we only need a tile clip mask from the first frame */
1933 getFixedGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1935 if (copy_clipmask_gc == None)
1937 clip_gc_values.graphics_exposures = False;
1938 clip_gc_valuemask = GCGraphicsExposures;
1939 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
1940 clip_gc_valuemask, &clip_gc_values);
1943 graphic_info[i].clip_mask =
1944 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
1946 src_pixmap = src_bitmap->clip_mask;
1947 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
1948 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
1950 clip_gc_values.graphics_exposures = False;
1951 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
1952 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
1954 graphic_info[i].clip_gc =
1955 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
1959 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1960 if (copy_clipmask_gc)
1961 XFreeGC(display, copy_clipmask_gc);
1963 clipmasks_initialized = TRUE;
1967 static void InitGraphicCompatibilityInfo()
1969 struct FileInfo *fi_global_door =
1970 getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1971 int num_images = getImageListSize();
1974 /* the following compatibility handling is needed for the following case:
1975 versions up to 3.3.0.0 used one large bitmap "global.door" for various
1976 graphics mainly used for door and panel graphics, like editor, tape and
1977 in-game buttons with hard-coded bitmap positions and button sizes; as
1978 these graphics now have individual definitions, redefining "global.door"
1979 to change all these graphics at once like before does not work anymore
1980 (because all those individual definitions still have their default values);
1981 to solve this, remap all those individual definitions that are not
1982 redefined to the new bitmap of "global.door" if it was redefined */
1984 /* special compatibility handling if image "global.door" was redefined */
1985 if (fi_global_door->redefined)
1987 for (i = 0; i < num_images; i++)
1989 struct FileInfo *fi = getImageListEntryFromImageID(i);
1991 /* process only those images that still use the default settings */
1994 /* process all images which default to same image as "global.door" */
1995 if (strEqual(fi->default_filename, fi_global_door->default_filename))
1997 // printf("::: special treatment needed for token '%s'\n", fi->token);
1999 graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2006 for (i = 0; i < num_images; i++)
2008 struct FileInfo *fi = getImageListEntryFromImageID(i);
2010 if (i == IMG_GLOBAL_DOOR)
2012 printf("::: %s, %s, %d\n",
2013 fi->default_filename,
2021 static void InitElementSoundInfo()
2023 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
2024 int num_property_mappings = getSoundListPropertyMappingSize();
2027 /* set values to -1 to identify later as "uninitialized" values */
2028 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2029 for (act = 0; act < NUM_ACTIONS; act++)
2030 element_info[i].sound[act] = -1;
2032 /* initialize element/sound mapping from static configuration */
2033 for (i = 0; element_to_sound[i].element > -1; i++)
2035 int element = element_to_sound[i].element;
2036 int action = element_to_sound[i].action;
2037 int sound = element_to_sound[i].sound;
2038 boolean is_class = element_to_sound[i].is_class;
2041 action = ACTION_DEFAULT;
2044 element_info[element].sound[action] = sound;
2046 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2047 if (strEqual(element_info[j].class_name,
2048 element_info[element].class_name))
2049 element_info[j].sound[action] = sound;
2052 /* initialize element class/sound mapping from dynamic configuration */
2053 for (i = 0; i < num_property_mappings; i++)
2055 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
2056 int action = property_mapping[i].ext1_index;
2057 int sound = property_mapping[i].artwork_index;
2059 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
2063 action = ACTION_DEFAULT;
2065 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2066 if (strEqual(element_info[j].class_name,
2067 element_info[element_class].class_name))
2068 element_info[j].sound[action] = sound;
2071 /* initialize element/sound mapping from dynamic configuration */
2072 for (i = 0; i < num_property_mappings; i++)
2074 int element = property_mapping[i].base_index;
2075 int action = property_mapping[i].ext1_index;
2076 int sound = property_mapping[i].artwork_index;
2078 if (element >= MAX_NUM_ELEMENTS)
2082 action = ACTION_DEFAULT;
2084 element_info[element].sound[action] = sound;
2087 /* now set all '-1' values to element specific default values */
2088 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2090 for (act = 0; act < NUM_ACTIONS; act++)
2092 /* generic default action sound (defined by "[default]" directive) */
2093 int default_action_sound = element_info[EL_DEFAULT].sound[act];
2095 /* look for special default action sound (classic game specific) */
2096 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
2097 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
2098 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
2099 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
2100 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
2101 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
2103 /* !!! there's no such thing as a "default action sound" !!! */
2105 /* look for element specific default sound (independent from action) */
2106 if (element_info[i].sound[ACTION_DEFAULT] != -1)
2107 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
2111 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
2112 /* !!! make this better !!! */
2113 if (i == EL_EMPTY_SPACE)
2114 default_action_sound = element_info[EL_DEFAULT].sound[act];
2117 /* no sound for this specific action -- use default action sound */
2118 if (element_info[i].sound[act] == -1)
2119 element_info[i].sound[act] = default_action_sound;
2123 /* copy sound settings to some elements that are only stored in level file
2124 in native R'n'D levels, but are used by game engine in native EM levels */
2125 for (i = 0; copy_properties[i][0] != -1; i++)
2126 for (j = 1; j <= 4; j++)
2127 for (act = 0; act < NUM_ACTIONS; act++)
2128 element_info[copy_properties[i][j]].sound[act] =
2129 element_info[copy_properties[i][0]].sound[act];
2132 static void InitGameModeSoundInfo()
2136 /* set values to -1 to identify later as "uninitialized" values */
2137 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2140 /* initialize gamemode/sound mapping from static configuration */
2141 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
2143 int gamemode = gamemode_to_sound[i].gamemode;
2144 int sound = gamemode_to_sound[i].sound;
2147 gamemode = GAME_MODE_DEFAULT;
2149 menu.sound[gamemode] = sound;
2152 /* now set all '-1' values to levelset specific default values */
2153 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2154 if (menu.sound[i] == -1)
2155 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
2158 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2159 if (menu.sound[i] != -1)
2160 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
2164 static void set_sound_parameters(int sound, char **parameter_raw)
2166 int parameter[NUM_SND_ARGS];
2169 /* get integer values from string parameters */
2170 for (i = 0; i < NUM_SND_ARGS; i++)
2172 get_parameter_value(parameter_raw[i],
2173 sound_config_suffix[i].token,
2174 sound_config_suffix[i].type);
2176 /* explicit loop mode setting in configuration overrides default value */
2177 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2178 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
2180 /* sound volume to change the original volume when loading the sound file */
2181 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
2183 /* sound priority to give certain sounds a higher or lower priority */
2184 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
2187 static void InitSoundInfo()
2189 int *sound_effect_properties;
2190 int num_sounds = getSoundListSize();
2193 checked_free(sound_info);
2195 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
2196 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
2198 /* initialize sound effect for all elements to "no sound" */
2199 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2200 for (j = 0; j < NUM_ACTIONS; j++)
2201 element_info[i].sound[j] = SND_UNDEFINED;
2203 for (i = 0; i < num_sounds; i++)
2205 struct FileInfo *sound = getSoundListEntry(i);
2206 int len_effect_text = strlen(sound->token);
2208 sound_effect_properties[i] = ACTION_OTHER;
2209 sound_info[i].loop = FALSE; /* default: play sound only once */
2212 printf("::: sound %d: '%s'\n", i, sound->token);
2215 /* determine all loop sounds and identify certain sound classes */
2217 for (j = 0; element_action_info[j].suffix; j++)
2219 int len_action_text = strlen(element_action_info[j].suffix);
2221 if (len_action_text < len_effect_text &&
2222 strEqual(&sound->token[len_effect_text - len_action_text],
2223 element_action_info[j].suffix))
2225 sound_effect_properties[i] = element_action_info[j].value;
2226 sound_info[i].loop = element_action_info[j].is_loop_sound;
2232 /* associate elements and some selected sound actions */
2234 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2236 if (element_info[j].class_name)
2238 int len_class_text = strlen(element_info[j].class_name);
2240 if (len_class_text + 1 < len_effect_text &&
2241 strncmp(sound->token,
2242 element_info[j].class_name, len_class_text) == 0 &&
2243 sound->token[len_class_text] == '.')
2245 int sound_action_value = sound_effect_properties[i];
2247 element_info[j].sound[sound_action_value] = i;
2252 set_sound_parameters(i, sound->parameter);
2255 free(sound_effect_properties);
2258 static void InitGameModeMusicInfo()
2260 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
2261 int num_property_mappings = getMusicListPropertyMappingSize();
2262 int default_levelset_music = -1;
2265 /* set values to -1 to identify later as "uninitialized" values */
2266 for (i = 0; i < MAX_LEVELS; i++)
2267 levelset.music[i] = -1;
2268 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2271 /* initialize gamemode/music mapping from static configuration */
2272 for (i = 0; gamemode_to_music[i].music > -1; i++)
2274 int gamemode = gamemode_to_music[i].gamemode;
2275 int music = gamemode_to_music[i].music;
2278 printf("::: gamemode == %d, music == %d\n", gamemode, music);
2282 gamemode = GAME_MODE_DEFAULT;
2284 menu.music[gamemode] = music;
2287 /* initialize gamemode/music mapping from dynamic configuration */
2288 for (i = 0; i < num_property_mappings; i++)
2290 int prefix = property_mapping[i].base_index;
2291 int gamemode = property_mapping[i].ext1_index;
2292 int level = property_mapping[i].ext2_index;
2293 int music = property_mapping[i].artwork_index;
2296 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
2297 prefix, gamemode, level, music);
2300 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
2304 gamemode = GAME_MODE_DEFAULT;
2306 /* level specific music only allowed for in-game music */
2307 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
2308 gamemode = GAME_MODE_PLAYING;
2313 default_levelset_music = music;
2316 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
2317 levelset.music[level] = music;
2318 if (gamemode != GAME_MODE_PLAYING)
2319 menu.music[gamemode] = music;
2322 /* now set all '-1' values to menu specific default values */
2323 /* (undefined values of "levelset.music[]" might stay at "-1" to
2324 allow dynamic selection of music files from music directory!) */
2325 for (i = 0; i < MAX_LEVELS; i++)
2326 if (levelset.music[i] == -1)
2327 levelset.music[i] = default_levelset_music;
2328 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2329 if (menu.music[i] == -1)
2330 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
2333 for (i = 0; i < MAX_LEVELS; i++)
2334 if (levelset.music[i] != -1)
2335 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
2336 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2337 if (menu.music[i] != -1)
2338 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
2342 static void set_music_parameters(int music, char **parameter_raw)
2344 int parameter[NUM_MUS_ARGS];
2347 /* get integer values from string parameters */
2348 for (i = 0; i < NUM_MUS_ARGS; i++)
2350 get_parameter_value(parameter_raw[i],
2351 music_config_suffix[i].token,
2352 music_config_suffix[i].type);
2354 /* explicit loop mode setting in configuration overrides default value */
2355 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2356 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
2359 static void InitMusicInfo()
2361 int num_music = getMusicListSize();
2364 checked_free(music_info);
2366 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
2368 for (i = 0; i < num_music; i++)
2370 struct FileInfo *music = getMusicListEntry(i);
2371 int len_music_text = strlen(music->token);
2373 music_info[i].loop = TRUE; /* default: play music in loop mode */
2375 /* determine all loop music */
2377 for (j = 0; music_prefix_info[j].prefix; j++)
2379 int len_prefix_text = strlen(music_prefix_info[j].prefix);
2381 if (len_prefix_text < len_music_text &&
2382 strncmp(music->token,
2383 music_prefix_info[j].prefix, len_prefix_text) == 0)
2385 music_info[i].loop = music_prefix_info[j].is_loop_music;
2391 set_music_parameters(i, music->parameter);
2395 static void ReinitializeGraphics()
2397 print_timestamp_init("ReinitializeGraphics");
2399 InitGraphicInfo(); /* graphic properties mapping */
2400 print_timestamp_time("InitGraphicInfo");
2401 InitElementGraphicInfo(); /* element game graphic mapping */
2402 print_timestamp_time("InitElementGraphicInfo");
2403 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
2404 print_timestamp_time("InitElementSpecialGraphicInfo");
2406 InitElementSmallImages(); /* scale elements to all needed sizes */
2407 print_timestamp_time("InitElementSmallImages");
2408 InitScaledImages(); /* scale all other images, if needed */
2409 print_timestamp_time("InitScaledImages");
2410 InitFontGraphicInfo(); /* initialize text drawing functions */
2411 print_timestamp_time("InitFontGraphicInfo");
2413 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
2414 print_timestamp_time("InitGraphicInfo_EM");
2416 InitGraphicCompatibilityInfo();
2417 print_timestamp_time("InitGraphicCompatibilityInfo");
2419 SetMainBackgroundImage(IMG_BACKGROUND);
2420 print_timestamp_time("SetMainBackgroundImage");
2421 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2422 print_timestamp_time("SetDoorBackgroundImage");
2425 print_timestamp_time("InitGadgets");
2427 print_timestamp_time("InitToons");
2429 print_timestamp_done("ReinitializeGraphics");
2432 static void ReinitializeSounds()
2434 InitSoundInfo(); /* sound properties mapping */
2435 InitElementSoundInfo(); /* element game sound mapping */
2436 InitGameModeSoundInfo(); /* game mode sound mapping */
2438 InitPlayLevelSound(); /* internal game sound settings */
2441 static void ReinitializeMusic()
2443 InitMusicInfo(); /* music properties mapping */
2444 InitGameModeMusicInfo(); /* game mode music mapping */
2447 static int get_special_property_bit(int element, int property_bit_nr)
2449 struct PropertyBitInfo
2455 static struct PropertyBitInfo pb_can_move_into_acid[] =
2457 /* the player may be able fall into acid when gravity is activated */
2462 { EL_SP_MURPHY, 0 },
2463 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2465 /* all elements that can move may be able to also move into acid */
2468 { EL_BUG_RIGHT, 1 },
2471 { EL_SPACESHIP, 2 },
2472 { EL_SPACESHIP_LEFT, 2 },
2473 { EL_SPACESHIP_RIGHT, 2 },
2474 { EL_SPACESHIP_UP, 2 },
2475 { EL_SPACESHIP_DOWN, 2 },
2476 { EL_BD_BUTTERFLY, 3 },
2477 { EL_BD_BUTTERFLY_LEFT, 3 },
2478 { EL_BD_BUTTERFLY_RIGHT, 3 },
2479 { EL_BD_BUTTERFLY_UP, 3 },
2480 { EL_BD_BUTTERFLY_DOWN, 3 },
2481 { EL_BD_FIREFLY, 4 },
2482 { EL_BD_FIREFLY_LEFT, 4 },
2483 { EL_BD_FIREFLY_RIGHT, 4 },
2484 { EL_BD_FIREFLY_UP, 4 },
2485 { EL_BD_FIREFLY_DOWN, 4 },
2487 { EL_YAMYAM_LEFT, 5 },
2488 { EL_YAMYAM_RIGHT, 5 },
2489 { EL_YAMYAM_UP, 5 },
2490 { EL_YAMYAM_DOWN, 5 },
2491 { EL_DARK_YAMYAM, 6 },
2494 { EL_PACMAN_LEFT, 8 },
2495 { EL_PACMAN_RIGHT, 8 },
2496 { EL_PACMAN_UP, 8 },
2497 { EL_PACMAN_DOWN, 8 },
2499 { EL_MOLE_LEFT, 9 },
2500 { EL_MOLE_RIGHT, 9 },
2502 { EL_MOLE_DOWN, 9 },
2506 { EL_SATELLITE, 13 },
2507 { EL_SP_SNIKSNAK, 14 },
2508 { EL_SP_ELECTRON, 15 },
2511 { EL_EMC_ANDROID, 18 },
2516 static struct PropertyBitInfo pb_dont_collide_with[] =
2518 { EL_SP_SNIKSNAK, 0 },
2519 { EL_SP_ELECTRON, 1 },
2527 struct PropertyBitInfo *pb_info;
2530 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2531 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2536 struct PropertyBitInfo *pb_info = NULL;
2539 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2540 if (pb_definition[i].bit_nr == property_bit_nr)
2541 pb_info = pb_definition[i].pb_info;
2543 if (pb_info == NULL)
2546 for (i = 0; pb_info[i].element != -1; i++)
2547 if (pb_info[i].element == element)
2548 return pb_info[i].bit_nr;
2553 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2554 boolean property_value)
2556 int bit_nr = get_special_property_bit(element, property_bit_nr);
2561 *bitfield |= (1 << bit_nr);
2563 *bitfield &= ~(1 << bit_nr);
2567 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2569 int bit_nr = get_special_property_bit(element, property_bit_nr);
2572 return ((*bitfield & (1 << bit_nr)) != 0);
2577 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2579 static int group_nr;
2580 static struct ElementGroupInfo *group;
2581 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2584 if (actual_group == NULL) /* not yet initialized */
2587 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
2589 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2590 group_element - EL_GROUP_START + 1);
2592 /* replace element which caused too deep recursion by question mark */
2593 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2598 if (recursion_depth == 0) /* initialization */
2600 group = actual_group;
2601 group_nr = GROUP_NR(group_element);
2603 group->num_elements_resolved = 0;
2604 group->choice_pos = 0;
2606 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2607 element_info[i].in_group[group_nr] = FALSE;
2610 for (i = 0; i < actual_group->num_elements; i++)
2612 int element = actual_group->element[i];
2614 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2617 if (IS_GROUP_ELEMENT(element))
2618 ResolveGroupElementExt(element, recursion_depth + 1);
2621 group->element_resolved[group->num_elements_resolved++] = element;
2622 element_info[element].in_group[group_nr] = TRUE;
2627 void ResolveGroupElement(int group_element)
2629 ResolveGroupElementExt(group_element, 0);
2632 void InitElementPropertiesStatic()
2634 static boolean clipboard_elements_initialized = FALSE;
2636 static int ep_diggable[] =
2641 EL_SP_BUGGY_BASE_ACTIVATING,
2644 EL_INVISIBLE_SAND_ACTIVE,
2647 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2648 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2653 EL_SP_BUGGY_BASE_ACTIVE,
2660 static int ep_collectible_only[] =
2682 EL_DYNABOMB_INCREASE_NUMBER,
2683 EL_DYNABOMB_INCREASE_SIZE,
2684 EL_DYNABOMB_INCREASE_POWER,
2702 /* !!! handle separately !!! */
2703 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2709 static int ep_dont_run_into[] =
2711 /* same elements as in 'ep_dont_touch' */
2717 /* same elements as in 'ep_dont_collide_with' */
2729 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2734 EL_SP_BUGGY_BASE_ACTIVE,
2741 static int ep_dont_collide_with[] =
2743 /* same elements as in 'ep_dont_touch' */
2760 static int ep_dont_touch[] =
2770 static int ep_indestructible[] =
2774 EL_ACID_POOL_TOPLEFT,
2775 EL_ACID_POOL_TOPRIGHT,
2776 EL_ACID_POOL_BOTTOMLEFT,
2777 EL_ACID_POOL_BOTTOM,
2778 EL_ACID_POOL_BOTTOMRIGHT,
2779 EL_SP_HARDWARE_GRAY,
2780 EL_SP_HARDWARE_GREEN,
2781 EL_SP_HARDWARE_BLUE,
2783 EL_SP_HARDWARE_YELLOW,
2784 EL_SP_HARDWARE_BASE_1,
2785 EL_SP_HARDWARE_BASE_2,
2786 EL_SP_HARDWARE_BASE_3,
2787 EL_SP_HARDWARE_BASE_4,
2788 EL_SP_HARDWARE_BASE_5,
2789 EL_SP_HARDWARE_BASE_6,
2790 EL_INVISIBLE_STEELWALL,
2791 EL_INVISIBLE_STEELWALL_ACTIVE,
2792 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2793 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2794 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2795 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2796 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2797 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2798 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2799 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2800 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2801 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2802 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2803 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2805 EL_LIGHT_SWITCH_ACTIVE,
2806 EL_SIGN_EXCLAMATION,
2807 EL_SIGN_RADIOACTIVITY,
2814 EL_SIGN_ENTRY_FORBIDDEN,
2815 EL_SIGN_EMERGENCY_EXIT,
2823 EL_STEEL_EXIT_CLOSED,
2825 EL_STEEL_EXIT_OPENING,
2826 EL_STEEL_EXIT_CLOSING,
2827 EL_EM_STEEL_EXIT_CLOSED,
2828 EL_EM_STEEL_EXIT_OPEN,
2829 EL_EM_STEEL_EXIT_OPENING,
2830 EL_EM_STEEL_EXIT_CLOSING,
2831 EL_DC_STEELWALL_1_LEFT,
2832 EL_DC_STEELWALL_1_RIGHT,
2833 EL_DC_STEELWALL_1_TOP,
2834 EL_DC_STEELWALL_1_BOTTOM,
2835 EL_DC_STEELWALL_1_HORIZONTAL,
2836 EL_DC_STEELWALL_1_VERTICAL,
2837 EL_DC_STEELWALL_1_TOPLEFT,
2838 EL_DC_STEELWALL_1_TOPRIGHT,
2839 EL_DC_STEELWALL_1_BOTTOMLEFT,
2840 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2841 EL_DC_STEELWALL_1_TOPLEFT_2,
2842 EL_DC_STEELWALL_1_TOPRIGHT_2,
2843 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2844 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2845 EL_DC_STEELWALL_2_LEFT,
2846 EL_DC_STEELWALL_2_RIGHT,
2847 EL_DC_STEELWALL_2_TOP,
2848 EL_DC_STEELWALL_2_BOTTOM,
2849 EL_DC_STEELWALL_2_HORIZONTAL,
2850 EL_DC_STEELWALL_2_VERTICAL,
2851 EL_DC_STEELWALL_2_MIDDLE,
2852 EL_DC_STEELWALL_2_SINGLE,
2853 EL_STEELWALL_SLIPPERY,
2867 EL_GATE_1_GRAY_ACTIVE,
2868 EL_GATE_2_GRAY_ACTIVE,
2869 EL_GATE_3_GRAY_ACTIVE,
2870 EL_GATE_4_GRAY_ACTIVE,
2879 EL_EM_GATE_1_GRAY_ACTIVE,
2880 EL_EM_GATE_2_GRAY_ACTIVE,
2881 EL_EM_GATE_3_GRAY_ACTIVE,
2882 EL_EM_GATE_4_GRAY_ACTIVE,
2891 EL_EMC_GATE_5_GRAY_ACTIVE,
2892 EL_EMC_GATE_6_GRAY_ACTIVE,
2893 EL_EMC_GATE_7_GRAY_ACTIVE,
2894 EL_EMC_GATE_8_GRAY_ACTIVE,
2896 EL_DC_GATE_WHITE_GRAY,
2897 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2898 EL_DC_GATE_FAKE_GRAY,
2900 EL_SWITCHGATE_OPENING,
2901 EL_SWITCHGATE_CLOSED,
2902 EL_SWITCHGATE_CLOSING,
2904 EL_DC_SWITCHGATE_SWITCH_UP,
2905 EL_DC_SWITCHGATE_SWITCH_DOWN,
2908 EL_TIMEGATE_OPENING,
2910 EL_TIMEGATE_CLOSING,
2912 EL_DC_TIMEGATE_SWITCH,
2913 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2918 EL_TUBE_VERTICAL_LEFT,
2919 EL_TUBE_VERTICAL_RIGHT,
2920 EL_TUBE_HORIZONTAL_UP,
2921 EL_TUBE_HORIZONTAL_DOWN,
2926 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2927 EL_EXPANDABLE_STEELWALL_VERTICAL,
2928 EL_EXPANDABLE_STEELWALL_ANY,
2933 static int ep_slippery[] =
2947 EL_ROBOT_WHEEL_ACTIVE,
2953 EL_ACID_POOL_TOPLEFT,
2954 EL_ACID_POOL_TOPRIGHT,
2964 EL_STEELWALL_SLIPPERY,
2967 EL_EMC_WALL_SLIPPERY_1,
2968 EL_EMC_WALL_SLIPPERY_2,
2969 EL_EMC_WALL_SLIPPERY_3,
2970 EL_EMC_WALL_SLIPPERY_4,
2972 EL_EMC_MAGIC_BALL_ACTIVE,
2977 static int ep_can_change[] =
2982 static int ep_can_move[] =
2984 /* same elements as in 'pb_can_move_into_acid' */
3007 static int ep_can_fall[] =
3021 EL_QUICKSAND_FAST_FULL,
3023 EL_BD_MAGIC_WALL_FULL,
3024 EL_DC_MAGIC_WALL_FULL,
3038 static int ep_can_smash_player[] =
3064 static int ep_can_smash_enemies[] =
3073 static int ep_can_smash_everything[] =
3082 static int ep_explodes_by_fire[] =
3084 /* same elements as in 'ep_explodes_impact' */
3089 /* same elements as in 'ep_explodes_smashed' */
3099 EL_EM_DYNAMITE_ACTIVE,
3100 EL_DYNABOMB_PLAYER_1_ACTIVE,
3101 EL_DYNABOMB_PLAYER_2_ACTIVE,
3102 EL_DYNABOMB_PLAYER_3_ACTIVE,
3103 EL_DYNABOMB_PLAYER_4_ACTIVE,
3104 EL_DYNABOMB_INCREASE_NUMBER,
3105 EL_DYNABOMB_INCREASE_SIZE,
3106 EL_DYNABOMB_INCREASE_POWER,
3107 EL_SP_DISK_RED_ACTIVE,
3121 static int ep_explodes_smashed[] =
3123 /* same elements as in 'ep_explodes_impact' */
3137 static int ep_explodes_impact[] =
3146 static int ep_walkable_over[] =
3150 EL_SOKOBAN_FIELD_EMPTY,
3159 EL_EM_STEEL_EXIT_OPEN,
3161 EL_EM_STEEL_EXIT_OPENING,
3171 EL_GATE_1_GRAY_ACTIVE,
3172 EL_GATE_2_GRAY_ACTIVE,
3173 EL_GATE_3_GRAY_ACTIVE,
3174 EL_GATE_4_GRAY_ACTIVE,
3182 static int ep_walkable_inside[] =
3187 EL_TUBE_VERTICAL_LEFT,
3188 EL_TUBE_VERTICAL_RIGHT,
3189 EL_TUBE_HORIZONTAL_UP,
3190 EL_TUBE_HORIZONTAL_DOWN,
3199 static int ep_walkable_under[] =
3204 static int ep_passable_over[] =
3214 EL_EM_GATE_1_GRAY_ACTIVE,
3215 EL_EM_GATE_2_GRAY_ACTIVE,
3216 EL_EM_GATE_3_GRAY_ACTIVE,
3217 EL_EM_GATE_4_GRAY_ACTIVE,
3226 EL_EMC_GATE_5_GRAY_ACTIVE,
3227 EL_EMC_GATE_6_GRAY_ACTIVE,
3228 EL_EMC_GATE_7_GRAY_ACTIVE,
3229 EL_EMC_GATE_8_GRAY_ACTIVE,
3231 EL_DC_GATE_WHITE_GRAY,
3232 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3239 static int ep_passable_inside[] =
3245 EL_SP_PORT_HORIZONTAL,
3246 EL_SP_PORT_VERTICAL,
3248 EL_SP_GRAVITY_PORT_LEFT,
3249 EL_SP_GRAVITY_PORT_RIGHT,
3250 EL_SP_GRAVITY_PORT_UP,
3251 EL_SP_GRAVITY_PORT_DOWN,
3252 EL_SP_GRAVITY_ON_PORT_LEFT,
3253 EL_SP_GRAVITY_ON_PORT_RIGHT,
3254 EL_SP_GRAVITY_ON_PORT_UP,
3255 EL_SP_GRAVITY_ON_PORT_DOWN,
3256 EL_SP_GRAVITY_OFF_PORT_LEFT,
3257 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3258 EL_SP_GRAVITY_OFF_PORT_UP,
3259 EL_SP_GRAVITY_OFF_PORT_DOWN,
3264 static int ep_passable_under[] =
3269 static int ep_droppable[] =
3274 static int ep_explodes_1x1_old[] =
3279 static int ep_pushable[] =
3291 EL_SOKOBAN_FIELD_FULL,
3300 static int ep_explodes_cross_old[] =
3305 static int ep_protected[] =
3307 /* same elements as in 'ep_walkable_inside' */
3311 EL_TUBE_VERTICAL_LEFT,
3312 EL_TUBE_VERTICAL_RIGHT,
3313 EL_TUBE_HORIZONTAL_UP,
3314 EL_TUBE_HORIZONTAL_DOWN,
3320 /* same elements as in 'ep_passable_over' */
3329 EL_EM_GATE_1_GRAY_ACTIVE,
3330 EL_EM_GATE_2_GRAY_ACTIVE,
3331 EL_EM_GATE_3_GRAY_ACTIVE,
3332 EL_EM_GATE_4_GRAY_ACTIVE,
3341 EL_EMC_GATE_5_GRAY_ACTIVE,
3342 EL_EMC_GATE_6_GRAY_ACTIVE,
3343 EL_EMC_GATE_7_GRAY_ACTIVE,
3344 EL_EMC_GATE_8_GRAY_ACTIVE,
3346 EL_DC_GATE_WHITE_GRAY,
3347 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3351 /* same elements as in 'ep_passable_inside' */
3356 EL_SP_PORT_HORIZONTAL,
3357 EL_SP_PORT_VERTICAL,
3359 EL_SP_GRAVITY_PORT_LEFT,
3360 EL_SP_GRAVITY_PORT_RIGHT,
3361 EL_SP_GRAVITY_PORT_UP,
3362 EL_SP_GRAVITY_PORT_DOWN,
3363 EL_SP_GRAVITY_ON_PORT_LEFT,
3364 EL_SP_GRAVITY_ON_PORT_RIGHT,
3365 EL_SP_GRAVITY_ON_PORT_UP,
3366 EL_SP_GRAVITY_ON_PORT_DOWN,
3367 EL_SP_GRAVITY_OFF_PORT_LEFT,
3368 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3369 EL_SP_GRAVITY_OFF_PORT_UP,
3370 EL_SP_GRAVITY_OFF_PORT_DOWN,
3375 static int ep_throwable[] =
3380 static int ep_can_explode[] =
3382 /* same elements as in 'ep_explodes_impact' */
3387 /* same elements as in 'ep_explodes_smashed' */
3393 /* elements that can explode by explosion or by dragonfire */
3397 EL_EM_DYNAMITE_ACTIVE,
3398 EL_DYNABOMB_PLAYER_1_ACTIVE,
3399 EL_DYNABOMB_PLAYER_2_ACTIVE,
3400 EL_DYNABOMB_PLAYER_3_ACTIVE,
3401 EL_DYNABOMB_PLAYER_4_ACTIVE,
3402 EL_DYNABOMB_INCREASE_NUMBER,
3403 EL_DYNABOMB_INCREASE_SIZE,
3404 EL_DYNABOMB_INCREASE_POWER,
3405 EL_SP_DISK_RED_ACTIVE,
3413 /* elements that can explode only by explosion */
3419 static int ep_gravity_reachable[] =
3425 EL_INVISIBLE_SAND_ACTIVE,
3430 EL_SP_PORT_HORIZONTAL,
3431 EL_SP_PORT_VERTICAL,
3433 EL_SP_GRAVITY_PORT_LEFT,
3434 EL_SP_GRAVITY_PORT_RIGHT,
3435 EL_SP_GRAVITY_PORT_UP,
3436 EL_SP_GRAVITY_PORT_DOWN,
3437 EL_SP_GRAVITY_ON_PORT_LEFT,
3438 EL_SP_GRAVITY_ON_PORT_RIGHT,
3439 EL_SP_GRAVITY_ON_PORT_UP,
3440 EL_SP_GRAVITY_ON_PORT_DOWN,
3441 EL_SP_GRAVITY_OFF_PORT_LEFT,
3442 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3443 EL_SP_GRAVITY_OFF_PORT_UP,
3444 EL_SP_GRAVITY_OFF_PORT_DOWN,
3450 static int ep_player[] =
3457 EL_SOKOBAN_FIELD_PLAYER,
3463 static int ep_can_pass_magic_wall[] =
3477 static int ep_can_pass_dc_magic_wall[] =
3493 static int ep_switchable[] =
3497 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3498 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3499 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3500 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3501 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3502 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3503 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3504 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3505 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3506 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3507 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3508 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3509 EL_SWITCHGATE_SWITCH_UP,
3510 EL_SWITCHGATE_SWITCH_DOWN,
3511 EL_DC_SWITCHGATE_SWITCH_UP,
3512 EL_DC_SWITCHGATE_SWITCH_DOWN,
3514 EL_LIGHT_SWITCH_ACTIVE,
3516 EL_DC_TIMEGATE_SWITCH,
3517 EL_BALLOON_SWITCH_LEFT,
3518 EL_BALLOON_SWITCH_RIGHT,
3519 EL_BALLOON_SWITCH_UP,
3520 EL_BALLOON_SWITCH_DOWN,
3521 EL_BALLOON_SWITCH_ANY,
3522 EL_BALLOON_SWITCH_NONE,
3525 EL_EMC_MAGIC_BALL_SWITCH,
3526 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3531 static int ep_bd_element[] =
3565 static int ep_sp_element[] =
3567 /* should always be valid */
3570 /* standard classic Supaplex elements */
3577 EL_SP_HARDWARE_GRAY,
3585 EL_SP_GRAVITY_PORT_RIGHT,
3586 EL_SP_GRAVITY_PORT_DOWN,
3587 EL_SP_GRAVITY_PORT_LEFT,
3588 EL_SP_GRAVITY_PORT_UP,
3593 EL_SP_PORT_VERTICAL,
3594 EL_SP_PORT_HORIZONTAL,
3600 EL_SP_HARDWARE_BASE_1,
3601 EL_SP_HARDWARE_GREEN,
3602 EL_SP_HARDWARE_BLUE,
3604 EL_SP_HARDWARE_YELLOW,
3605 EL_SP_HARDWARE_BASE_2,
3606 EL_SP_HARDWARE_BASE_3,
3607 EL_SP_HARDWARE_BASE_4,
3608 EL_SP_HARDWARE_BASE_5,
3609 EL_SP_HARDWARE_BASE_6,
3613 /* additional elements that appeared in newer Supaplex levels */
3616 /* additional gravity port elements (not switching, but setting gravity) */
3617 EL_SP_GRAVITY_ON_PORT_LEFT,
3618 EL_SP_GRAVITY_ON_PORT_RIGHT,
3619 EL_SP_GRAVITY_ON_PORT_UP,
3620 EL_SP_GRAVITY_ON_PORT_DOWN,
3621 EL_SP_GRAVITY_OFF_PORT_LEFT,
3622 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3623 EL_SP_GRAVITY_OFF_PORT_UP,
3624 EL_SP_GRAVITY_OFF_PORT_DOWN,
3626 /* more than one Murphy in a level results in an inactive clone */
3629 /* runtime Supaplex elements */
3630 EL_SP_DISK_RED_ACTIVE,
3631 EL_SP_TERMINAL_ACTIVE,
3632 EL_SP_BUGGY_BASE_ACTIVATING,
3633 EL_SP_BUGGY_BASE_ACTIVE,
3640 static int ep_sb_element[] =
3645 EL_SOKOBAN_FIELD_EMPTY,
3646 EL_SOKOBAN_FIELD_FULL,
3647 EL_SOKOBAN_FIELD_PLAYER,
3652 EL_INVISIBLE_STEELWALL,
3657 static int ep_gem[] =
3669 static int ep_food_dark_yamyam[] =
3697 static int ep_food_penguin[] =
3711 static int ep_food_pig[] =
3723 static int ep_historic_wall[] =
3734 EL_GATE_1_GRAY_ACTIVE,
3735 EL_GATE_2_GRAY_ACTIVE,
3736 EL_GATE_3_GRAY_ACTIVE,
3737 EL_GATE_4_GRAY_ACTIVE,
3746 EL_EM_GATE_1_GRAY_ACTIVE,
3747 EL_EM_GATE_2_GRAY_ACTIVE,
3748 EL_EM_GATE_3_GRAY_ACTIVE,
3749 EL_EM_GATE_4_GRAY_ACTIVE,
3756 EL_EXPANDABLE_WALL_HORIZONTAL,
3757 EL_EXPANDABLE_WALL_VERTICAL,
3758 EL_EXPANDABLE_WALL_ANY,
3759 EL_EXPANDABLE_WALL_GROWING,
3760 EL_BD_EXPANDABLE_WALL,
3767 EL_SP_HARDWARE_GRAY,
3768 EL_SP_HARDWARE_GREEN,
3769 EL_SP_HARDWARE_BLUE,
3771 EL_SP_HARDWARE_YELLOW,
3772 EL_SP_HARDWARE_BASE_1,
3773 EL_SP_HARDWARE_BASE_2,
3774 EL_SP_HARDWARE_BASE_3,
3775 EL_SP_HARDWARE_BASE_4,
3776 EL_SP_HARDWARE_BASE_5,
3777 EL_SP_HARDWARE_BASE_6,
3779 EL_SP_TERMINAL_ACTIVE,
3782 EL_INVISIBLE_STEELWALL,
3783 EL_INVISIBLE_STEELWALL_ACTIVE,
3785 EL_INVISIBLE_WALL_ACTIVE,
3786 EL_STEELWALL_SLIPPERY,
3803 static int ep_historic_solid[] =
3807 EL_EXPANDABLE_WALL_HORIZONTAL,
3808 EL_EXPANDABLE_WALL_VERTICAL,
3809 EL_EXPANDABLE_WALL_ANY,
3810 EL_BD_EXPANDABLE_WALL,
3823 EL_QUICKSAND_FILLING,
3824 EL_QUICKSAND_EMPTYING,
3826 EL_MAGIC_WALL_ACTIVE,
3827 EL_MAGIC_WALL_EMPTYING,
3828 EL_MAGIC_WALL_FILLING,
3832 EL_BD_MAGIC_WALL_ACTIVE,
3833 EL_BD_MAGIC_WALL_EMPTYING,
3834 EL_BD_MAGIC_WALL_FULL,
3835 EL_BD_MAGIC_WALL_FILLING,
3836 EL_BD_MAGIC_WALL_DEAD,
3845 EL_SP_TERMINAL_ACTIVE,
3849 EL_INVISIBLE_WALL_ACTIVE,
3850 EL_SWITCHGATE_SWITCH_UP,
3851 EL_SWITCHGATE_SWITCH_DOWN,
3852 EL_DC_SWITCHGATE_SWITCH_UP,
3853 EL_DC_SWITCHGATE_SWITCH_DOWN,
3855 EL_TIMEGATE_SWITCH_ACTIVE,
3856 EL_DC_TIMEGATE_SWITCH,
3857 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3869 /* the following elements are a direct copy of "indestructible" elements,
3870 except "EL_ACID", which is "indestructible", but not "solid"! */
3875 EL_ACID_POOL_TOPLEFT,
3876 EL_ACID_POOL_TOPRIGHT,
3877 EL_ACID_POOL_BOTTOMLEFT,
3878 EL_ACID_POOL_BOTTOM,
3879 EL_ACID_POOL_BOTTOMRIGHT,
3880 EL_SP_HARDWARE_GRAY,
3881 EL_SP_HARDWARE_GREEN,
3882 EL_SP_HARDWARE_BLUE,
3884 EL_SP_HARDWARE_YELLOW,
3885 EL_SP_HARDWARE_BASE_1,
3886 EL_SP_HARDWARE_BASE_2,
3887 EL_SP_HARDWARE_BASE_3,
3888 EL_SP_HARDWARE_BASE_4,
3889 EL_SP_HARDWARE_BASE_5,
3890 EL_SP_HARDWARE_BASE_6,
3891 EL_INVISIBLE_STEELWALL,
3892 EL_INVISIBLE_STEELWALL_ACTIVE,
3893 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3894 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3895 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3896 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3897 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3898 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3899 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3900 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3901 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3902 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3903 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3904 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3906 EL_LIGHT_SWITCH_ACTIVE,
3907 EL_SIGN_EXCLAMATION,
3908 EL_SIGN_RADIOACTIVITY,
3915 EL_SIGN_ENTRY_FORBIDDEN,
3916 EL_SIGN_EMERGENCY_EXIT,
3924 EL_STEEL_EXIT_CLOSED,
3926 EL_DC_STEELWALL_1_LEFT,
3927 EL_DC_STEELWALL_1_RIGHT,
3928 EL_DC_STEELWALL_1_TOP,
3929 EL_DC_STEELWALL_1_BOTTOM,
3930 EL_DC_STEELWALL_1_HORIZONTAL,
3931 EL_DC_STEELWALL_1_VERTICAL,
3932 EL_DC_STEELWALL_1_TOPLEFT,
3933 EL_DC_STEELWALL_1_TOPRIGHT,
3934 EL_DC_STEELWALL_1_BOTTOMLEFT,
3935 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3936 EL_DC_STEELWALL_1_TOPLEFT_2,
3937 EL_DC_STEELWALL_1_TOPRIGHT_2,
3938 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3939 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3940 EL_DC_STEELWALL_2_LEFT,
3941 EL_DC_STEELWALL_2_RIGHT,
3942 EL_DC_STEELWALL_2_TOP,
3943 EL_DC_STEELWALL_2_BOTTOM,
3944 EL_DC_STEELWALL_2_HORIZONTAL,
3945 EL_DC_STEELWALL_2_VERTICAL,
3946 EL_DC_STEELWALL_2_MIDDLE,
3947 EL_DC_STEELWALL_2_SINGLE,
3948 EL_STEELWALL_SLIPPERY,
3962 EL_GATE_1_GRAY_ACTIVE,
3963 EL_GATE_2_GRAY_ACTIVE,
3964 EL_GATE_3_GRAY_ACTIVE,
3965 EL_GATE_4_GRAY_ACTIVE,
3974 EL_EM_GATE_1_GRAY_ACTIVE,
3975 EL_EM_GATE_2_GRAY_ACTIVE,
3976 EL_EM_GATE_3_GRAY_ACTIVE,
3977 EL_EM_GATE_4_GRAY_ACTIVE,
3979 EL_SWITCHGATE_OPENING,
3980 EL_SWITCHGATE_CLOSED,
3981 EL_SWITCHGATE_CLOSING,
3983 EL_TIMEGATE_OPENING,
3985 EL_TIMEGATE_CLOSING,
3989 EL_TUBE_VERTICAL_LEFT,
3990 EL_TUBE_VERTICAL_RIGHT,
3991 EL_TUBE_HORIZONTAL_UP,
3992 EL_TUBE_HORIZONTAL_DOWN,
4001 static int ep_classic_enemy[] =
4018 static int ep_belt[] =
4020 EL_CONVEYOR_BELT_1_LEFT,
4021 EL_CONVEYOR_BELT_1_MIDDLE,
4022 EL_CONVEYOR_BELT_1_RIGHT,
4023 EL_CONVEYOR_BELT_2_LEFT,
4024 EL_CONVEYOR_BELT_2_MIDDLE,
4025 EL_CONVEYOR_BELT_2_RIGHT,
4026 EL_CONVEYOR_BELT_3_LEFT,
4027 EL_CONVEYOR_BELT_3_MIDDLE,
4028 EL_CONVEYOR_BELT_3_RIGHT,
4029 EL_CONVEYOR_BELT_4_LEFT,
4030 EL_CONVEYOR_BELT_4_MIDDLE,
4031 EL_CONVEYOR_BELT_4_RIGHT,
4036 static int ep_belt_active[] =
4038 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
4039 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
4040 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
4041 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
4042 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
4043 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
4044 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
4045 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
4046 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
4047 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
4048 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
4049 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
4054 static int ep_belt_switch[] =
4056 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4057 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4058 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4059 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4060 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4061 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4062 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4063 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4064 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4065 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4066 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4067 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4072 static int ep_tube[] =
4079 EL_TUBE_HORIZONTAL_UP,
4080 EL_TUBE_HORIZONTAL_DOWN,
4082 EL_TUBE_VERTICAL_LEFT,
4083 EL_TUBE_VERTICAL_RIGHT,
4089 static int ep_acid_pool[] =
4091 EL_ACID_POOL_TOPLEFT,
4092 EL_ACID_POOL_TOPRIGHT,
4093 EL_ACID_POOL_BOTTOMLEFT,
4094 EL_ACID_POOL_BOTTOM,
4095 EL_ACID_POOL_BOTTOMRIGHT,
4100 static int ep_keygate[] =
4110 EL_GATE_1_GRAY_ACTIVE,
4111 EL_GATE_2_GRAY_ACTIVE,
4112 EL_GATE_3_GRAY_ACTIVE,
4113 EL_GATE_4_GRAY_ACTIVE,
4122 EL_EM_GATE_1_GRAY_ACTIVE,
4123 EL_EM_GATE_2_GRAY_ACTIVE,
4124 EL_EM_GATE_3_GRAY_ACTIVE,
4125 EL_EM_GATE_4_GRAY_ACTIVE,
4134 EL_EMC_GATE_5_GRAY_ACTIVE,
4135 EL_EMC_GATE_6_GRAY_ACTIVE,
4136 EL_EMC_GATE_7_GRAY_ACTIVE,
4137 EL_EMC_GATE_8_GRAY_ACTIVE,
4139 EL_DC_GATE_WHITE_GRAY,
4140 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4145 static int ep_amoeboid[] =
4157 static int ep_amoebalive[] =
4168 static int ep_has_editor_content[] =
4174 EL_SOKOBAN_FIELD_PLAYER,
4191 static int ep_can_turn_each_move[] =
4193 /* !!! do something with this one !!! */
4197 static int ep_can_grow[] =
4211 static int ep_active_bomb[] =
4214 EL_EM_DYNAMITE_ACTIVE,
4215 EL_DYNABOMB_PLAYER_1_ACTIVE,
4216 EL_DYNABOMB_PLAYER_2_ACTIVE,
4217 EL_DYNABOMB_PLAYER_3_ACTIVE,
4218 EL_DYNABOMB_PLAYER_4_ACTIVE,
4219 EL_SP_DISK_RED_ACTIVE,
4224 static int ep_inactive[] =
4234 EL_QUICKSAND_FAST_EMPTY,
4257 EL_GATE_1_GRAY_ACTIVE,
4258 EL_GATE_2_GRAY_ACTIVE,
4259 EL_GATE_3_GRAY_ACTIVE,
4260 EL_GATE_4_GRAY_ACTIVE,
4269 EL_EM_GATE_1_GRAY_ACTIVE,
4270 EL_EM_GATE_2_GRAY_ACTIVE,
4271 EL_EM_GATE_3_GRAY_ACTIVE,
4272 EL_EM_GATE_4_GRAY_ACTIVE,
4281 EL_EMC_GATE_5_GRAY_ACTIVE,
4282 EL_EMC_GATE_6_GRAY_ACTIVE,
4283 EL_EMC_GATE_7_GRAY_ACTIVE,
4284 EL_EMC_GATE_8_GRAY_ACTIVE,
4286 EL_DC_GATE_WHITE_GRAY,
4287 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4288 EL_DC_GATE_FAKE_GRAY,
4291 EL_INVISIBLE_STEELWALL,
4299 EL_WALL_EMERALD_YELLOW,
4300 EL_DYNABOMB_INCREASE_NUMBER,
4301 EL_DYNABOMB_INCREASE_SIZE,
4302 EL_DYNABOMB_INCREASE_POWER,
4306 EL_SOKOBAN_FIELD_EMPTY,
4307 EL_SOKOBAN_FIELD_FULL,
4308 EL_WALL_EMERALD_RED,
4309 EL_WALL_EMERALD_PURPLE,
4310 EL_ACID_POOL_TOPLEFT,
4311 EL_ACID_POOL_TOPRIGHT,
4312 EL_ACID_POOL_BOTTOMLEFT,
4313 EL_ACID_POOL_BOTTOM,
4314 EL_ACID_POOL_BOTTOMRIGHT,
4318 EL_BD_MAGIC_WALL_DEAD,
4320 EL_DC_MAGIC_WALL_DEAD,
4321 EL_AMOEBA_TO_DIAMOND,
4329 EL_SP_GRAVITY_PORT_RIGHT,
4330 EL_SP_GRAVITY_PORT_DOWN,
4331 EL_SP_GRAVITY_PORT_LEFT,
4332 EL_SP_GRAVITY_PORT_UP,
4333 EL_SP_PORT_HORIZONTAL,
4334 EL_SP_PORT_VERTICAL,
4345 EL_SP_HARDWARE_GRAY,
4346 EL_SP_HARDWARE_GREEN,
4347 EL_SP_HARDWARE_BLUE,
4349 EL_SP_HARDWARE_YELLOW,
4350 EL_SP_HARDWARE_BASE_1,
4351 EL_SP_HARDWARE_BASE_2,
4352 EL_SP_HARDWARE_BASE_3,
4353 EL_SP_HARDWARE_BASE_4,
4354 EL_SP_HARDWARE_BASE_5,
4355 EL_SP_HARDWARE_BASE_6,
4356 EL_SP_GRAVITY_ON_PORT_LEFT,
4357 EL_SP_GRAVITY_ON_PORT_RIGHT,
4358 EL_SP_GRAVITY_ON_PORT_UP,
4359 EL_SP_GRAVITY_ON_PORT_DOWN,
4360 EL_SP_GRAVITY_OFF_PORT_LEFT,
4361 EL_SP_GRAVITY_OFF_PORT_RIGHT,
4362 EL_SP_GRAVITY_OFF_PORT_UP,
4363 EL_SP_GRAVITY_OFF_PORT_DOWN,
4364 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4365 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4366 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4367 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4368 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4369 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4370 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4371 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4372 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4373 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4374 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4375 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4376 EL_SIGN_EXCLAMATION,
4377 EL_SIGN_RADIOACTIVITY,
4384 EL_SIGN_ENTRY_FORBIDDEN,
4385 EL_SIGN_EMERGENCY_EXIT,
4393 EL_DC_STEELWALL_1_LEFT,
4394 EL_DC_STEELWALL_1_RIGHT,
4395 EL_DC_STEELWALL_1_TOP,
4396 EL_DC_STEELWALL_1_BOTTOM,
4397 EL_DC_STEELWALL_1_HORIZONTAL,
4398 EL_DC_STEELWALL_1_VERTICAL,
4399 EL_DC_STEELWALL_1_TOPLEFT,
4400 EL_DC_STEELWALL_1_TOPRIGHT,
4401 EL_DC_STEELWALL_1_BOTTOMLEFT,
4402 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4403 EL_DC_STEELWALL_1_TOPLEFT_2,
4404 EL_DC_STEELWALL_1_TOPRIGHT_2,
4405 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4406 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4407 EL_DC_STEELWALL_2_LEFT,
4408 EL_DC_STEELWALL_2_RIGHT,
4409 EL_DC_STEELWALL_2_TOP,
4410 EL_DC_STEELWALL_2_BOTTOM,
4411 EL_DC_STEELWALL_2_HORIZONTAL,
4412 EL_DC_STEELWALL_2_VERTICAL,
4413 EL_DC_STEELWALL_2_MIDDLE,
4414 EL_DC_STEELWALL_2_SINGLE,
4415 EL_STEELWALL_SLIPPERY,
4420 EL_EMC_WALL_SLIPPERY_1,
4421 EL_EMC_WALL_SLIPPERY_2,
4422 EL_EMC_WALL_SLIPPERY_3,
4423 EL_EMC_WALL_SLIPPERY_4,
4444 static int ep_em_slippery_wall[] =
4449 static int ep_gfx_crumbled[] =
4460 static int ep_editor_cascade_active[] =
4462 EL_INTERNAL_CASCADE_BD_ACTIVE,
4463 EL_INTERNAL_CASCADE_EM_ACTIVE,
4464 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4465 EL_INTERNAL_CASCADE_RND_ACTIVE,
4466 EL_INTERNAL_CASCADE_SB_ACTIVE,
4467 EL_INTERNAL_CASCADE_SP_ACTIVE,
4468 EL_INTERNAL_CASCADE_DC_ACTIVE,
4469 EL_INTERNAL_CASCADE_DX_ACTIVE,
4470 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4471 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4472 EL_INTERNAL_CASCADE_CE_ACTIVE,
4473 EL_INTERNAL_CASCADE_GE_ACTIVE,
4474 EL_INTERNAL_CASCADE_REF_ACTIVE,
4475 EL_INTERNAL_CASCADE_USER_ACTIVE,
4476 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4481 static int ep_editor_cascade_inactive[] =
4483 EL_INTERNAL_CASCADE_BD,
4484 EL_INTERNAL_CASCADE_EM,
4485 EL_INTERNAL_CASCADE_EMC,
4486 EL_INTERNAL_CASCADE_RND,
4487 EL_INTERNAL_CASCADE_SB,
4488 EL_INTERNAL_CASCADE_SP,
4489 EL_INTERNAL_CASCADE_DC,
4490 EL_INTERNAL_CASCADE_DX,
4491 EL_INTERNAL_CASCADE_CHARS,
4492 EL_INTERNAL_CASCADE_STEEL_CHARS,
4493 EL_INTERNAL_CASCADE_CE,
4494 EL_INTERNAL_CASCADE_GE,
4495 EL_INTERNAL_CASCADE_REF,
4496 EL_INTERNAL_CASCADE_USER,
4497 EL_INTERNAL_CASCADE_DYNAMIC,
4502 static int ep_obsolete[] =
4506 EL_EM_KEY_1_FILE_OBSOLETE,
4507 EL_EM_KEY_2_FILE_OBSOLETE,
4508 EL_EM_KEY_3_FILE_OBSOLETE,
4509 EL_EM_KEY_4_FILE_OBSOLETE,
4510 EL_ENVELOPE_OBSOLETE,
4519 } element_properties[] =
4521 { ep_diggable, EP_DIGGABLE },
4522 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4523 { ep_dont_run_into, EP_DONT_RUN_INTO },
4524 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4525 { ep_dont_touch, EP_DONT_TOUCH },
4526 { ep_indestructible, EP_INDESTRUCTIBLE },
4527 { ep_slippery, EP_SLIPPERY },
4528 { ep_can_change, EP_CAN_CHANGE },
4529 { ep_can_move, EP_CAN_MOVE },
4530 { ep_can_fall, EP_CAN_FALL },
4531 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4532 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4533 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4534 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4535 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4536 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4537 { ep_walkable_over, EP_WALKABLE_OVER },
4538 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4539 { ep_walkable_under, EP_WALKABLE_UNDER },
4540 { ep_passable_over, EP_PASSABLE_OVER },
4541 { ep_passable_inside, EP_PASSABLE_INSIDE },
4542 { ep_passable_under, EP_PASSABLE_UNDER },
4543 { ep_droppable, EP_DROPPABLE },
4544 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4545 { ep_pushable, EP_PUSHABLE },
4546 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4547 { ep_protected, EP_PROTECTED },
4548 { ep_throwable, EP_THROWABLE },
4549 { ep_can_explode, EP_CAN_EXPLODE },
4550 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4552 { ep_player, EP_PLAYER },
4553 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4554 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4555 { ep_switchable, EP_SWITCHABLE },
4556 { ep_bd_element, EP_BD_ELEMENT },
4557 { ep_sp_element, EP_SP_ELEMENT },
4558 { ep_sb_element, EP_SB_ELEMENT },
4560 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4561 { ep_food_penguin, EP_FOOD_PENGUIN },
4562 { ep_food_pig, EP_FOOD_PIG },
4563 { ep_historic_wall, EP_HISTORIC_WALL },
4564 { ep_historic_solid, EP_HISTORIC_SOLID },
4565 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4566 { ep_belt, EP_BELT },
4567 { ep_belt_active, EP_BELT_ACTIVE },
4568 { ep_belt_switch, EP_BELT_SWITCH },
4569 { ep_tube, EP_TUBE },
4570 { ep_acid_pool, EP_ACID_POOL },
4571 { ep_keygate, EP_KEYGATE },
4572 { ep_amoeboid, EP_AMOEBOID },
4573 { ep_amoebalive, EP_AMOEBALIVE },
4574 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4575 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4576 { ep_can_grow, EP_CAN_GROW },
4577 { ep_active_bomb, EP_ACTIVE_BOMB },
4578 { ep_inactive, EP_INACTIVE },
4580 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4582 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4584 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4585 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4587 { ep_obsolete, EP_OBSOLETE },
4594 /* always start with reliable default values (element has no properties) */
4595 /* (but never initialize clipboard elements after the very first time) */
4596 /* (to be able to use clipboard elements between several levels) */
4597 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4598 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4599 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4600 SET_PROPERTY(i, j, FALSE);
4602 /* set all base element properties from above array definitions */
4603 for (i = 0; element_properties[i].elements != NULL; i++)
4604 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4605 SET_PROPERTY((element_properties[i].elements)[j],
4606 element_properties[i].property, TRUE);
4608 /* copy properties to some elements that are only stored in level file */
4609 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4610 for (j = 0; copy_properties[j][0] != -1; j++)
4611 if (HAS_PROPERTY(copy_properties[j][0], i))
4612 for (k = 1; k <= 4; k++)
4613 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4615 /* set static element properties that are not listed in array definitions */
4616 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4617 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4619 clipboard_elements_initialized = TRUE;
4622 void InitElementPropertiesEngine(int engine_version)
4624 static int no_wall_properties[] =
4627 EP_COLLECTIBLE_ONLY,
4629 EP_DONT_COLLIDE_WITH,
4632 EP_CAN_SMASH_PLAYER,
4633 EP_CAN_SMASH_ENEMIES,
4634 EP_CAN_SMASH_EVERYTHING,
4639 EP_FOOD_DARK_YAMYAM,
4655 /* important: after initialization in InitElementPropertiesStatic(), the
4656 elements are not again initialized to a default value; therefore all
4657 changes have to make sure that they leave the element with a defined
4658 property (which means that conditional property changes must be set to
4659 a reliable default value before) */
4661 /* resolve group elements */
4662 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4663 ResolveGroupElement(EL_GROUP_START + i);
4665 /* set all special, combined or engine dependent element properties */
4666 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4668 /* do not change (already initialized) clipboard elements here */
4669 if (IS_CLIPBOARD_ELEMENT(i))
4672 /* ---------- INACTIVE ------------------------------------------------- */
4673 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4674 i <= EL_CHAR_END) ||
4675 (i >= EL_STEEL_CHAR_START &&
4676 i <= EL_STEEL_CHAR_END)));
4678 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4679 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4680 IS_WALKABLE_INSIDE(i) ||
4681 IS_WALKABLE_UNDER(i)));
4683 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4684 IS_PASSABLE_INSIDE(i) ||
4685 IS_PASSABLE_UNDER(i)));
4687 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4688 IS_PASSABLE_OVER(i)));
4690 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4691 IS_PASSABLE_INSIDE(i)));
4693 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4694 IS_PASSABLE_UNDER(i)));
4696 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4699 /* ---------- COLLECTIBLE ---------------------------------------------- */
4700 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4704 /* ---------- SNAPPABLE ------------------------------------------------ */
4705 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4706 IS_COLLECTIBLE(i) ||
4710 /* ---------- WALL ----------------------------------------------------- */
4711 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4713 for (j = 0; no_wall_properties[j] != -1; j++)
4714 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4715 i >= EL_FIRST_RUNTIME_UNREAL)
4716 SET_PROPERTY(i, EP_WALL, FALSE);
4718 if (IS_HISTORIC_WALL(i))
4719 SET_PROPERTY(i, EP_WALL, TRUE);
4721 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4722 if (engine_version < VERSION_IDENT(2,2,0,0))
4723 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4725 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4727 !IS_COLLECTIBLE(i)));
4729 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4730 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4731 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4733 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4734 IS_INDESTRUCTIBLE(i)));
4736 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4738 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4739 else if (engine_version < VERSION_IDENT(2,2,0,0))
4740 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4742 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4746 if (IS_CUSTOM_ELEMENT(i))
4748 /* these are additional properties which are initially false when set */
4750 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4752 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4753 if (DONT_COLLIDE_WITH(i))
4754 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4756 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4757 if (CAN_SMASH_EVERYTHING(i))
4758 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4759 if (CAN_SMASH_ENEMIES(i))
4760 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4763 /* ---------- CAN_SMASH ------------------------------------------------ */
4764 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4765 CAN_SMASH_ENEMIES(i) ||
4766 CAN_SMASH_EVERYTHING(i)));
4768 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4769 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4770 EXPLODES_BY_FIRE(i)));
4772 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4773 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4774 EXPLODES_SMASHED(i)));
4776 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4777 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4778 EXPLODES_IMPACT(i)));
4780 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4781 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4783 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4784 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4785 i == EL_BLACK_ORB));
4787 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4788 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4790 IS_CUSTOM_ELEMENT(i)));
4792 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4793 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4794 i == EL_SP_ELECTRON));
4796 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4797 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4798 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4799 getMoveIntoAcidProperty(&level, i));
4801 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4802 if (MAYBE_DONT_COLLIDE_WITH(i))
4803 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4804 getDontCollideWithProperty(&level, i));
4806 /* ---------- SP_PORT -------------------------------------------------- */
4807 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4808 IS_PASSABLE_INSIDE(i)));
4810 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4811 for (j = 0; j < level.num_android_clone_elements; j++)
4812 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4814 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4816 /* ---------- CAN_CHANGE ----------------------------------------------- */
4817 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4818 for (j = 0; j < element_info[i].num_change_pages; j++)
4819 if (element_info[i].change_page[j].can_change)
4820 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4822 /* ---------- HAS_ACTION ----------------------------------------------- */
4823 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4824 for (j = 0; j < element_info[i].num_change_pages; j++)
4825 if (element_info[i].change_page[j].has_action)
4826 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4828 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4829 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4832 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4834 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4835 element_info[i].crumbled[ACTION_DEFAULT] !=
4836 element_info[i].graphic[ACTION_DEFAULT]);
4838 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
4839 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4840 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
4843 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4844 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4845 IS_EDITOR_CASCADE_INACTIVE(i)));
4848 /* dynamically adjust element properties according to game engine version */
4850 static int ep_em_slippery_wall[] =
4855 EL_EXPANDABLE_WALL_HORIZONTAL,
4856 EL_EXPANDABLE_WALL_VERTICAL,
4857 EL_EXPANDABLE_WALL_ANY,
4858 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4859 EL_EXPANDABLE_STEELWALL_VERTICAL,
4860 EL_EXPANDABLE_STEELWALL_ANY,
4861 EL_EXPANDABLE_STEELWALL_GROWING,
4865 static int ep_em_explodes_by_fire[] =
4868 EL_EM_DYNAMITE_ACTIVE,
4873 /* special EM style gems behaviour */
4874 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4875 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4876 level.em_slippery_gems);
4878 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4879 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4880 (level.em_slippery_gems &&
4881 engine_version > VERSION_IDENT(2,0,1,0)));
4883 /* special EM style explosion behaviour regarding chain reactions */
4884 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4885 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4886 level.em_explodes_by_fire);
4889 /* this is needed because some graphics depend on element properties */
4890 if (game_status == GAME_MODE_PLAYING)
4891 InitElementGraphicInfo();
4894 void InitElementPropertiesAfterLoading(int engine_version)
4898 /* set some other uninitialized values of custom elements in older levels */
4899 if (engine_version < VERSION_IDENT(3,1,0,0))
4901 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4903 int element = EL_CUSTOM_START + i;
4905 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4907 element_info[element].explosion_delay = 17;
4908 element_info[element].ignition_delay = 8;
4913 void InitElementPropertiesGfxElement()
4917 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4919 struct ElementInfo *ei = &element_info[i];
4921 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4925 static void InitGlobal()
4930 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4932 /* check if element_name_info entry defined for each element in "main.h" */
4933 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4934 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4936 element_info[i].token_name = element_name_info[i].token_name;
4937 element_info[i].class_name = element_name_info[i].class_name;
4938 element_info[i].editor_description= element_name_info[i].editor_description;
4941 printf("%04d: %s\n", i, element_name_info[i].token_name);
4945 /* create hash from image config list */
4946 image_config_hash = newSetupFileHash();
4947 for (i = 0; image_config[i].token != NULL; i++)
4948 setHashEntry(image_config_hash,
4949 image_config[i].token,
4950 image_config[i].value);
4952 /* create hash from element token list */
4953 element_token_hash = newSetupFileHash();
4954 for (i = 0; element_name_info[i].token_name != NULL; i++)
4955 setHashEntry(element_token_hash,
4956 element_name_info[i].token_name,
4959 /* create hash from graphic token list */
4960 graphic_token_hash = newSetupFileHash();
4961 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4962 if (strSuffix(image_config[i].value, ".png") ||
4963 strSuffix(image_config[i].value, ".pcx") ||
4964 strSuffix(image_config[i].value, ".wav") ||
4965 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4966 setHashEntry(graphic_token_hash,
4967 image_config[i].token,
4968 int2str(graphic++, 0));
4970 /* create hash from font token list */
4971 font_token_hash = newSetupFileHash();
4972 for (i = 0; font_info[i].token_name != NULL; i++)
4973 setHashEntry(font_token_hash,
4974 font_info[i].token_name,
4977 /* always start with reliable default values (all elements) */
4978 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4979 ActiveElement[i] = i;
4981 /* now add all entries that have an active state (active elements) */
4982 for (i = 0; element_with_active_state[i].element != -1; i++)
4984 int element = element_with_active_state[i].element;
4985 int element_active = element_with_active_state[i].element_active;
4987 ActiveElement[element] = element_active;
4990 /* always start with reliable default values (all buttons) */
4991 for (i = 0; i < NUM_IMAGE_FILES; i++)
4992 ActiveButton[i] = i;
4994 /* now add all entries that have an active state (active buttons) */
4995 for (i = 0; button_with_active_state[i].button != -1; i++)
4997 int button = button_with_active_state[i].button;
4998 int button_active = button_with_active_state[i].button_active;
5000 ActiveButton[button] = button_active;
5003 /* always start with reliable default values (all fonts) */
5004 for (i = 0; i < NUM_FONTS; i++)
5007 /* now add all entries that have an active state (active fonts) */
5008 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
5010 int font = font_with_active_state[i].font_nr;
5011 int font_active = font_with_active_state[i].font_nr_active;
5013 ActiveFont[font] = font_active;
5016 global.autoplay_leveldir = NULL;
5017 global.convert_leveldir = NULL;
5018 global.create_images_dir = NULL;
5020 global.frames_per_second = 0;
5021 global.fps_slowdown = FALSE;
5022 global.fps_slowdown_factor = 1;
5024 global.border_status = GAME_MODE_MAIN;
5026 global.fading_status = GAME_MODE_MAIN;
5027 global.fading_type = TYPE_ENTER_MENU;
5030 global.use_envelope_request = FALSE; /* !!! MOVE TO ARTWORK CONFIG !!! */
5033 void Execute_Command(char *command)
5037 if (strEqual(command, "print graphicsinfo.conf"))
5039 printf("# You can configure additional/alternative image files here.\n");
5040 printf("# (The entries below are default and therefore commented out.)\n");
5042 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
5044 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5047 for (i = 0; image_config[i].token != NULL; i++)
5048 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
5049 image_config[i].value));
5053 else if (strEqual(command, "print soundsinfo.conf"))
5055 printf("# You can configure additional/alternative sound files here.\n");
5056 printf("# (The entries below are default and therefore commented out.)\n");
5058 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
5060 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5063 for (i = 0; sound_config[i].token != NULL; i++)
5064 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
5065 sound_config[i].value));
5069 else if (strEqual(command, "print musicinfo.conf"))
5071 printf("# You can configure additional/alternative music files here.\n");
5072 printf("# (The entries below are default and therefore commented out.)\n");
5074 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
5076 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5079 for (i = 0; music_config[i].token != NULL; i++)
5080 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
5081 music_config[i].value));
5085 else if (strEqual(command, "print editorsetup.conf"))
5087 printf("# You can configure your personal editor element list here.\n");
5088 printf("# (The entries below are default and therefore commented out.)\n");
5091 /* this is needed to be able to check element list for cascade elements */
5092 InitElementPropertiesStatic();
5093 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5095 PrintEditorElementList();
5099 else if (strEqual(command, "print helpanim.conf"))
5101 printf("# You can configure different element help animations here.\n");
5102 printf("# (The entries below are default and therefore commented out.)\n");
5105 for (i = 0; helpanim_config[i].token != NULL; i++)
5107 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
5108 helpanim_config[i].value));
5110 if (strEqual(helpanim_config[i].token, "end"))
5116 else if (strEqual(command, "print helptext.conf"))
5118 printf("# You can configure different element help text here.\n");
5119 printf("# (The entries below are default and therefore commented out.)\n");
5122 for (i = 0; helptext_config[i].token != NULL; i++)
5123 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
5124 helptext_config[i].value));
5128 else if (strPrefix(command, "dump level "))
5130 char *filename = &command[11];
5132 if (!fileExists(filename))
5133 Error(ERR_EXIT, "cannot open file '%s'", filename);
5135 LoadLevelFromFilename(&level, filename);
5140 else if (strPrefix(command, "dump tape "))
5142 char *filename = &command[10];
5144 if (!fileExists(filename))
5145 Error(ERR_EXIT, "cannot open file '%s'", filename);
5147 LoadTapeFromFilename(filename);
5152 else if (strPrefix(command, "autoplay "))
5154 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
5156 while (*str_ptr != '\0') /* continue parsing string */
5158 /* cut leading whitespace from string, replace it by string terminator */
5159 while (*str_ptr == ' ' || *str_ptr == '\t')
5162 if (*str_ptr == '\0') /* end of string reached */
5165 if (global.autoplay_leveldir == NULL) /* read level set string */
5167 global.autoplay_leveldir = str_ptr;
5168 global.autoplay_all = TRUE; /* default: play all tapes */
5170 for (i = 0; i < MAX_TAPES_PER_SET; i++)
5171 global.autoplay_level[i] = FALSE;
5173 else /* read level number string */
5175 int level_nr = atoi(str_ptr); /* get level_nr value */
5177 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5178 global.autoplay_level[level_nr] = TRUE;
5180 global.autoplay_all = FALSE;
5183 /* advance string pointer to the next whitespace (or end of string) */
5184 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5188 else if (strPrefix(command, "convert "))
5190 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
5191 char *str_ptr = strchr(str_copy, ' ');
5193 global.convert_leveldir = str_copy;
5194 global.convert_level_nr = -1;
5196 if (str_ptr != NULL) /* level number follows */
5198 *str_ptr++ = '\0'; /* terminate leveldir string */
5199 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
5202 else if (strPrefix(command, "create images "))
5204 #if defined(TARGET_SDL)
5205 global.create_images_dir = getStringCopy(&command[14]);
5207 if (access(global.create_images_dir, W_OK) != 0)
5208 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
5209 global.create_images_dir);
5211 Error(ERR_EXIT, "command only available for SDL target");
5216 #if defined(TARGET_SDL2)
5217 else if (strEqual(command, "SDL_ListModes"))
5219 SDL_Init(SDL_INIT_VIDEO);
5221 int num_displays = SDL_GetNumVideoDisplays();
5223 // check if there are any displays available
5224 if (num_displays < 0)
5226 printf("No displays available: %s\n", SDL_GetError());
5231 for (i = 0; i < num_displays; i++)
5233 int num_modes = SDL_GetNumDisplayModes(i);
5236 printf("Available display modes for display %d:\n", i);
5238 // check if there are any display modes available for this display
5241 printf("No display modes available for display %d: %s\n",
5247 for (j = 0; j < num_modes; j++)
5249 SDL_DisplayMode mode;
5251 if (SDL_GetDisplayMode(i, j, &mode) < 0)
5253 printf("Cannot get display mode %d for display %d: %s\n",
5254 j, i, SDL_GetError());
5259 printf("- %d x %d\n", mode.w, mode.h);
5265 #elif defined(TARGET_SDL)
5266 else if (strEqual(command, "SDL_ListModes"))
5271 SDL_Init(SDL_INIT_VIDEO);
5273 /* get available fullscreen/hardware modes */
5274 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
5276 /* check if there are any modes available */
5279 printf("No modes available!\n");
5284 /* check if our resolution is restricted */
5285 if (modes == (SDL_Rect **)-1)
5287 printf("All resolutions available.\n");
5291 printf("Available display modes:\n");
5293 for (i = 0; modes[i]; i++)
5294 printf("- %d x %d\n", modes[i]->w, modes[i]->h);
5304 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
5308 static void InitSetup()
5310 LoadSetup(); /* global setup info */
5312 /* set some options from setup file */
5314 if (setup.options.verbose)
5315 options.verbose = TRUE;
5318 static void InitGameInfo()
5320 game.restart_level = FALSE;
5323 static void InitPlayerInfo()
5327 /* choose default local player */
5328 local_player = &stored_player[0];
5330 for (i = 0; i < MAX_PLAYERS; i++)
5331 stored_player[i].connected = FALSE;
5333 local_player->connected = TRUE;
5336 static void InitArtworkInfo()
5341 static char *get_string_in_brackets(char *string)
5343 char *string_in_brackets = checked_malloc(strlen(string) + 3);
5345 sprintf(string_in_brackets, "[%s]", string);
5347 return string_in_brackets;
5350 static char *get_level_id_suffix(int id_nr)
5352 char *id_suffix = checked_malloc(1 + 3 + 1);
5354 if (id_nr < 0 || id_nr > 999)
5357 sprintf(id_suffix, ".%03d", id_nr);
5363 static char *get_element_class_token(int element)
5365 char *element_class_name = element_info[element].class_name;
5366 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
5368 sprintf(element_class_token, "[%s]", element_class_name);
5370 return element_class_token;
5373 static char *get_action_class_token(int action)
5375 char *action_class_name = &element_action_info[action].suffix[1];
5376 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
5378 sprintf(action_class_token, "[%s]", action_class_name);
5380 return action_class_token;
5384 static void InitArtworkConfig()
5386 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
5387 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
5388 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
5389 static char *action_id_suffix[NUM_ACTIONS + 1];
5390 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5391 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5392 static char *level_id_suffix[MAX_LEVELS + 1];
5393 static char *dummy[1] = { NULL };
5394 static char *ignore_generic_tokens[] =
5400 static char **ignore_image_tokens;
5401 static char **ignore_sound_tokens;
5402 static char **ignore_music_tokens;
5403 int num_ignore_generic_tokens;
5404 int num_ignore_image_tokens;
5405 int num_ignore_sound_tokens;
5406 int num_ignore_music_tokens;
5409 /* dynamically determine list of generic tokens to be ignored */
5410 num_ignore_generic_tokens = 0;
5411 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5412 num_ignore_generic_tokens++;
5414 /* dynamically determine list of image tokens to be ignored */
5415 num_ignore_image_tokens = num_ignore_generic_tokens;
5416 for (i = 0; image_config_vars[i].token != NULL; i++)
5417 num_ignore_image_tokens++;
5418 ignore_image_tokens =
5419 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5420 for (i = 0; i < num_ignore_generic_tokens; i++)
5421 ignore_image_tokens[i] = ignore_generic_tokens[i];
5422 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5423 ignore_image_tokens[num_ignore_generic_tokens + i] =
5424 image_config_vars[i].token;
5425 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5427 /* dynamically determine list of sound tokens to be ignored */
5428 num_ignore_sound_tokens = num_ignore_generic_tokens;
5429 ignore_sound_tokens =
5430 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5431 for (i = 0; i < num_ignore_generic_tokens; i++)
5432 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5433 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5435 /* dynamically determine list of music tokens to be ignored */
5436 num_ignore_music_tokens = num_ignore_generic_tokens;
5437 ignore_music_tokens =
5438 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5439 for (i = 0; i < num_ignore_generic_tokens; i++)
5440 ignore_music_tokens[i] = ignore_generic_tokens[i];
5441 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5443 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5444 image_id_prefix[i] = element_info[i].token_name;
5445 for (i = 0; i < NUM_FONTS; i++)
5446 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5447 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
5449 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5450 sound_id_prefix[i] = element_info[i].token_name;
5451 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5452 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5453 get_string_in_brackets(element_info[i].class_name);
5454 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
5456 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5457 music_id_prefix[i] = music_prefix_info[i].prefix;
5458 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
5460 for (i = 0; i < NUM_ACTIONS; i++)
5461 action_id_suffix[i] = element_action_info[i].suffix;
5462 action_id_suffix[NUM_ACTIONS] = NULL;
5464 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5465 direction_id_suffix[i] = element_direction_info[i].suffix;
5466 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5468 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5469 special_id_suffix[i] = special_suffix_info[i].suffix;
5470 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5472 for (i = 0; i < MAX_LEVELS; i++)
5473 level_id_suffix[i] = get_level_id_suffix(i);
5474 level_id_suffix[MAX_LEVELS] = NULL;
5476 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5477 image_id_prefix, action_id_suffix, direction_id_suffix,
5478 special_id_suffix, ignore_image_tokens);
5479 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5480 sound_id_prefix, action_id_suffix, dummy,
5481 special_id_suffix, ignore_sound_tokens);
5482 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5483 music_id_prefix, special_id_suffix, level_id_suffix,
5484 dummy, ignore_music_tokens);
5487 static void InitMixer()
5494 void InitGfxBuffers()
5496 ReCreateBitmap(&bitmap_db_store, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5497 ReCreateBitmap(&bitmap_db_cross, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5498 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE, DEFAULT_DEPTH);
5499 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE, DEFAULT_DEPTH);
5500 ReCreateBitmap(&bitmap_db_door, 3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
5501 ReCreateBitmap(&bitmap_db_toons, FULL_SXSIZE, FULL_SYSIZE, DEFAULT_DEPTH);
5503 /* initialize screen properties */
5504 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5505 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5507 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5508 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5509 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5510 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5511 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5513 InitGfxBuffers_EM();
5514 InitGfxBuffers_SP();
5519 struct GraphicInfo *graphic_info_last = graphic_info;
5520 char *filename_font_initial = NULL;
5521 char *filename_anim_initial = NULL;
5522 Bitmap *bitmap_font_initial = NULL;
5526 /* determine settings for initial font (for displaying startup messages) */
5527 for (i = 0; image_config[i].token != NULL; i++)
5529 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5531 char font_token[128];
5534 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5535 len_font_token = strlen(font_token);
5537 if (strEqual(image_config[i].token, font_token))
5538 filename_font_initial = image_config[i].value;
5539 else if (strlen(image_config[i].token) > len_font_token &&
5540 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5542 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5543 font_initial[j].src_x = atoi(image_config[i].value);
5544 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5545 font_initial[j].src_y = atoi(image_config[i].value);
5546 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5547 font_initial[j].width = atoi(image_config[i].value);
5548 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5549 font_initial[j].height = atoi(image_config[i].value);
5554 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5556 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5557 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5560 if (filename_font_initial == NULL) /* should not happen */
5561 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5566 /* create additional image buffers for double-buffering and cross-fading */
5567 bitmap_db_store = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5568 bitmap_db_cross = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5569 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
5570 bitmap_db_panel = CreateBitmap(DXSIZE, DYSIZE, DEFAULT_DEPTH);
5571 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
5572 bitmap_db_toons = CreateBitmap(FULL_SXSIZE, FULL_SYSIZE, DEFAULT_DEPTH);
5574 /* initialize screen properties */
5575 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5576 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5578 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5579 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5580 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5581 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5584 InitGfxCustomArtworkInfo();
5586 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5588 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5589 font_initial[j].bitmap = bitmap_font_initial;
5591 InitFontGraphicInfo();
5593 font_height = getFontHeight(FC_RED);
5596 DrawInitText(getWindowTitleString(), 20, FC_YELLOW);
5598 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
5600 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
5601 DrawInitText(PROGRAM_WEBSITE_STRING, WIN_YSIZE - 20 - font_height, FC_RED);
5603 DrawInitText("Loading graphics", 120, FC_GREEN);
5607 /* initialize busy animation with default values */
5608 int parameter[NUM_GFX_ARGS];
5609 for (i = 0; i < NUM_GFX_ARGS; i++)
5610 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5611 image_config_suffix[i].token,
5612 image_config_suffix[i].type);
5614 for (i = 0; i < NUM_GFX_ARGS; i++)
5615 printf("::: '%s' => %d\n", image_config_suffix[i].token, parameter[i]);
5619 /* determine settings for busy animation (when displaying startup messages) */
5620 for (i = 0; image_config[i].token != NULL; i++)
5622 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5623 int len_anim_token = strlen(anim_token);
5625 if (strEqual(image_config[i].token, anim_token))
5626 filename_anim_initial = image_config[i].value;
5627 else if (strlen(image_config[i].token) > len_anim_token &&
5628 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5631 for (j = 0; image_config_suffix[j].token != NULL; j++)
5633 if (strEqual(&image_config[i].token[len_anim_token],
5634 image_config_suffix[j].token))
5636 get_graphic_parameter_value(image_config[i].value,
5637 image_config_suffix[j].token,
5638 image_config_suffix[j].type);
5641 if (strEqual(&image_config[i].token[len_anim_token], ".x"))
5642 anim_initial.src_x = atoi(image_config[i].value);
5643 else if (strEqual(&image_config[i].token[len_anim_token], ".y"))
5644 anim_initial.src_y = atoi(image_config[i].value);
5645 else if (strEqual(&image_config[i].token[len_anim_token], ".width"))
5646 anim_initial.width = atoi(image_config[i].value);
5647 else if (strEqual(&image_config[i].token[len_anim_token], ".height"))
5648 anim_initial.height = atoi(image_config[i].value);
5649 else if (strEqual(&image_config[i].token[len_anim_token], ".frames"))
5650 anim_initial.anim_frames = atoi(image_config[i].value);
5651 else if (strEqual(&image_config[i].token[len_anim_token],
5652 ".frames_per_line"))
5653 anim_initial.anim_frames_per_line = atoi(image_config[i].value);
5654 else if (strEqual(&image_config[i].token[len_anim_token], ".delay"))
5655 anim_initial.anim_delay = atoi(image_config[i].value);
5660 #if defined(CREATE_SPECIAL_EDITION_RND_JUE)
5661 filename_anim_initial = "loading.pcx";
5663 parameter[GFX_ARG_X] = 0;
5664 parameter[GFX_ARG_Y] = 0;
5665 parameter[GFX_ARG_WIDTH] = 128;
5666 parameter[GFX_ARG_HEIGHT] = 40;
5667 parameter[GFX_ARG_FRAMES] = 32;
5668 parameter[GFX_ARG_DELAY] = 4;
5669 parameter[GFX_ARG_FRAMES_PER_LINE] = ARG_UNDEFINED_VALUE;
5672 if (filename_anim_initial == NULL) /* should not happen */
5673 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5675 anim_initial.bitmap = LoadCustomImage(filename_anim_initial);
5677 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
5679 set_graphic_parameters_ext(0, parameter, anim_initial.bitmap);
5682 printf("::: INIT_GFX: anim_frames_per_line == %d [%d / %d] [%d, %d]\n",
5683 graphic_info[0].anim_frames_per_line,
5684 get_scaled_graphic_width(0),
5685 graphic_info[0].width,
5686 getOriginalImageWidthFromImageID(0),
5687 graphic_info[0].scale_up_factor);
5690 graphic_info = graphic_info_last;
5692 init.busy.width = anim_initial.width;
5693 init.busy.height = anim_initial.height;
5695 InitMenuDesignSettings_Static();
5696 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5698 /* use copy of busy animation to prevent change while reloading artwork */
5703 void RedrawBackground()
5705 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
5706 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
5708 redraw_mask = REDRAW_ALL;
5711 void InitGfxBackground()
5715 fieldbuffer = bitmap_db_field;
5716 SetDrawtoField(DRAW_BACKBUFFER);
5719 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5723 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
5724 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
5727 for (x = 0; x < MAX_BUF_XSIZE; x++)
5728 for (y = 0; y < MAX_BUF_YSIZE; y++)
5731 redraw_mask = REDRAW_ALL;
5734 static void InitLevelInfo()
5736 LoadLevelInfo(); /* global level info */
5737 LoadLevelSetup_LastSeries(); /* last played series info */
5738 LoadLevelSetup_SeriesInfo(); /* last played level info */
5741 static void InitLevelArtworkInfo()
5743 LoadLevelArtworkInfo();
5746 static void InitImages()
5748 print_timestamp_init("InitImages");
5751 printf("::: leveldir_current->identifier == '%s'\n",
5752 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5753 printf("::: leveldir_current->graphics_path == '%s'\n",
5754 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5755 printf("::: leveldir_current->graphics_set == '%s'\n",
5756 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5757 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5758 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5761 setLevelArtworkDir(artwork.gfx_first);
5764 printf("::: leveldir_current->identifier == '%s'\n",
5765 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5766 printf("::: leveldir_current->graphics_path == '%s'\n",
5767 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5768 printf("::: leveldir_current->graphics_set == '%s'\n",
5769 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5770 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5771 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5775 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5776 leveldir_current->identifier,
5777 artwork.gfx_current_identifier,
5778 artwork.gfx_current->identifier,
5779 leveldir_current->graphics_set,
5780 leveldir_current->graphics_path);
5783 UPDATE_BUSY_STATE();
5785 ReloadCustomImages();
5786 print_timestamp_time("ReloadCustomImages");
5788 UPDATE_BUSY_STATE();
5790 LoadCustomElementDescriptions();
5791 print_timestamp_time("LoadCustomElementDescriptions");
5793 UPDATE_BUSY_STATE();
5795 LoadMenuDesignSettings();
5796 print_timestamp_time("LoadMenuDesignSettings");
5798 UPDATE_BUSY_STATE();
5800 ReinitializeGraphics();
5801 print_timestamp_time("ReinitializeGraphics");
5803 UPDATE_BUSY_STATE();
5805 print_timestamp_done("InitImages");
5808 static void InitSound(char *identifier)
5810 print_timestamp_init("InitSound");
5812 if (identifier == NULL)
5813 identifier = artwork.snd_current->identifier;
5815 /* set artwork path to send it to the sound server process */
5816 setLevelArtworkDir(artwork.snd_first);
5818 InitReloadCustomSounds(identifier);
5819 print_timestamp_time("InitReloadCustomSounds");
5821 ReinitializeSounds();
5822 print_timestamp_time("ReinitializeSounds");
5824 print_timestamp_done("InitSound");
5827 static void InitMusic(char *identifier)
5829 print_timestamp_init("InitMusic");
5831 if (identifier == NULL)
5832 identifier = artwork.mus_current->identifier;
5834 /* set artwork path to send it to the sound server process */
5835 setLevelArtworkDir(artwork.mus_first);
5837 InitReloadCustomMusic(identifier);
5838 print_timestamp_time("InitReloadCustomMusic");
5840 ReinitializeMusic();
5841 print_timestamp_time("ReinitializeMusic");
5843 print_timestamp_done("InitMusic");
5846 void InitNetworkServer()
5848 #if defined(NETWORK_AVALIABLE)
5852 if (!options.network)
5855 #if defined(NETWORK_AVALIABLE)
5856 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5858 if (!ConnectToServer(options.server_host, options.server_port))
5859 Error(ERR_EXIT, "cannot connect to network game server");
5861 SendToServer_PlayerName(setup.player_name);
5862 SendToServer_ProtocolVersion();
5865 SendToServer_NrWanted(nr_wanted);
5869 static boolean CheckArtworkConfigForCustomElements(char *filename)
5871 SetupFileHash *setup_file_hash;
5872 boolean redefined_ce_found = FALSE;
5874 /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */
5876 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5878 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5880 char *token = HASH_ITERATION_TOKEN(itr);
5882 if (strPrefix(token, "custom_"))
5884 redefined_ce_found = TRUE;
5889 END_HASH_ITERATION(setup_file_hash, itr)
5891 freeSetupFileHash(setup_file_hash);
5894 return redefined_ce_found;
5897 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5899 char *filename_base, *filename_local;
5900 boolean redefined_ce_found = FALSE;
5902 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5905 printf("::: leveldir_current->identifier == '%s'\n",
5906 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5907 printf("::: leveldir_current->graphics_path == '%s'\n",
5908 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5909 printf("::: leveldir_current->graphics_set == '%s'\n",
5910 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5911 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5912 leveldir_current == NULL ? "[NULL]" :
5913 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5916 /* first look for special artwork configured in level series config */
5917 filename_base = getCustomArtworkLevelConfigFilename(type);
5920 printf("::: filename_base == '%s'\n", filename_base);
5923 if (fileExists(filename_base))
5924 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5926 filename_local = getCustomArtworkConfigFilename(type);
5929 printf("::: filename_local == '%s'\n", filename_local);
5932 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5933 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5936 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5939 return redefined_ce_found;
5942 static void InitOverrideArtwork()
5944 boolean redefined_ce_found = FALSE;
5946 /* to check if this level set redefines any CEs, do not use overriding */
5947 gfx.override_level_graphics = FALSE;
5948 gfx.override_level_sounds = FALSE;
5949 gfx.override_level_music = FALSE;
5951 /* now check if this level set has definitions for custom elements */
5952 if (setup.override_level_graphics == AUTO ||
5953 setup.override_level_sounds == AUTO ||
5954 setup.override_level_music == AUTO)
5955 redefined_ce_found =
5956 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5957 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5958 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5961 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5964 if (redefined_ce_found)
5966 /* this level set has CE definitions: change "AUTO" to "FALSE" */
5967 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5968 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
5969 gfx.override_level_music = (setup.override_level_music == TRUE);
5973 /* this level set has no CE definitions: change "AUTO" to "TRUE" */
5974 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5975 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
5976 gfx.override_level_music = (setup.override_level_music != FALSE);
5980 printf("::: => %d, %d, %d\n",
5981 gfx.override_level_graphics,
5982 gfx.override_level_sounds,
5983 gfx.override_level_music);
5987 static char *getNewArtworkIdentifier(int type)
5989 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5990 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5991 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5992 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5993 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5995 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5997 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
5999 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
6000 char *leveldir_identifier = leveldir_current->identifier;
6002 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
6003 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
6005 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
6007 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
6008 char *artwork_current_identifier;
6009 char *artwork_new_identifier = NULL; /* default: nothing has changed */
6011 /* leveldir_current may be invalid (level group, parent link) */
6012 if (!validLevelSeries(leveldir_current))
6015 /* 1st step: determine artwork set to be activated in descending order:
6016 --------------------------------------------------------------------
6017 1. setup artwork (when configured to override everything else)
6018 2. artwork set configured in "levelinfo.conf" of current level set
6019 (artwork in level directory will have priority when loading later)
6020 3. artwork in level directory (stored in artwork sub-directory)
6021 4. setup artwork (currently configured in setup menu) */
6023 if (setup_override_artwork)
6024 artwork_current_identifier = setup_artwork_set;
6025 else if (leveldir_artwork_set != NULL)
6026 artwork_current_identifier = leveldir_artwork_set;
6027 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
6028 artwork_current_identifier = leveldir_identifier;
6030 artwork_current_identifier = setup_artwork_set;
6033 /* 2nd step: check if it is really needed to reload artwork set
6034 ------------------------------------------------------------ */
6037 if (type == ARTWORK_TYPE_GRAPHICS)
6038 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
6039 artwork_new_identifier,
6040 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
6041 artwork_current_identifier,
6042 leveldir_current->graphics_set,
6043 leveldir_current->identifier);
6046 /* ---------- reload if level set and also artwork set has changed ------- */
6047 if (leveldir_current_identifier[type] != leveldir_identifier &&
6048 (last_has_level_artwork_set[type] || has_level_artwork_set))
6049 artwork_new_identifier = artwork_current_identifier;
6051 leveldir_current_identifier[type] = leveldir_identifier;
6052 last_has_level_artwork_set[type] = has_level_artwork_set;
6055 if (type == ARTWORK_TYPE_GRAPHICS)
6056 printf("::: 1: '%s'\n", artwork_new_identifier);
6059 /* ---------- reload if "override artwork" setting has changed ----------- */
6060 if (last_override_level_artwork[type] != setup_override_artwork)
6061 artwork_new_identifier = artwork_current_identifier;
6063 last_override_level_artwork[type] = setup_override_artwork;
6066 if (type == ARTWORK_TYPE_GRAPHICS)
6067 printf("::: 2: '%s'\n", artwork_new_identifier);
6070 /* ---------- reload if current artwork identifier has changed ----------- */
6071 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
6072 artwork_current_identifier))
6073 artwork_new_identifier = artwork_current_identifier;
6075 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
6078 if (type == ARTWORK_TYPE_GRAPHICS)
6079 printf("::: 3: '%s'\n", artwork_new_identifier);
6082 /* ---------- do not reload directly after starting ---------------------- */
6083 if (!initialized[type])
6084 artwork_new_identifier = NULL;
6086 initialized[type] = TRUE;
6089 if (type == ARTWORK_TYPE_GRAPHICS)
6090 printf("::: 4: '%s'\n", artwork_new_identifier);
6094 if (type == ARTWORK_TYPE_GRAPHICS)
6095 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
6096 artwork.gfx_current_identifier, artwork_current_identifier,
6097 artwork.gfx_current->identifier, leveldir_current->graphics_set,
6098 artwork_new_identifier);
6101 return artwork_new_identifier;
6104 void ReloadCustomArtwork(int force_reload)
6106 int last_game_status = game_status; /* save current game status */
6107 char *gfx_new_identifier;
6108 char *snd_new_identifier;
6109 char *mus_new_identifier;
6110 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
6111 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
6112 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
6113 boolean reload_needed;
6115 InitOverrideArtwork();
6117 force_reload_gfx |= AdjustGraphicsForEMC();
6119 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
6120 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
6121 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
6123 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
6124 snd_new_identifier != NULL || force_reload_snd ||
6125 mus_new_identifier != NULL || force_reload_mus);
6130 print_timestamp_init("ReloadCustomArtwork");
6132 game_status = GAME_MODE_LOADING;
6134 FadeOut(REDRAW_ALL);
6137 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6139 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
6141 print_timestamp_time("ClearRectangle");
6144 printf("::: fading in ... %d\n", fading.fade_mode);
6148 printf("::: done\n");
6151 if (gfx_new_identifier != NULL || force_reload_gfx)
6154 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
6155 artwork.gfx_current_identifier,
6157 artwork.gfx_current->identifier,
6158 leveldir_current->graphics_set);
6162 print_timestamp_time("InitImages");
6165 if (snd_new_identifier != NULL || force_reload_snd)
6167 InitSound(snd_new_identifier);
6168 print_timestamp_time("InitSound");
6171 if (mus_new_identifier != NULL || force_reload_mus)
6173 InitMusic(mus_new_identifier);
6174 print_timestamp_time("InitMusic");
6177 game_status = last_game_status; /* restore current game status */
6179 init_last = init; /* switch to new busy animation */
6182 printf("::: ----------------DELAY 1 ...\n");
6187 printf("::: FadeOut @ ReloadCustomArtwork ...\n");
6189 FadeOut(REDRAW_ALL);
6191 printf("::: FadeOut @ ReloadCustomArtwork done\n");
6196 /* force redraw of (open or closed) door graphics */
6197 SetDoorState(DOOR_OPEN_ALL);
6198 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
6203 FadeSetEnterScreen();
6204 FadeSkipNextFadeOut();
6205 // FadeSetDisabled();
6210 fading = fading_none;
6215 redraw_mask = REDRAW_ALL;
6218 print_timestamp_done("ReloadCustomArtwork");
6221 void KeyboardAutoRepeatOffUnlessAutoplay()
6223 if (global.autoplay_leveldir == NULL)
6224 KeyboardAutoRepeatOff();
6227 void DisplayExitMessage(char *format, va_list ap)
6229 // check if draw buffer and fonts for exit message are already available
6230 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
6233 int font_1 = FC_RED;
6234 int font_2 = FC_YELLOW;
6235 int font_3 = FC_BLUE;
6236 int font_width = getFontWidth(font_2);
6237 int font_height = getFontHeight(font_2);
6240 int sxsize = WIN_XSIZE - 2 * sx;
6241 int sysize = WIN_YSIZE - 2 * sy;
6242 int line_length = sxsize / font_width;
6243 int max_lines = sysize / font_height;
6244 int num_lines_printed;
6248 gfx.sxsize = sxsize;
6249 gfx.sysize = sysize;
6253 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6255 DrawTextSCentered(sy, font_1, "Fatal error:");
6256 sy += 3 * font_height;;
6259 DrawTextBufferVA(sx, sy, format, ap, font_2,
6260 line_length, line_length, max_lines,
6261 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6262 sy += (num_lines_printed + 3) * font_height;
6264 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
6265 sy += 3 * font_height;
6268 DrawTextBuffer(sx, sy, program.error_filename, font_2,
6269 line_length, line_length, max_lines,
6270 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6272 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
6274 redraw_mask = REDRAW_ALL;
6278 /* deactivate toons on error message screen */
6279 setup.toons = FALSE;
6281 WaitForEventToContinue();
6285 /* ========================================================================= */
6287 /* ========================================================================= */
6291 print_timestamp_init("OpenAll");
6293 game_status = GAME_MODE_LOADING;
6299 InitGlobal(); /* initialize some global variables */
6301 print_timestamp_time("[init global stuff]");
6303 if (options.execute_command)
6304 Execute_Command(options.execute_command);
6306 if (options.serveronly)
6308 #if defined(PLATFORM_UNIX)
6309 NetworkServer(options.server_port, options.serveronly);
6311 Error(ERR_WARN, "networking only supported in Unix version");
6314 exit(0); /* never reached, server loops forever */
6320 Error(ERR_INFO, "::: MARK 1: setup.fullscreen == %d", setup.fullscreen);
6323 print_timestamp_time("[init setup/config stuff (1)]");
6326 print_timestamp_time("[init setup/config stuff (2)]");
6328 print_timestamp_time("[init setup/config stuff (3)]");
6329 InitArtworkInfo(); /* needed before loading gfx, sound & music */
6330 print_timestamp_time("[init setup/config stuff (4)]");
6331 InitArtworkConfig(); /* needed before forking sound child process */
6332 print_timestamp_time("[init setup/config stuff (5)]");
6334 print_timestamp_time("[init setup/config stuff (6)]");
6340 InitRND(NEW_RANDOMIZE);
6341 InitSimpleRandom(NEW_RANDOMIZE);
6345 print_timestamp_time("[init setup/config stuff]");
6348 Error(ERR_INFO, "::: MARK 2: setup.fullscreen == %d", setup.fullscreen);
6352 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
6354 InitEventFilter(FilterEvents);
6356 print_timestamp_time("[init video stuff]");
6358 InitElementPropertiesStatic();
6359 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
6360 InitElementPropertiesGfxElement();
6362 print_timestamp_time("[init element properties stuff]");
6366 print_timestamp_time("InitGfx");
6369 print_timestamp_time("InitLevelInfo");
6371 InitLevelArtworkInfo();
6372 print_timestamp_time("InitLevelArtworkInfo");
6374 InitOverrideArtwork(); /* needs to know current level directory */
6375 print_timestamp_time("InitOverrideArtwork");
6377 InitImages(); /* needs to know current level directory */
6378 print_timestamp_time("InitImages");
6380 InitSound(NULL); /* needs to know current level directory */
6381 print_timestamp_time("InitSound");
6383 InitMusic(NULL); /* needs to know current level directory */
6384 print_timestamp_time("InitMusic");
6386 InitGfxBackground();
6396 if (global.autoplay_leveldir)
6401 else if (global.convert_leveldir)
6406 else if (global.create_images_dir)
6408 CreateLevelSketchImages();
6412 game_status = GAME_MODE_MAIN;
6415 FadeSetEnterScreen();
6416 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
6417 FadeSkipNextFadeOut();
6418 // FadeSetDisabled();
6420 fading = fading_none;
6423 print_timestamp_time("[post-artwork]");
6425 print_timestamp_done("OpenAll");
6429 InitNetworkServer();
6432 Error(ERR_DEBUG, "::: SDL_GetBasePath() == '%s'",
6434 Error(ERR_DEBUG, "::: SDL_GetPrefPath() == '%s'",
6435 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
6436 #if defined(PLATFORM_ANDROID)
6437 Error(ERR_DEBUG, "::: SDL_AndroidGetInternalStoragePath() == '%s'",
6438 SDL_AndroidGetInternalStoragePath());
6439 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStoragePath() == '%s'",
6440 SDL_AndroidGetExternalStoragePath());
6441 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStorageState() == '%s'",
6442 (SDL_AndroidGetExternalStorageState() ==
6443 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "read" :
6444 SDL_AndroidGetExternalStorageState() ==
6445 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "write" : "not available"));
6450 void CloseAllAndExit(int exit_value)
6455 CloseAudio(); /* called after freeing sounds (needed for SDL) */
6467 #if defined(TARGET_SDL)
6468 #if defined(TARGET_SDL2)
6470 // set a flag to tell the network server thread to quit and wait for it
6471 // using SDL_WaitThread()
6473 if (network_server) /* terminate network server */
6474 SDL_KillThread(server_thread);
6478 CloseVideoDisplay();
6479 ClosePlatformDependentStuff();
6481 if (exit_value != 0)
6483 /* fall back to default level set (current set may have caused an error) */
6484 SaveLevelSetup_LastSeries_Deactivate();
6486 /* tell user where to find error log file which may contain more details */
6487 // (error notification now directly displayed on screen inside R'n'D
6488 // NotifyUserAboutErrorFile(); /* currently only works for Windows */