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 InitGraphicCompatibilityInfo_Doors();
2013 int *width, *height;
2018 { IMG_DOOR_1_WING_LEFT, &door_1.width, &door_1.height, FALSE },
2019 { IMG_DOOR_1_WING_RIGHT, &door_1.width, &door_1.height, TRUE },
2020 { IMG_DOOR_2_WING_LEFT, &door_2.width, &door_2.height, FALSE },
2021 { IMG_DOOR_2_WING_RIGHT, &door_2.width, &door_2.height, TRUE },
2023 { 0, NULL, NULL, FALSE }
2026 for (i = 0; doors[i].graphic != 0; i++)
2028 int graphic = doors[i].graphic;
2029 int *width = doors[i].width;
2030 int *height = doors[i].height;
2031 boolean right_wing = doors[i].right_wing;
2033 struct FileInfo *fi = getImageListEntryFromImageID(graphic);
2034 struct GraphicInfo *g = &graphic_info[graphic];
2040 // correct start position for right wing of "standard" door graphic
2042 g->src_x += g->width - *width;
2048 g->height = *height;
2054 for (i = 0; i < num_images; i++)
2056 struct FileInfo *fi = getImageListEntryFromImageID(i);
2058 if (i == IMG_GLOBAL_DOOR)
2060 printf("::: %s, %s, %d\n",
2061 fi->default_filename,
2069 static void InitElementSoundInfo()
2071 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
2072 int num_property_mappings = getSoundListPropertyMappingSize();
2075 /* set values to -1 to identify later as "uninitialized" values */
2076 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2077 for (act = 0; act < NUM_ACTIONS; act++)
2078 element_info[i].sound[act] = -1;
2080 /* initialize element/sound mapping from static configuration */
2081 for (i = 0; element_to_sound[i].element > -1; i++)
2083 int element = element_to_sound[i].element;
2084 int action = element_to_sound[i].action;
2085 int sound = element_to_sound[i].sound;
2086 boolean is_class = element_to_sound[i].is_class;
2089 action = ACTION_DEFAULT;
2092 element_info[element].sound[action] = sound;
2094 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2095 if (strEqual(element_info[j].class_name,
2096 element_info[element].class_name))
2097 element_info[j].sound[action] = sound;
2100 /* initialize element class/sound mapping from dynamic configuration */
2101 for (i = 0; i < num_property_mappings; i++)
2103 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
2104 int action = property_mapping[i].ext1_index;
2105 int sound = property_mapping[i].artwork_index;
2107 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
2111 action = ACTION_DEFAULT;
2113 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2114 if (strEqual(element_info[j].class_name,
2115 element_info[element_class].class_name))
2116 element_info[j].sound[action] = sound;
2119 /* initialize element/sound mapping from dynamic configuration */
2120 for (i = 0; i < num_property_mappings; i++)
2122 int element = property_mapping[i].base_index;
2123 int action = property_mapping[i].ext1_index;
2124 int sound = property_mapping[i].artwork_index;
2126 if (element >= MAX_NUM_ELEMENTS)
2130 action = ACTION_DEFAULT;
2132 element_info[element].sound[action] = sound;
2135 /* now set all '-1' values to element specific default values */
2136 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2138 for (act = 0; act < NUM_ACTIONS; act++)
2140 /* generic default action sound (defined by "[default]" directive) */
2141 int default_action_sound = element_info[EL_DEFAULT].sound[act];
2143 /* look for special default action sound (classic game specific) */
2144 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
2145 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
2146 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
2147 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
2148 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
2149 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
2151 /* !!! there's no such thing as a "default action sound" !!! */
2153 /* look for element specific default sound (independent from action) */
2154 if (element_info[i].sound[ACTION_DEFAULT] != -1)
2155 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
2159 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
2160 /* !!! make this better !!! */
2161 if (i == EL_EMPTY_SPACE)
2162 default_action_sound = element_info[EL_DEFAULT].sound[act];
2165 /* no sound for this specific action -- use default action sound */
2166 if (element_info[i].sound[act] == -1)
2167 element_info[i].sound[act] = default_action_sound;
2171 /* copy sound settings to some elements that are only stored in level file
2172 in native R'n'D levels, but are used by game engine in native EM levels */
2173 for (i = 0; copy_properties[i][0] != -1; i++)
2174 for (j = 1; j <= 4; j++)
2175 for (act = 0; act < NUM_ACTIONS; act++)
2176 element_info[copy_properties[i][j]].sound[act] =
2177 element_info[copy_properties[i][0]].sound[act];
2180 static void InitGameModeSoundInfo()
2184 /* set values to -1 to identify later as "uninitialized" values */
2185 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2188 /* initialize gamemode/sound mapping from static configuration */
2189 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
2191 int gamemode = gamemode_to_sound[i].gamemode;
2192 int sound = gamemode_to_sound[i].sound;
2195 gamemode = GAME_MODE_DEFAULT;
2197 menu.sound[gamemode] = sound;
2200 /* now set all '-1' values to levelset specific default values */
2201 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2202 if (menu.sound[i] == -1)
2203 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
2206 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2207 if (menu.sound[i] != -1)
2208 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
2212 static void set_sound_parameters(int sound, char **parameter_raw)
2214 int parameter[NUM_SND_ARGS];
2217 /* get integer values from string parameters */
2218 for (i = 0; i < NUM_SND_ARGS; i++)
2220 get_parameter_value(parameter_raw[i],
2221 sound_config_suffix[i].token,
2222 sound_config_suffix[i].type);
2224 /* explicit loop mode setting in configuration overrides default value */
2225 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2226 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
2228 /* sound volume to change the original volume when loading the sound file */
2229 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
2231 /* sound priority to give certain sounds a higher or lower priority */
2232 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
2235 static void InitSoundInfo()
2237 int *sound_effect_properties;
2238 int num_sounds = getSoundListSize();
2241 checked_free(sound_info);
2243 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
2244 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
2246 /* initialize sound effect for all elements to "no sound" */
2247 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2248 for (j = 0; j < NUM_ACTIONS; j++)
2249 element_info[i].sound[j] = SND_UNDEFINED;
2251 for (i = 0; i < num_sounds; i++)
2253 struct FileInfo *sound = getSoundListEntry(i);
2254 int len_effect_text = strlen(sound->token);
2256 sound_effect_properties[i] = ACTION_OTHER;
2257 sound_info[i].loop = FALSE; /* default: play sound only once */
2260 printf("::: sound %d: '%s'\n", i, sound->token);
2263 /* determine all loop sounds and identify certain sound classes */
2265 for (j = 0; element_action_info[j].suffix; j++)
2267 int len_action_text = strlen(element_action_info[j].suffix);
2269 if (len_action_text < len_effect_text &&
2270 strEqual(&sound->token[len_effect_text - len_action_text],
2271 element_action_info[j].suffix))
2273 sound_effect_properties[i] = element_action_info[j].value;
2274 sound_info[i].loop = element_action_info[j].is_loop_sound;
2280 /* associate elements and some selected sound actions */
2282 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2284 if (element_info[j].class_name)
2286 int len_class_text = strlen(element_info[j].class_name);
2288 if (len_class_text + 1 < len_effect_text &&
2289 strncmp(sound->token,
2290 element_info[j].class_name, len_class_text) == 0 &&
2291 sound->token[len_class_text] == '.')
2293 int sound_action_value = sound_effect_properties[i];
2295 element_info[j].sound[sound_action_value] = i;
2300 set_sound_parameters(i, sound->parameter);
2303 free(sound_effect_properties);
2306 static void InitGameModeMusicInfo()
2308 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
2309 int num_property_mappings = getMusicListPropertyMappingSize();
2310 int default_levelset_music = -1;
2313 /* set values to -1 to identify later as "uninitialized" values */
2314 for (i = 0; i < MAX_LEVELS; i++)
2315 levelset.music[i] = -1;
2316 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2319 /* initialize gamemode/music mapping from static configuration */
2320 for (i = 0; gamemode_to_music[i].music > -1; i++)
2322 int gamemode = gamemode_to_music[i].gamemode;
2323 int music = gamemode_to_music[i].music;
2326 printf("::: gamemode == %d, music == %d\n", gamemode, music);
2330 gamemode = GAME_MODE_DEFAULT;
2332 menu.music[gamemode] = music;
2335 /* initialize gamemode/music mapping from dynamic configuration */
2336 for (i = 0; i < num_property_mappings; i++)
2338 int prefix = property_mapping[i].base_index;
2339 int gamemode = property_mapping[i].ext1_index;
2340 int level = property_mapping[i].ext2_index;
2341 int music = property_mapping[i].artwork_index;
2344 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
2345 prefix, gamemode, level, music);
2348 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
2352 gamemode = GAME_MODE_DEFAULT;
2354 /* level specific music only allowed for in-game music */
2355 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
2356 gamemode = GAME_MODE_PLAYING;
2361 default_levelset_music = music;
2364 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
2365 levelset.music[level] = music;
2366 if (gamemode != GAME_MODE_PLAYING)
2367 menu.music[gamemode] = music;
2370 /* now set all '-1' values to menu specific default values */
2371 /* (undefined values of "levelset.music[]" might stay at "-1" to
2372 allow dynamic selection of music files from music directory!) */
2373 for (i = 0; i < MAX_LEVELS; i++)
2374 if (levelset.music[i] == -1)
2375 levelset.music[i] = default_levelset_music;
2376 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2377 if (menu.music[i] == -1)
2378 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
2381 for (i = 0; i < MAX_LEVELS; i++)
2382 if (levelset.music[i] != -1)
2383 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
2384 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2385 if (menu.music[i] != -1)
2386 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
2390 static void set_music_parameters(int music, char **parameter_raw)
2392 int parameter[NUM_MUS_ARGS];
2395 /* get integer values from string parameters */
2396 for (i = 0; i < NUM_MUS_ARGS; i++)
2398 get_parameter_value(parameter_raw[i],
2399 music_config_suffix[i].token,
2400 music_config_suffix[i].type);
2402 /* explicit loop mode setting in configuration overrides default value */
2403 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2404 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
2407 static void InitMusicInfo()
2409 int num_music = getMusicListSize();
2412 checked_free(music_info);
2414 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
2416 for (i = 0; i < num_music; i++)
2418 struct FileInfo *music = getMusicListEntry(i);
2419 int len_music_text = strlen(music->token);
2421 music_info[i].loop = TRUE; /* default: play music in loop mode */
2423 /* determine all loop music */
2425 for (j = 0; music_prefix_info[j].prefix; j++)
2427 int len_prefix_text = strlen(music_prefix_info[j].prefix);
2429 if (len_prefix_text < len_music_text &&
2430 strncmp(music->token,
2431 music_prefix_info[j].prefix, len_prefix_text) == 0)
2433 music_info[i].loop = music_prefix_info[j].is_loop_music;
2439 set_music_parameters(i, music->parameter);
2443 static void ReinitializeGraphics()
2445 print_timestamp_init("ReinitializeGraphics");
2447 InitGraphicInfo(); /* graphic properties mapping */
2448 print_timestamp_time("InitGraphicInfo");
2449 InitElementGraphicInfo(); /* element game graphic mapping */
2450 print_timestamp_time("InitElementGraphicInfo");
2451 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
2452 print_timestamp_time("InitElementSpecialGraphicInfo");
2454 InitElementSmallImages(); /* scale elements to all needed sizes */
2455 print_timestamp_time("InitElementSmallImages");
2456 InitScaledImages(); /* scale all other images, if needed */
2457 print_timestamp_time("InitScaledImages");
2458 InitFontGraphicInfo(); /* initialize text drawing functions */
2459 print_timestamp_time("InitFontGraphicInfo");
2461 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
2462 print_timestamp_time("InitGraphicInfo_EM");
2464 InitGraphicCompatibilityInfo();
2465 print_timestamp_time("InitGraphicCompatibilityInfo");
2467 SetMainBackgroundImage(IMG_BACKGROUND);
2468 print_timestamp_time("SetMainBackgroundImage");
2469 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2470 print_timestamp_time("SetDoorBackgroundImage");
2473 print_timestamp_time("InitGadgets");
2475 print_timestamp_time("InitToons");
2477 print_timestamp_time("InitDoors");
2479 print_timestamp_done("ReinitializeGraphics");
2482 static void ReinitializeSounds()
2484 InitSoundInfo(); /* sound properties mapping */
2485 InitElementSoundInfo(); /* element game sound mapping */
2486 InitGameModeSoundInfo(); /* game mode sound mapping */
2488 InitPlayLevelSound(); /* internal game sound settings */
2491 static void ReinitializeMusic()
2493 InitMusicInfo(); /* music properties mapping */
2494 InitGameModeMusicInfo(); /* game mode music mapping */
2497 static int get_special_property_bit(int element, int property_bit_nr)
2499 struct PropertyBitInfo
2505 static struct PropertyBitInfo pb_can_move_into_acid[] =
2507 /* the player may be able fall into acid when gravity is activated */
2512 { EL_SP_MURPHY, 0 },
2513 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2515 /* all elements that can move may be able to also move into acid */
2518 { EL_BUG_RIGHT, 1 },
2521 { EL_SPACESHIP, 2 },
2522 { EL_SPACESHIP_LEFT, 2 },
2523 { EL_SPACESHIP_RIGHT, 2 },
2524 { EL_SPACESHIP_UP, 2 },
2525 { EL_SPACESHIP_DOWN, 2 },
2526 { EL_BD_BUTTERFLY, 3 },
2527 { EL_BD_BUTTERFLY_LEFT, 3 },
2528 { EL_BD_BUTTERFLY_RIGHT, 3 },
2529 { EL_BD_BUTTERFLY_UP, 3 },
2530 { EL_BD_BUTTERFLY_DOWN, 3 },
2531 { EL_BD_FIREFLY, 4 },
2532 { EL_BD_FIREFLY_LEFT, 4 },
2533 { EL_BD_FIREFLY_RIGHT, 4 },
2534 { EL_BD_FIREFLY_UP, 4 },
2535 { EL_BD_FIREFLY_DOWN, 4 },
2537 { EL_YAMYAM_LEFT, 5 },
2538 { EL_YAMYAM_RIGHT, 5 },
2539 { EL_YAMYAM_UP, 5 },
2540 { EL_YAMYAM_DOWN, 5 },
2541 { EL_DARK_YAMYAM, 6 },
2544 { EL_PACMAN_LEFT, 8 },
2545 { EL_PACMAN_RIGHT, 8 },
2546 { EL_PACMAN_UP, 8 },
2547 { EL_PACMAN_DOWN, 8 },
2549 { EL_MOLE_LEFT, 9 },
2550 { EL_MOLE_RIGHT, 9 },
2552 { EL_MOLE_DOWN, 9 },
2556 { EL_SATELLITE, 13 },
2557 { EL_SP_SNIKSNAK, 14 },
2558 { EL_SP_ELECTRON, 15 },
2561 { EL_EMC_ANDROID, 18 },
2566 static struct PropertyBitInfo pb_dont_collide_with[] =
2568 { EL_SP_SNIKSNAK, 0 },
2569 { EL_SP_ELECTRON, 1 },
2577 struct PropertyBitInfo *pb_info;
2580 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2581 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2586 struct PropertyBitInfo *pb_info = NULL;
2589 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2590 if (pb_definition[i].bit_nr == property_bit_nr)
2591 pb_info = pb_definition[i].pb_info;
2593 if (pb_info == NULL)
2596 for (i = 0; pb_info[i].element != -1; i++)
2597 if (pb_info[i].element == element)
2598 return pb_info[i].bit_nr;
2603 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2604 boolean property_value)
2606 int bit_nr = get_special_property_bit(element, property_bit_nr);
2611 *bitfield |= (1 << bit_nr);
2613 *bitfield &= ~(1 << bit_nr);
2617 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2619 int bit_nr = get_special_property_bit(element, property_bit_nr);
2622 return ((*bitfield & (1 << bit_nr)) != 0);
2627 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2629 static int group_nr;
2630 static struct ElementGroupInfo *group;
2631 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2634 if (actual_group == NULL) /* not yet initialized */
2637 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
2639 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2640 group_element - EL_GROUP_START + 1);
2642 /* replace element which caused too deep recursion by question mark */
2643 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2648 if (recursion_depth == 0) /* initialization */
2650 group = actual_group;
2651 group_nr = GROUP_NR(group_element);
2653 group->num_elements_resolved = 0;
2654 group->choice_pos = 0;
2656 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2657 element_info[i].in_group[group_nr] = FALSE;
2660 for (i = 0; i < actual_group->num_elements; i++)
2662 int element = actual_group->element[i];
2664 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2667 if (IS_GROUP_ELEMENT(element))
2668 ResolveGroupElementExt(element, recursion_depth + 1);
2671 group->element_resolved[group->num_elements_resolved++] = element;
2672 element_info[element].in_group[group_nr] = TRUE;
2677 void ResolveGroupElement(int group_element)
2679 ResolveGroupElementExt(group_element, 0);
2682 void InitElementPropertiesStatic()
2684 static boolean clipboard_elements_initialized = FALSE;
2686 static int ep_diggable[] =
2691 EL_SP_BUGGY_BASE_ACTIVATING,
2694 EL_INVISIBLE_SAND_ACTIVE,
2697 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2698 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2703 EL_SP_BUGGY_BASE_ACTIVE,
2710 static int ep_collectible_only[] =
2732 EL_DYNABOMB_INCREASE_NUMBER,
2733 EL_DYNABOMB_INCREASE_SIZE,
2734 EL_DYNABOMB_INCREASE_POWER,
2752 /* !!! handle separately !!! */
2753 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2759 static int ep_dont_run_into[] =
2761 /* same elements as in 'ep_dont_touch' */
2767 /* same elements as in 'ep_dont_collide_with' */
2779 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2784 EL_SP_BUGGY_BASE_ACTIVE,
2791 static int ep_dont_collide_with[] =
2793 /* same elements as in 'ep_dont_touch' */
2810 static int ep_dont_touch[] =
2820 static int ep_indestructible[] =
2824 EL_ACID_POOL_TOPLEFT,
2825 EL_ACID_POOL_TOPRIGHT,
2826 EL_ACID_POOL_BOTTOMLEFT,
2827 EL_ACID_POOL_BOTTOM,
2828 EL_ACID_POOL_BOTTOMRIGHT,
2829 EL_SP_HARDWARE_GRAY,
2830 EL_SP_HARDWARE_GREEN,
2831 EL_SP_HARDWARE_BLUE,
2833 EL_SP_HARDWARE_YELLOW,
2834 EL_SP_HARDWARE_BASE_1,
2835 EL_SP_HARDWARE_BASE_2,
2836 EL_SP_HARDWARE_BASE_3,
2837 EL_SP_HARDWARE_BASE_4,
2838 EL_SP_HARDWARE_BASE_5,
2839 EL_SP_HARDWARE_BASE_6,
2840 EL_INVISIBLE_STEELWALL,
2841 EL_INVISIBLE_STEELWALL_ACTIVE,
2842 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2843 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2844 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2845 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2846 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2847 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2848 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2849 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2850 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2851 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2852 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2853 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2855 EL_LIGHT_SWITCH_ACTIVE,
2856 EL_SIGN_EXCLAMATION,
2857 EL_SIGN_RADIOACTIVITY,
2864 EL_SIGN_ENTRY_FORBIDDEN,
2865 EL_SIGN_EMERGENCY_EXIT,
2873 EL_STEEL_EXIT_CLOSED,
2875 EL_STEEL_EXIT_OPENING,
2876 EL_STEEL_EXIT_CLOSING,
2877 EL_EM_STEEL_EXIT_CLOSED,
2878 EL_EM_STEEL_EXIT_OPEN,
2879 EL_EM_STEEL_EXIT_OPENING,
2880 EL_EM_STEEL_EXIT_CLOSING,
2881 EL_DC_STEELWALL_1_LEFT,
2882 EL_DC_STEELWALL_1_RIGHT,
2883 EL_DC_STEELWALL_1_TOP,
2884 EL_DC_STEELWALL_1_BOTTOM,
2885 EL_DC_STEELWALL_1_HORIZONTAL,
2886 EL_DC_STEELWALL_1_VERTICAL,
2887 EL_DC_STEELWALL_1_TOPLEFT,
2888 EL_DC_STEELWALL_1_TOPRIGHT,
2889 EL_DC_STEELWALL_1_BOTTOMLEFT,
2890 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2891 EL_DC_STEELWALL_1_TOPLEFT_2,
2892 EL_DC_STEELWALL_1_TOPRIGHT_2,
2893 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2894 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2895 EL_DC_STEELWALL_2_LEFT,
2896 EL_DC_STEELWALL_2_RIGHT,
2897 EL_DC_STEELWALL_2_TOP,
2898 EL_DC_STEELWALL_2_BOTTOM,
2899 EL_DC_STEELWALL_2_HORIZONTAL,
2900 EL_DC_STEELWALL_2_VERTICAL,
2901 EL_DC_STEELWALL_2_MIDDLE,
2902 EL_DC_STEELWALL_2_SINGLE,
2903 EL_STEELWALL_SLIPPERY,
2917 EL_GATE_1_GRAY_ACTIVE,
2918 EL_GATE_2_GRAY_ACTIVE,
2919 EL_GATE_3_GRAY_ACTIVE,
2920 EL_GATE_4_GRAY_ACTIVE,
2929 EL_EM_GATE_1_GRAY_ACTIVE,
2930 EL_EM_GATE_2_GRAY_ACTIVE,
2931 EL_EM_GATE_3_GRAY_ACTIVE,
2932 EL_EM_GATE_4_GRAY_ACTIVE,
2941 EL_EMC_GATE_5_GRAY_ACTIVE,
2942 EL_EMC_GATE_6_GRAY_ACTIVE,
2943 EL_EMC_GATE_7_GRAY_ACTIVE,
2944 EL_EMC_GATE_8_GRAY_ACTIVE,
2946 EL_DC_GATE_WHITE_GRAY,
2947 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2948 EL_DC_GATE_FAKE_GRAY,
2950 EL_SWITCHGATE_OPENING,
2951 EL_SWITCHGATE_CLOSED,
2952 EL_SWITCHGATE_CLOSING,
2954 EL_DC_SWITCHGATE_SWITCH_UP,
2955 EL_DC_SWITCHGATE_SWITCH_DOWN,
2958 EL_TIMEGATE_OPENING,
2960 EL_TIMEGATE_CLOSING,
2962 EL_DC_TIMEGATE_SWITCH,
2963 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2968 EL_TUBE_VERTICAL_LEFT,
2969 EL_TUBE_VERTICAL_RIGHT,
2970 EL_TUBE_HORIZONTAL_UP,
2971 EL_TUBE_HORIZONTAL_DOWN,
2976 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2977 EL_EXPANDABLE_STEELWALL_VERTICAL,
2978 EL_EXPANDABLE_STEELWALL_ANY,
2983 static int ep_slippery[] =
2997 EL_ROBOT_WHEEL_ACTIVE,
3003 EL_ACID_POOL_TOPLEFT,
3004 EL_ACID_POOL_TOPRIGHT,
3014 EL_STEELWALL_SLIPPERY,
3017 EL_EMC_WALL_SLIPPERY_1,
3018 EL_EMC_WALL_SLIPPERY_2,
3019 EL_EMC_WALL_SLIPPERY_3,
3020 EL_EMC_WALL_SLIPPERY_4,
3022 EL_EMC_MAGIC_BALL_ACTIVE,
3027 static int ep_can_change[] =
3032 static int ep_can_move[] =
3034 /* same elements as in 'pb_can_move_into_acid' */
3057 static int ep_can_fall[] =
3071 EL_QUICKSAND_FAST_FULL,
3073 EL_BD_MAGIC_WALL_FULL,
3074 EL_DC_MAGIC_WALL_FULL,
3088 static int ep_can_smash_player[] =
3114 static int ep_can_smash_enemies[] =
3123 static int ep_can_smash_everything[] =
3132 static int ep_explodes_by_fire[] =
3134 /* same elements as in 'ep_explodes_impact' */
3139 /* same elements as in 'ep_explodes_smashed' */
3149 EL_EM_DYNAMITE_ACTIVE,
3150 EL_DYNABOMB_PLAYER_1_ACTIVE,
3151 EL_DYNABOMB_PLAYER_2_ACTIVE,
3152 EL_DYNABOMB_PLAYER_3_ACTIVE,
3153 EL_DYNABOMB_PLAYER_4_ACTIVE,
3154 EL_DYNABOMB_INCREASE_NUMBER,
3155 EL_DYNABOMB_INCREASE_SIZE,
3156 EL_DYNABOMB_INCREASE_POWER,
3157 EL_SP_DISK_RED_ACTIVE,
3171 static int ep_explodes_smashed[] =
3173 /* same elements as in 'ep_explodes_impact' */
3187 static int ep_explodes_impact[] =
3196 static int ep_walkable_over[] =
3200 EL_SOKOBAN_FIELD_EMPTY,
3209 EL_EM_STEEL_EXIT_OPEN,
3211 EL_EM_STEEL_EXIT_OPENING,
3221 EL_GATE_1_GRAY_ACTIVE,
3222 EL_GATE_2_GRAY_ACTIVE,
3223 EL_GATE_3_GRAY_ACTIVE,
3224 EL_GATE_4_GRAY_ACTIVE,
3232 static int ep_walkable_inside[] =
3237 EL_TUBE_VERTICAL_LEFT,
3238 EL_TUBE_VERTICAL_RIGHT,
3239 EL_TUBE_HORIZONTAL_UP,
3240 EL_TUBE_HORIZONTAL_DOWN,
3249 static int ep_walkable_under[] =
3254 static int ep_passable_over[] =
3264 EL_EM_GATE_1_GRAY_ACTIVE,
3265 EL_EM_GATE_2_GRAY_ACTIVE,
3266 EL_EM_GATE_3_GRAY_ACTIVE,
3267 EL_EM_GATE_4_GRAY_ACTIVE,
3276 EL_EMC_GATE_5_GRAY_ACTIVE,
3277 EL_EMC_GATE_6_GRAY_ACTIVE,
3278 EL_EMC_GATE_7_GRAY_ACTIVE,
3279 EL_EMC_GATE_8_GRAY_ACTIVE,
3281 EL_DC_GATE_WHITE_GRAY,
3282 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3289 static int ep_passable_inside[] =
3295 EL_SP_PORT_HORIZONTAL,
3296 EL_SP_PORT_VERTICAL,
3298 EL_SP_GRAVITY_PORT_LEFT,
3299 EL_SP_GRAVITY_PORT_RIGHT,
3300 EL_SP_GRAVITY_PORT_UP,
3301 EL_SP_GRAVITY_PORT_DOWN,
3302 EL_SP_GRAVITY_ON_PORT_LEFT,
3303 EL_SP_GRAVITY_ON_PORT_RIGHT,
3304 EL_SP_GRAVITY_ON_PORT_UP,
3305 EL_SP_GRAVITY_ON_PORT_DOWN,
3306 EL_SP_GRAVITY_OFF_PORT_LEFT,
3307 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3308 EL_SP_GRAVITY_OFF_PORT_UP,
3309 EL_SP_GRAVITY_OFF_PORT_DOWN,
3314 static int ep_passable_under[] =
3319 static int ep_droppable[] =
3324 static int ep_explodes_1x1_old[] =
3329 static int ep_pushable[] =
3341 EL_SOKOBAN_FIELD_FULL,
3350 static int ep_explodes_cross_old[] =
3355 static int ep_protected[] =
3357 /* same elements as in 'ep_walkable_inside' */
3361 EL_TUBE_VERTICAL_LEFT,
3362 EL_TUBE_VERTICAL_RIGHT,
3363 EL_TUBE_HORIZONTAL_UP,
3364 EL_TUBE_HORIZONTAL_DOWN,
3370 /* same elements as in 'ep_passable_over' */
3379 EL_EM_GATE_1_GRAY_ACTIVE,
3380 EL_EM_GATE_2_GRAY_ACTIVE,
3381 EL_EM_GATE_3_GRAY_ACTIVE,
3382 EL_EM_GATE_4_GRAY_ACTIVE,
3391 EL_EMC_GATE_5_GRAY_ACTIVE,
3392 EL_EMC_GATE_6_GRAY_ACTIVE,
3393 EL_EMC_GATE_7_GRAY_ACTIVE,
3394 EL_EMC_GATE_8_GRAY_ACTIVE,
3396 EL_DC_GATE_WHITE_GRAY,
3397 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3401 /* same elements as in 'ep_passable_inside' */
3406 EL_SP_PORT_HORIZONTAL,
3407 EL_SP_PORT_VERTICAL,
3409 EL_SP_GRAVITY_PORT_LEFT,
3410 EL_SP_GRAVITY_PORT_RIGHT,
3411 EL_SP_GRAVITY_PORT_UP,
3412 EL_SP_GRAVITY_PORT_DOWN,
3413 EL_SP_GRAVITY_ON_PORT_LEFT,
3414 EL_SP_GRAVITY_ON_PORT_RIGHT,
3415 EL_SP_GRAVITY_ON_PORT_UP,
3416 EL_SP_GRAVITY_ON_PORT_DOWN,
3417 EL_SP_GRAVITY_OFF_PORT_LEFT,
3418 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3419 EL_SP_GRAVITY_OFF_PORT_UP,
3420 EL_SP_GRAVITY_OFF_PORT_DOWN,
3425 static int ep_throwable[] =
3430 static int ep_can_explode[] =
3432 /* same elements as in 'ep_explodes_impact' */
3437 /* same elements as in 'ep_explodes_smashed' */
3443 /* elements that can explode by explosion or by dragonfire */
3447 EL_EM_DYNAMITE_ACTIVE,
3448 EL_DYNABOMB_PLAYER_1_ACTIVE,
3449 EL_DYNABOMB_PLAYER_2_ACTIVE,
3450 EL_DYNABOMB_PLAYER_3_ACTIVE,
3451 EL_DYNABOMB_PLAYER_4_ACTIVE,
3452 EL_DYNABOMB_INCREASE_NUMBER,
3453 EL_DYNABOMB_INCREASE_SIZE,
3454 EL_DYNABOMB_INCREASE_POWER,
3455 EL_SP_DISK_RED_ACTIVE,
3463 /* elements that can explode only by explosion */
3469 static int ep_gravity_reachable[] =
3475 EL_INVISIBLE_SAND_ACTIVE,
3480 EL_SP_PORT_HORIZONTAL,
3481 EL_SP_PORT_VERTICAL,
3483 EL_SP_GRAVITY_PORT_LEFT,
3484 EL_SP_GRAVITY_PORT_RIGHT,
3485 EL_SP_GRAVITY_PORT_UP,
3486 EL_SP_GRAVITY_PORT_DOWN,
3487 EL_SP_GRAVITY_ON_PORT_LEFT,
3488 EL_SP_GRAVITY_ON_PORT_RIGHT,
3489 EL_SP_GRAVITY_ON_PORT_UP,
3490 EL_SP_GRAVITY_ON_PORT_DOWN,
3491 EL_SP_GRAVITY_OFF_PORT_LEFT,
3492 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3493 EL_SP_GRAVITY_OFF_PORT_UP,
3494 EL_SP_GRAVITY_OFF_PORT_DOWN,
3500 static int ep_player[] =
3507 EL_SOKOBAN_FIELD_PLAYER,
3513 static int ep_can_pass_magic_wall[] =
3527 static int ep_can_pass_dc_magic_wall[] =
3543 static int ep_switchable[] =
3547 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3548 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3549 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3550 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3551 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3552 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3553 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3554 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3555 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3556 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3557 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3558 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3559 EL_SWITCHGATE_SWITCH_UP,
3560 EL_SWITCHGATE_SWITCH_DOWN,
3561 EL_DC_SWITCHGATE_SWITCH_UP,
3562 EL_DC_SWITCHGATE_SWITCH_DOWN,
3564 EL_LIGHT_SWITCH_ACTIVE,
3566 EL_DC_TIMEGATE_SWITCH,
3567 EL_BALLOON_SWITCH_LEFT,
3568 EL_BALLOON_SWITCH_RIGHT,
3569 EL_BALLOON_SWITCH_UP,
3570 EL_BALLOON_SWITCH_DOWN,
3571 EL_BALLOON_SWITCH_ANY,
3572 EL_BALLOON_SWITCH_NONE,
3575 EL_EMC_MAGIC_BALL_SWITCH,
3576 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3581 static int ep_bd_element[] =
3615 static int ep_sp_element[] =
3617 /* should always be valid */
3620 /* standard classic Supaplex elements */
3627 EL_SP_HARDWARE_GRAY,
3635 EL_SP_GRAVITY_PORT_RIGHT,
3636 EL_SP_GRAVITY_PORT_DOWN,
3637 EL_SP_GRAVITY_PORT_LEFT,
3638 EL_SP_GRAVITY_PORT_UP,
3643 EL_SP_PORT_VERTICAL,
3644 EL_SP_PORT_HORIZONTAL,
3650 EL_SP_HARDWARE_BASE_1,
3651 EL_SP_HARDWARE_GREEN,
3652 EL_SP_HARDWARE_BLUE,
3654 EL_SP_HARDWARE_YELLOW,
3655 EL_SP_HARDWARE_BASE_2,
3656 EL_SP_HARDWARE_BASE_3,
3657 EL_SP_HARDWARE_BASE_4,
3658 EL_SP_HARDWARE_BASE_5,
3659 EL_SP_HARDWARE_BASE_6,
3663 /* additional elements that appeared in newer Supaplex levels */
3666 /* additional gravity port elements (not switching, but setting gravity) */
3667 EL_SP_GRAVITY_ON_PORT_LEFT,
3668 EL_SP_GRAVITY_ON_PORT_RIGHT,
3669 EL_SP_GRAVITY_ON_PORT_UP,
3670 EL_SP_GRAVITY_ON_PORT_DOWN,
3671 EL_SP_GRAVITY_OFF_PORT_LEFT,
3672 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3673 EL_SP_GRAVITY_OFF_PORT_UP,
3674 EL_SP_GRAVITY_OFF_PORT_DOWN,
3676 /* more than one Murphy in a level results in an inactive clone */
3679 /* runtime Supaplex elements */
3680 EL_SP_DISK_RED_ACTIVE,
3681 EL_SP_TERMINAL_ACTIVE,
3682 EL_SP_BUGGY_BASE_ACTIVATING,
3683 EL_SP_BUGGY_BASE_ACTIVE,
3690 static int ep_sb_element[] =
3695 EL_SOKOBAN_FIELD_EMPTY,
3696 EL_SOKOBAN_FIELD_FULL,
3697 EL_SOKOBAN_FIELD_PLAYER,
3702 EL_INVISIBLE_STEELWALL,
3707 static int ep_gem[] =
3719 static int ep_food_dark_yamyam[] =
3747 static int ep_food_penguin[] =
3761 static int ep_food_pig[] =
3773 static int ep_historic_wall[] =
3784 EL_GATE_1_GRAY_ACTIVE,
3785 EL_GATE_2_GRAY_ACTIVE,
3786 EL_GATE_3_GRAY_ACTIVE,
3787 EL_GATE_4_GRAY_ACTIVE,
3796 EL_EM_GATE_1_GRAY_ACTIVE,
3797 EL_EM_GATE_2_GRAY_ACTIVE,
3798 EL_EM_GATE_3_GRAY_ACTIVE,
3799 EL_EM_GATE_4_GRAY_ACTIVE,
3806 EL_EXPANDABLE_WALL_HORIZONTAL,
3807 EL_EXPANDABLE_WALL_VERTICAL,
3808 EL_EXPANDABLE_WALL_ANY,
3809 EL_EXPANDABLE_WALL_GROWING,
3810 EL_BD_EXPANDABLE_WALL,
3817 EL_SP_HARDWARE_GRAY,
3818 EL_SP_HARDWARE_GREEN,
3819 EL_SP_HARDWARE_BLUE,
3821 EL_SP_HARDWARE_YELLOW,
3822 EL_SP_HARDWARE_BASE_1,
3823 EL_SP_HARDWARE_BASE_2,
3824 EL_SP_HARDWARE_BASE_3,
3825 EL_SP_HARDWARE_BASE_4,
3826 EL_SP_HARDWARE_BASE_5,
3827 EL_SP_HARDWARE_BASE_6,
3829 EL_SP_TERMINAL_ACTIVE,
3832 EL_INVISIBLE_STEELWALL,
3833 EL_INVISIBLE_STEELWALL_ACTIVE,
3835 EL_INVISIBLE_WALL_ACTIVE,
3836 EL_STEELWALL_SLIPPERY,
3853 static int ep_historic_solid[] =
3857 EL_EXPANDABLE_WALL_HORIZONTAL,
3858 EL_EXPANDABLE_WALL_VERTICAL,
3859 EL_EXPANDABLE_WALL_ANY,
3860 EL_BD_EXPANDABLE_WALL,
3873 EL_QUICKSAND_FILLING,
3874 EL_QUICKSAND_EMPTYING,
3876 EL_MAGIC_WALL_ACTIVE,
3877 EL_MAGIC_WALL_EMPTYING,
3878 EL_MAGIC_WALL_FILLING,
3882 EL_BD_MAGIC_WALL_ACTIVE,
3883 EL_BD_MAGIC_WALL_EMPTYING,
3884 EL_BD_MAGIC_WALL_FULL,
3885 EL_BD_MAGIC_WALL_FILLING,
3886 EL_BD_MAGIC_WALL_DEAD,
3895 EL_SP_TERMINAL_ACTIVE,
3899 EL_INVISIBLE_WALL_ACTIVE,
3900 EL_SWITCHGATE_SWITCH_UP,
3901 EL_SWITCHGATE_SWITCH_DOWN,
3902 EL_DC_SWITCHGATE_SWITCH_UP,
3903 EL_DC_SWITCHGATE_SWITCH_DOWN,
3905 EL_TIMEGATE_SWITCH_ACTIVE,
3906 EL_DC_TIMEGATE_SWITCH,
3907 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3919 /* the following elements are a direct copy of "indestructible" elements,
3920 except "EL_ACID", which is "indestructible", but not "solid"! */
3925 EL_ACID_POOL_TOPLEFT,
3926 EL_ACID_POOL_TOPRIGHT,
3927 EL_ACID_POOL_BOTTOMLEFT,
3928 EL_ACID_POOL_BOTTOM,
3929 EL_ACID_POOL_BOTTOMRIGHT,
3930 EL_SP_HARDWARE_GRAY,
3931 EL_SP_HARDWARE_GREEN,
3932 EL_SP_HARDWARE_BLUE,
3934 EL_SP_HARDWARE_YELLOW,
3935 EL_SP_HARDWARE_BASE_1,
3936 EL_SP_HARDWARE_BASE_2,
3937 EL_SP_HARDWARE_BASE_3,
3938 EL_SP_HARDWARE_BASE_4,
3939 EL_SP_HARDWARE_BASE_5,
3940 EL_SP_HARDWARE_BASE_6,
3941 EL_INVISIBLE_STEELWALL,
3942 EL_INVISIBLE_STEELWALL_ACTIVE,
3943 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3944 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3945 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3946 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3947 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3948 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3949 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3950 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3951 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3952 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3953 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3954 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3956 EL_LIGHT_SWITCH_ACTIVE,
3957 EL_SIGN_EXCLAMATION,
3958 EL_SIGN_RADIOACTIVITY,
3965 EL_SIGN_ENTRY_FORBIDDEN,
3966 EL_SIGN_EMERGENCY_EXIT,
3974 EL_STEEL_EXIT_CLOSED,
3976 EL_DC_STEELWALL_1_LEFT,
3977 EL_DC_STEELWALL_1_RIGHT,
3978 EL_DC_STEELWALL_1_TOP,
3979 EL_DC_STEELWALL_1_BOTTOM,
3980 EL_DC_STEELWALL_1_HORIZONTAL,
3981 EL_DC_STEELWALL_1_VERTICAL,
3982 EL_DC_STEELWALL_1_TOPLEFT,
3983 EL_DC_STEELWALL_1_TOPRIGHT,
3984 EL_DC_STEELWALL_1_BOTTOMLEFT,
3985 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3986 EL_DC_STEELWALL_1_TOPLEFT_2,
3987 EL_DC_STEELWALL_1_TOPRIGHT_2,
3988 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3989 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3990 EL_DC_STEELWALL_2_LEFT,
3991 EL_DC_STEELWALL_2_RIGHT,
3992 EL_DC_STEELWALL_2_TOP,
3993 EL_DC_STEELWALL_2_BOTTOM,
3994 EL_DC_STEELWALL_2_HORIZONTAL,
3995 EL_DC_STEELWALL_2_VERTICAL,
3996 EL_DC_STEELWALL_2_MIDDLE,
3997 EL_DC_STEELWALL_2_SINGLE,
3998 EL_STEELWALL_SLIPPERY,
4012 EL_GATE_1_GRAY_ACTIVE,
4013 EL_GATE_2_GRAY_ACTIVE,
4014 EL_GATE_3_GRAY_ACTIVE,
4015 EL_GATE_4_GRAY_ACTIVE,
4024 EL_EM_GATE_1_GRAY_ACTIVE,
4025 EL_EM_GATE_2_GRAY_ACTIVE,
4026 EL_EM_GATE_3_GRAY_ACTIVE,
4027 EL_EM_GATE_4_GRAY_ACTIVE,
4029 EL_SWITCHGATE_OPENING,
4030 EL_SWITCHGATE_CLOSED,
4031 EL_SWITCHGATE_CLOSING,
4033 EL_TIMEGATE_OPENING,
4035 EL_TIMEGATE_CLOSING,
4039 EL_TUBE_VERTICAL_LEFT,
4040 EL_TUBE_VERTICAL_RIGHT,
4041 EL_TUBE_HORIZONTAL_UP,
4042 EL_TUBE_HORIZONTAL_DOWN,
4051 static int ep_classic_enemy[] =
4068 static int ep_belt[] =
4070 EL_CONVEYOR_BELT_1_LEFT,
4071 EL_CONVEYOR_BELT_1_MIDDLE,
4072 EL_CONVEYOR_BELT_1_RIGHT,
4073 EL_CONVEYOR_BELT_2_LEFT,
4074 EL_CONVEYOR_BELT_2_MIDDLE,
4075 EL_CONVEYOR_BELT_2_RIGHT,
4076 EL_CONVEYOR_BELT_3_LEFT,
4077 EL_CONVEYOR_BELT_3_MIDDLE,
4078 EL_CONVEYOR_BELT_3_RIGHT,
4079 EL_CONVEYOR_BELT_4_LEFT,
4080 EL_CONVEYOR_BELT_4_MIDDLE,
4081 EL_CONVEYOR_BELT_4_RIGHT,
4086 static int ep_belt_active[] =
4088 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
4089 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
4090 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
4091 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
4092 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
4093 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
4094 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
4095 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
4096 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
4097 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
4098 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
4099 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
4104 static int ep_belt_switch[] =
4106 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4107 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4108 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4109 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4110 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4111 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4112 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4113 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4114 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4115 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4116 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4117 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4122 static int ep_tube[] =
4129 EL_TUBE_HORIZONTAL_UP,
4130 EL_TUBE_HORIZONTAL_DOWN,
4132 EL_TUBE_VERTICAL_LEFT,
4133 EL_TUBE_VERTICAL_RIGHT,
4139 static int ep_acid_pool[] =
4141 EL_ACID_POOL_TOPLEFT,
4142 EL_ACID_POOL_TOPRIGHT,
4143 EL_ACID_POOL_BOTTOMLEFT,
4144 EL_ACID_POOL_BOTTOM,
4145 EL_ACID_POOL_BOTTOMRIGHT,
4150 static int ep_keygate[] =
4160 EL_GATE_1_GRAY_ACTIVE,
4161 EL_GATE_2_GRAY_ACTIVE,
4162 EL_GATE_3_GRAY_ACTIVE,
4163 EL_GATE_4_GRAY_ACTIVE,
4172 EL_EM_GATE_1_GRAY_ACTIVE,
4173 EL_EM_GATE_2_GRAY_ACTIVE,
4174 EL_EM_GATE_3_GRAY_ACTIVE,
4175 EL_EM_GATE_4_GRAY_ACTIVE,
4184 EL_EMC_GATE_5_GRAY_ACTIVE,
4185 EL_EMC_GATE_6_GRAY_ACTIVE,
4186 EL_EMC_GATE_7_GRAY_ACTIVE,
4187 EL_EMC_GATE_8_GRAY_ACTIVE,
4189 EL_DC_GATE_WHITE_GRAY,
4190 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4195 static int ep_amoeboid[] =
4207 static int ep_amoebalive[] =
4218 static int ep_has_editor_content[] =
4224 EL_SOKOBAN_FIELD_PLAYER,
4241 static int ep_can_turn_each_move[] =
4243 /* !!! do something with this one !!! */
4247 static int ep_can_grow[] =
4261 static int ep_active_bomb[] =
4264 EL_EM_DYNAMITE_ACTIVE,
4265 EL_DYNABOMB_PLAYER_1_ACTIVE,
4266 EL_DYNABOMB_PLAYER_2_ACTIVE,
4267 EL_DYNABOMB_PLAYER_3_ACTIVE,
4268 EL_DYNABOMB_PLAYER_4_ACTIVE,
4269 EL_SP_DISK_RED_ACTIVE,
4274 static int ep_inactive[] =
4284 EL_QUICKSAND_FAST_EMPTY,
4307 EL_GATE_1_GRAY_ACTIVE,
4308 EL_GATE_2_GRAY_ACTIVE,
4309 EL_GATE_3_GRAY_ACTIVE,
4310 EL_GATE_4_GRAY_ACTIVE,
4319 EL_EM_GATE_1_GRAY_ACTIVE,
4320 EL_EM_GATE_2_GRAY_ACTIVE,
4321 EL_EM_GATE_3_GRAY_ACTIVE,
4322 EL_EM_GATE_4_GRAY_ACTIVE,
4331 EL_EMC_GATE_5_GRAY_ACTIVE,
4332 EL_EMC_GATE_6_GRAY_ACTIVE,
4333 EL_EMC_GATE_7_GRAY_ACTIVE,
4334 EL_EMC_GATE_8_GRAY_ACTIVE,
4336 EL_DC_GATE_WHITE_GRAY,
4337 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4338 EL_DC_GATE_FAKE_GRAY,
4341 EL_INVISIBLE_STEELWALL,
4349 EL_WALL_EMERALD_YELLOW,
4350 EL_DYNABOMB_INCREASE_NUMBER,
4351 EL_DYNABOMB_INCREASE_SIZE,
4352 EL_DYNABOMB_INCREASE_POWER,
4356 EL_SOKOBAN_FIELD_EMPTY,
4357 EL_SOKOBAN_FIELD_FULL,
4358 EL_WALL_EMERALD_RED,
4359 EL_WALL_EMERALD_PURPLE,
4360 EL_ACID_POOL_TOPLEFT,
4361 EL_ACID_POOL_TOPRIGHT,
4362 EL_ACID_POOL_BOTTOMLEFT,
4363 EL_ACID_POOL_BOTTOM,
4364 EL_ACID_POOL_BOTTOMRIGHT,
4368 EL_BD_MAGIC_WALL_DEAD,
4370 EL_DC_MAGIC_WALL_DEAD,
4371 EL_AMOEBA_TO_DIAMOND,
4379 EL_SP_GRAVITY_PORT_RIGHT,
4380 EL_SP_GRAVITY_PORT_DOWN,
4381 EL_SP_GRAVITY_PORT_LEFT,
4382 EL_SP_GRAVITY_PORT_UP,
4383 EL_SP_PORT_HORIZONTAL,
4384 EL_SP_PORT_VERTICAL,
4395 EL_SP_HARDWARE_GRAY,
4396 EL_SP_HARDWARE_GREEN,
4397 EL_SP_HARDWARE_BLUE,
4399 EL_SP_HARDWARE_YELLOW,
4400 EL_SP_HARDWARE_BASE_1,
4401 EL_SP_HARDWARE_BASE_2,
4402 EL_SP_HARDWARE_BASE_3,
4403 EL_SP_HARDWARE_BASE_4,
4404 EL_SP_HARDWARE_BASE_5,
4405 EL_SP_HARDWARE_BASE_6,
4406 EL_SP_GRAVITY_ON_PORT_LEFT,
4407 EL_SP_GRAVITY_ON_PORT_RIGHT,
4408 EL_SP_GRAVITY_ON_PORT_UP,
4409 EL_SP_GRAVITY_ON_PORT_DOWN,
4410 EL_SP_GRAVITY_OFF_PORT_LEFT,
4411 EL_SP_GRAVITY_OFF_PORT_RIGHT,
4412 EL_SP_GRAVITY_OFF_PORT_UP,
4413 EL_SP_GRAVITY_OFF_PORT_DOWN,
4414 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4415 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4416 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4417 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4418 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4419 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4420 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4421 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4422 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4423 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4424 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4425 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4426 EL_SIGN_EXCLAMATION,
4427 EL_SIGN_RADIOACTIVITY,
4434 EL_SIGN_ENTRY_FORBIDDEN,
4435 EL_SIGN_EMERGENCY_EXIT,
4443 EL_DC_STEELWALL_1_LEFT,
4444 EL_DC_STEELWALL_1_RIGHT,
4445 EL_DC_STEELWALL_1_TOP,
4446 EL_DC_STEELWALL_1_BOTTOM,
4447 EL_DC_STEELWALL_1_HORIZONTAL,
4448 EL_DC_STEELWALL_1_VERTICAL,
4449 EL_DC_STEELWALL_1_TOPLEFT,
4450 EL_DC_STEELWALL_1_TOPRIGHT,
4451 EL_DC_STEELWALL_1_BOTTOMLEFT,
4452 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4453 EL_DC_STEELWALL_1_TOPLEFT_2,
4454 EL_DC_STEELWALL_1_TOPRIGHT_2,
4455 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4456 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4457 EL_DC_STEELWALL_2_LEFT,
4458 EL_DC_STEELWALL_2_RIGHT,
4459 EL_DC_STEELWALL_2_TOP,
4460 EL_DC_STEELWALL_2_BOTTOM,
4461 EL_DC_STEELWALL_2_HORIZONTAL,
4462 EL_DC_STEELWALL_2_VERTICAL,
4463 EL_DC_STEELWALL_2_MIDDLE,
4464 EL_DC_STEELWALL_2_SINGLE,
4465 EL_STEELWALL_SLIPPERY,
4470 EL_EMC_WALL_SLIPPERY_1,
4471 EL_EMC_WALL_SLIPPERY_2,
4472 EL_EMC_WALL_SLIPPERY_3,
4473 EL_EMC_WALL_SLIPPERY_4,
4494 static int ep_em_slippery_wall[] =
4499 static int ep_gfx_crumbled[] =
4510 static int ep_editor_cascade_active[] =
4512 EL_INTERNAL_CASCADE_BD_ACTIVE,
4513 EL_INTERNAL_CASCADE_EM_ACTIVE,
4514 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4515 EL_INTERNAL_CASCADE_RND_ACTIVE,
4516 EL_INTERNAL_CASCADE_SB_ACTIVE,
4517 EL_INTERNAL_CASCADE_SP_ACTIVE,
4518 EL_INTERNAL_CASCADE_DC_ACTIVE,
4519 EL_INTERNAL_CASCADE_DX_ACTIVE,
4520 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4521 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4522 EL_INTERNAL_CASCADE_CE_ACTIVE,
4523 EL_INTERNAL_CASCADE_GE_ACTIVE,
4524 EL_INTERNAL_CASCADE_REF_ACTIVE,
4525 EL_INTERNAL_CASCADE_USER_ACTIVE,
4526 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4531 static int ep_editor_cascade_inactive[] =
4533 EL_INTERNAL_CASCADE_BD,
4534 EL_INTERNAL_CASCADE_EM,
4535 EL_INTERNAL_CASCADE_EMC,
4536 EL_INTERNAL_CASCADE_RND,
4537 EL_INTERNAL_CASCADE_SB,
4538 EL_INTERNAL_CASCADE_SP,
4539 EL_INTERNAL_CASCADE_DC,
4540 EL_INTERNAL_CASCADE_DX,
4541 EL_INTERNAL_CASCADE_CHARS,
4542 EL_INTERNAL_CASCADE_STEEL_CHARS,
4543 EL_INTERNAL_CASCADE_CE,
4544 EL_INTERNAL_CASCADE_GE,
4545 EL_INTERNAL_CASCADE_REF,
4546 EL_INTERNAL_CASCADE_USER,
4547 EL_INTERNAL_CASCADE_DYNAMIC,
4552 static int ep_obsolete[] =
4556 EL_EM_KEY_1_FILE_OBSOLETE,
4557 EL_EM_KEY_2_FILE_OBSOLETE,
4558 EL_EM_KEY_3_FILE_OBSOLETE,
4559 EL_EM_KEY_4_FILE_OBSOLETE,
4560 EL_ENVELOPE_OBSOLETE,
4569 } element_properties[] =
4571 { ep_diggable, EP_DIGGABLE },
4572 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4573 { ep_dont_run_into, EP_DONT_RUN_INTO },
4574 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4575 { ep_dont_touch, EP_DONT_TOUCH },
4576 { ep_indestructible, EP_INDESTRUCTIBLE },
4577 { ep_slippery, EP_SLIPPERY },
4578 { ep_can_change, EP_CAN_CHANGE },
4579 { ep_can_move, EP_CAN_MOVE },
4580 { ep_can_fall, EP_CAN_FALL },
4581 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4582 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4583 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4584 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4585 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4586 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4587 { ep_walkable_over, EP_WALKABLE_OVER },
4588 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4589 { ep_walkable_under, EP_WALKABLE_UNDER },
4590 { ep_passable_over, EP_PASSABLE_OVER },
4591 { ep_passable_inside, EP_PASSABLE_INSIDE },
4592 { ep_passable_under, EP_PASSABLE_UNDER },
4593 { ep_droppable, EP_DROPPABLE },
4594 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4595 { ep_pushable, EP_PUSHABLE },
4596 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4597 { ep_protected, EP_PROTECTED },
4598 { ep_throwable, EP_THROWABLE },
4599 { ep_can_explode, EP_CAN_EXPLODE },
4600 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4602 { ep_player, EP_PLAYER },
4603 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4604 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4605 { ep_switchable, EP_SWITCHABLE },
4606 { ep_bd_element, EP_BD_ELEMENT },
4607 { ep_sp_element, EP_SP_ELEMENT },
4608 { ep_sb_element, EP_SB_ELEMENT },
4610 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4611 { ep_food_penguin, EP_FOOD_PENGUIN },
4612 { ep_food_pig, EP_FOOD_PIG },
4613 { ep_historic_wall, EP_HISTORIC_WALL },
4614 { ep_historic_solid, EP_HISTORIC_SOLID },
4615 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4616 { ep_belt, EP_BELT },
4617 { ep_belt_active, EP_BELT_ACTIVE },
4618 { ep_belt_switch, EP_BELT_SWITCH },
4619 { ep_tube, EP_TUBE },
4620 { ep_acid_pool, EP_ACID_POOL },
4621 { ep_keygate, EP_KEYGATE },
4622 { ep_amoeboid, EP_AMOEBOID },
4623 { ep_amoebalive, EP_AMOEBALIVE },
4624 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4625 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4626 { ep_can_grow, EP_CAN_GROW },
4627 { ep_active_bomb, EP_ACTIVE_BOMB },
4628 { ep_inactive, EP_INACTIVE },
4630 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4632 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4634 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4635 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4637 { ep_obsolete, EP_OBSOLETE },
4644 /* always start with reliable default values (element has no properties) */
4645 /* (but never initialize clipboard elements after the very first time) */
4646 /* (to be able to use clipboard elements between several levels) */
4647 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4648 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4649 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4650 SET_PROPERTY(i, j, FALSE);
4652 /* set all base element properties from above array definitions */
4653 for (i = 0; element_properties[i].elements != NULL; i++)
4654 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4655 SET_PROPERTY((element_properties[i].elements)[j],
4656 element_properties[i].property, TRUE);
4658 /* copy properties to some elements that are only stored in level file */
4659 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4660 for (j = 0; copy_properties[j][0] != -1; j++)
4661 if (HAS_PROPERTY(copy_properties[j][0], i))
4662 for (k = 1; k <= 4; k++)
4663 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4665 /* set static element properties that are not listed in array definitions */
4666 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4667 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4669 clipboard_elements_initialized = TRUE;
4672 void InitElementPropertiesEngine(int engine_version)
4674 static int no_wall_properties[] =
4677 EP_COLLECTIBLE_ONLY,
4679 EP_DONT_COLLIDE_WITH,
4682 EP_CAN_SMASH_PLAYER,
4683 EP_CAN_SMASH_ENEMIES,
4684 EP_CAN_SMASH_EVERYTHING,
4689 EP_FOOD_DARK_YAMYAM,
4705 /* important: after initialization in InitElementPropertiesStatic(), the
4706 elements are not again initialized to a default value; therefore all
4707 changes have to make sure that they leave the element with a defined
4708 property (which means that conditional property changes must be set to
4709 a reliable default value before) */
4711 /* resolve group elements */
4712 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4713 ResolveGroupElement(EL_GROUP_START + i);
4715 /* set all special, combined or engine dependent element properties */
4716 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4718 /* do not change (already initialized) clipboard elements here */
4719 if (IS_CLIPBOARD_ELEMENT(i))
4722 /* ---------- INACTIVE ------------------------------------------------- */
4723 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4724 i <= EL_CHAR_END) ||
4725 (i >= EL_STEEL_CHAR_START &&
4726 i <= EL_STEEL_CHAR_END)));
4728 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4729 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4730 IS_WALKABLE_INSIDE(i) ||
4731 IS_WALKABLE_UNDER(i)));
4733 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4734 IS_PASSABLE_INSIDE(i) ||
4735 IS_PASSABLE_UNDER(i)));
4737 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4738 IS_PASSABLE_OVER(i)));
4740 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4741 IS_PASSABLE_INSIDE(i)));
4743 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4744 IS_PASSABLE_UNDER(i)));
4746 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4749 /* ---------- COLLECTIBLE ---------------------------------------------- */
4750 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4754 /* ---------- SNAPPABLE ------------------------------------------------ */
4755 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4756 IS_COLLECTIBLE(i) ||
4760 /* ---------- WALL ----------------------------------------------------- */
4761 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4763 for (j = 0; no_wall_properties[j] != -1; j++)
4764 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4765 i >= EL_FIRST_RUNTIME_UNREAL)
4766 SET_PROPERTY(i, EP_WALL, FALSE);
4768 if (IS_HISTORIC_WALL(i))
4769 SET_PROPERTY(i, EP_WALL, TRUE);
4771 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4772 if (engine_version < VERSION_IDENT(2,2,0,0))
4773 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4775 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4777 !IS_COLLECTIBLE(i)));
4779 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4780 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4781 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4783 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4784 IS_INDESTRUCTIBLE(i)));
4786 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4788 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4789 else if (engine_version < VERSION_IDENT(2,2,0,0))
4790 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4792 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4796 if (IS_CUSTOM_ELEMENT(i))
4798 /* these are additional properties which are initially false when set */
4800 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4802 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4803 if (DONT_COLLIDE_WITH(i))
4804 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4806 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4807 if (CAN_SMASH_EVERYTHING(i))
4808 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4809 if (CAN_SMASH_ENEMIES(i))
4810 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4813 /* ---------- CAN_SMASH ------------------------------------------------ */
4814 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4815 CAN_SMASH_ENEMIES(i) ||
4816 CAN_SMASH_EVERYTHING(i)));
4818 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4819 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4820 EXPLODES_BY_FIRE(i)));
4822 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4823 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4824 EXPLODES_SMASHED(i)));
4826 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4827 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4828 EXPLODES_IMPACT(i)));
4830 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4831 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4833 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4834 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4835 i == EL_BLACK_ORB));
4837 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4838 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4840 IS_CUSTOM_ELEMENT(i)));
4842 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4843 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4844 i == EL_SP_ELECTRON));
4846 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4847 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4848 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4849 getMoveIntoAcidProperty(&level, i));
4851 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4852 if (MAYBE_DONT_COLLIDE_WITH(i))
4853 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4854 getDontCollideWithProperty(&level, i));
4856 /* ---------- SP_PORT -------------------------------------------------- */
4857 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4858 IS_PASSABLE_INSIDE(i)));
4860 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4861 for (j = 0; j < level.num_android_clone_elements; j++)
4862 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4864 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4866 /* ---------- CAN_CHANGE ----------------------------------------------- */
4867 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4868 for (j = 0; j < element_info[i].num_change_pages; j++)
4869 if (element_info[i].change_page[j].can_change)
4870 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4872 /* ---------- HAS_ACTION ----------------------------------------------- */
4873 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4874 for (j = 0; j < element_info[i].num_change_pages; j++)
4875 if (element_info[i].change_page[j].has_action)
4876 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4878 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4879 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4882 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4884 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4885 element_info[i].crumbled[ACTION_DEFAULT] !=
4886 element_info[i].graphic[ACTION_DEFAULT]);
4888 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
4889 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4890 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
4893 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4894 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4895 IS_EDITOR_CASCADE_INACTIVE(i)));
4898 /* dynamically adjust element properties according to game engine version */
4900 static int ep_em_slippery_wall[] =
4905 EL_EXPANDABLE_WALL_HORIZONTAL,
4906 EL_EXPANDABLE_WALL_VERTICAL,
4907 EL_EXPANDABLE_WALL_ANY,
4908 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4909 EL_EXPANDABLE_STEELWALL_VERTICAL,
4910 EL_EXPANDABLE_STEELWALL_ANY,
4911 EL_EXPANDABLE_STEELWALL_GROWING,
4915 static int ep_em_explodes_by_fire[] =
4918 EL_EM_DYNAMITE_ACTIVE,
4923 /* special EM style gems behaviour */
4924 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4925 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4926 level.em_slippery_gems);
4928 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4929 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4930 (level.em_slippery_gems &&
4931 engine_version > VERSION_IDENT(2,0,1,0)));
4933 /* special EM style explosion behaviour regarding chain reactions */
4934 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4935 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4936 level.em_explodes_by_fire);
4939 /* this is needed because some graphics depend on element properties */
4940 if (game_status == GAME_MODE_PLAYING)
4941 InitElementGraphicInfo();
4944 void InitElementPropertiesAfterLoading(int engine_version)
4948 /* set some other uninitialized values of custom elements in older levels */
4949 if (engine_version < VERSION_IDENT(3,1,0,0))
4951 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4953 int element = EL_CUSTOM_START + i;
4955 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4957 element_info[element].explosion_delay = 17;
4958 element_info[element].ignition_delay = 8;
4963 void InitElementPropertiesGfxElement()
4967 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4969 struct ElementInfo *ei = &element_info[i];
4971 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4975 static void InitGlobal()
4980 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4982 /* check if element_name_info entry defined for each element in "main.h" */
4983 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4984 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4986 element_info[i].token_name = element_name_info[i].token_name;
4987 element_info[i].class_name = element_name_info[i].class_name;
4988 element_info[i].editor_description= element_name_info[i].editor_description;
4991 printf("%04d: %s\n", i, element_name_info[i].token_name);
4995 /* create hash from image config list */
4996 image_config_hash = newSetupFileHash();
4997 for (i = 0; image_config[i].token != NULL; i++)
4998 setHashEntry(image_config_hash,
4999 image_config[i].token,
5000 image_config[i].value);
5002 /* create hash from element token list */
5003 element_token_hash = newSetupFileHash();
5004 for (i = 0; element_name_info[i].token_name != NULL; i++)
5005 setHashEntry(element_token_hash,
5006 element_name_info[i].token_name,
5009 /* create hash from graphic token list */
5010 graphic_token_hash = newSetupFileHash();
5011 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
5012 if (strSuffix(image_config[i].value, ".png") ||
5013 strSuffix(image_config[i].value, ".pcx") ||
5014 strSuffix(image_config[i].value, ".wav") ||
5015 strEqual(image_config[i].value, UNDEFINED_FILENAME))
5016 setHashEntry(graphic_token_hash,
5017 image_config[i].token,
5018 int2str(graphic++, 0));
5020 /* create hash from font token list */
5021 font_token_hash = newSetupFileHash();
5022 for (i = 0; font_info[i].token_name != NULL; i++)
5023 setHashEntry(font_token_hash,
5024 font_info[i].token_name,
5027 /* always start with reliable default values (all elements) */
5028 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5029 ActiveElement[i] = i;
5031 /* now add all entries that have an active state (active elements) */
5032 for (i = 0; element_with_active_state[i].element != -1; i++)
5034 int element = element_with_active_state[i].element;
5035 int element_active = element_with_active_state[i].element_active;
5037 ActiveElement[element] = element_active;
5040 /* always start with reliable default values (all buttons) */
5041 for (i = 0; i < NUM_IMAGE_FILES; i++)
5042 ActiveButton[i] = i;
5044 /* now add all entries that have an active state (active buttons) */
5045 for (i = 0; button_with_active_state[i].button != -1; i++)
5047 int button = button_with_active_state[i].button;
5048 int button_active = button_with_active_state[i].button_active;
5050 ActiveButton[button] = button_active;
5053 /* always start with reliable default values (all fonts) */
5054 for (i = 0; i < NUM_FONTS; i++)
5057 /* now add all entries that have an active state (active fonts) */
5058 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
5060 int font = font_with_active_state[i].font_nr;
5061 int font_active = font_with_active_state[i].font_nr_active;
5063 ActiveFont[font] = font_active;
5066 global.autoplay_leveldir = NULL;
5067 global.convert_leveldir = NULL;
5068 global.create_images_dir = NULL;
5070 global.frames_per_second = 0;
5071 global.fps_slowdown = FALSE;
5072 global.fps_slowdown_factor = 1;
5074 global.border_status = GAME_MODE_MAIN;
5076 global.fading_status = GAME_MODE_MAIN;
5077 global.fading_type = TYPE_ENTER_MENU;
5080 global.use_envelope_request = FALSE;
5083 void Execute_Command(char *command)
5087 if (strEqual(command, "print graphicsinfo.conf"))
5089 printf("# You can configure additional/alternative image files here.\n");
5090 printf("# (The entries below are default and therefore commented out.)\n");
5092 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
5094 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5097 for (i = 0; image_config[i].token != NULL; i++)
5098 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
5099 image_config[i].value));
5103 else if (strEqual(command, "print soundsinfo.conf"))
5105 printf("# You can configure additional/alternative sound files here.\n");
5106 printf("# (The entries below are default and therefore commented out.)\n");
5108 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
5110 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5113 for (i = 0; sound_config[i].token != NULL; i++)
5114 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
5115 sound_config[i].value));
5119 else if (strEqual(command, "print musicinfo.conf"))
5121 printf("# You can configure additional/alternative music files here.\n");
5122 printf("# (The entries below are default and therefore commented out.)\n");
5124 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
5126 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5129 for (i = 0; music_config[i].token != NULL; i++)
5130 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
5131 music_config[i].value));
5135 else if (strEqual(command, "print editorsetup.conf"))
5137 printf("# You can configure your personal editor element list here.\n");
5138 printf("# (The entries below are default and therefore commented out.)\n");
5141 /* this is needed to be able to check element list for cascade elements */
5142 InitElementPropertiesStatic();
5143 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5145 PrintEditorElementList();
5149 else if (strEqual(command, "print helpanim.conf"))
5151 printf("# You can configure different element help animations here.\n");
5152 printf("# (The entries below are default and therefore commented out.)\n");
5155 for (i = 0; helpanim_config[i].token != NULL; i++)
5157 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
5158 helpanim_config[i].value));
5160 if (strEqual(helpanim_config[i].token, "end"))
5166 else if (strEqual(command, "print helptext.conf"))
5168 printf("# You can configure different element help text here.\n");
5169 printf("# (The entries below are default and therefore commented out.)\n");
5172 for (i = 0; helptext_config[i].token != NULL; i++)
5173 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
5174 helptext_config[i].value));
5178 else if (strPrefix(command, "dump level "))
5180 char *filename = &command[11];
5182 if (!fileExists(filename))
5183 Error(ERR_EXIT, "cannot open file '%s'", filename);
5185 LoadLevelFromFilename(&level, filename);
5190 else if (strPrefix(command, "dump tape "))
5192 char *filename = &command[10];
5194 if (!fileExists(filename))
5195 Error(ERR_EXIT, "cannot open file '%s'", filename);
5197 LoadTapeFromFilename(filename);
5202 else if (strPrefix(command, "autoplay "))
5204 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
5206 while (*str_ptr != '\0') /* continue parsing string */
5208 /* cut leading whitespace from string, replace it by string terminator */
5209 while (*str_ptr == ' ' || *str_ptr == '\t')
5212 if (*str_ptr == '\0') /* end of string reached */
5215 if (global.autoplay_leveldir == NULL) /* read level set string */
5217 global.autoplay_leveldir = str_ptr;
5218 global.autoplay_all = TRUE; /* default: play all tapes */
5220 for (i = 0; i < MAX_TAPES_PER_SET; i++)
5221 global.autoplay_level[i] = FALSE;
5223 else /* read level number string */
5225 int level_nr = atoi(str_ptr); /* get level_nr value */
5227 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5228 global.autoplay_level[level_nr] = TRUE;
5230 global.autoplay_all = FALSE;
5233 /* advance string pointer to the next whitespace (or end of string) */
5234 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5238 else if (strPrefix(command, "convert "))
5240 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
5241 char *str_ptr = strchr(str_copy, ' ');
5243 global.convert_leveldir = str_copy;
5244 global.convert_level_nr = -1;
5246 if (str_ptr != NULL) /* level number follows */
5248 *str_ptr++ = '\0'; /* terminate leveldir string */
5249 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
5252 else if (strPrefix(command, "create images "))
5254 #if defined(TARGET_SDL)
5255 global.create_images_dir = getStringCopy(&command[14]);
5257 if (access(global.create_images_dir, W_OK) != 0)
5258 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
5259 global.create_images_dir);
5261 Error(ERR_EXIT, "command only available for SDL target");
5266 #if defined(TARGET_SDL2)
5267 else if (strEqual(command, "SDL_ListModes"))
5269 SDL_Init(SDL_INIT_VIDEO);
5271 int num_displays = SDL_GetNumVideoDisplays();
5273 // check if there are any displays available
5274 if (num_displays < 0)
5276 printf("No displays available: %s\n", SDL_GetError());
5281 for (i = 0; i < num_displays; i++)
5283 int num_modes = SDL_GetNumDisplayModes(i);
5286 printf("Available display modes for display %d:\n", i);
5288 // check if there are any display modes available for this display
5291 printf("No display modes available for display %d: %s\n",
5297 for (j = 0; j < num_modes; j++)
5299 SDL_DisplayMode mode;
5301 if (SDL_GetDisplayMode(i, j, &mode) < 0)
5303 printf("Cannot get display mode %d for display %d: %s\n",
5304 j, i, SDL_GetError());
5309 printf("- %d x %d\n", mode.w, mode.h);
5315 #elif defined(TARGET_SDL)
5316 else if (strEqual(command, "SDL_ListModes"))
5321 SDL_Init(SDL_INIT_VIDEO);
5323 /* get available fullscreen/hardware modes */
5324 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
5326 /* check if there are any modes available */
5329 printf("No modes available!\n");
5334 /* check if our resolution is restricted */
5335 if (modes == (SDL_Rect **)-1)
5337 printf("All resolutions available.\n");
5341 printf("Available display modes:\n");
5343 for (i = 0; modes[i]; i++)
5344 printf("- %d x %d\n", modes[i]->w, modes[i]->h);
5354 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
5358 static void InitSetup()
5360 LoadSetup(); /* global setup info */
5362 /* set some options from setup file */
5364 if (setup.options.verbose)
5365 options.verbose = TRUE;
5368 static void InitGameInfo()
5370 game.restart_level = FALSE;
5373 static void InitPlayerInfo()
5377 /* choose default local player */
5378 local_player = &stored_player[0];
5380 for (i = 0; i < MAX_PLAYERS; i++)
5381 stored_player[i].connected = FALSE;
5383 local_player->connected = TRUE;
5386 static void InitArtworkInfo()
5391 static char *get_string_in_brackets(char *string)
5393 char *string_in_brackets = checked_malloc(strlen(string) + 3);
5395 sprintf(string_in_brackets, "[%s]", string);
5397 return string_in_brackets;
5400 static char *get_level_id_suffix(int id_nr)
5402 char *id_suffix = checked_malloc(1 + 3 + 1);
5404 if (id_nr < 0 || id_nr > 999)
5407 sprintf(id_suffix, ".%03d", id_nr);
5413 static char *get_element_class_token(int element)
5415 char *element_class_name = element_info[element].class_name;
5416 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
5418 sprintf(element_class_token, "[%s]", element_class_name);
5420 return element_class_token;
5423 static char *get_action_class_token(int action)
5425 char *action_class_name = &element_action_info[action].suffix[1];
5426 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
5428 sprintf(action_class_token, "[%s]", action_class_name);
5430 return action_class_token;
5434 static void InitArtworkConfig()
5436 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
5437 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
5438 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
5439 static char *action_id_suffix[NUM_ACTIONS + 1];
5440 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5441 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5442 static char *level_id_suffix[MAX_LEVELS + 1];
5443 static char *dummy[1] = { NULL };
5444 static char *ignore_generic_tokens[] =
5450 static char **ignore_image_tokens;
5451 static char **ignore_sound_tokens;
5452 static char **ignore_music_tokens;
5453 int num_ignore_generic_tokens;
5454 int num_ignore_image_tokens;
5455 int num_ignore_sound_tokens;
5456 int num_ignore_music_tokens;
5459 /* dynamically determine list of generic tokens to be ignored */
5460 num_ignore_generic_tokens = 0;
5461 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5462 num_ignore_generic_tokens++;
5464 /* dynamically determine list of image tokens to be ignored */
5465 num_ignore_image_tokens = num_ignore_generic_tokens;
5466 for (i = 0; image_config_vars[i].token != NULL; i++)
5467 num_ignore_image_tokens++;
5468 ignore_image_tokens =
5469 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5470 for (i = 0; i < num_ignore_generic_tokens; i++)
5471 ignore_image_tokens[i] = ignore_generic_tokens[i];
5472 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5473 ignore_image_tokens[num_ignore_generic_tokens + i] =
5474 image_config_vars[i].token;
5475 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5477 /* dynamically determine list of sound tokens to be ignored */
5478 num_ignore_sound_tokens = num_ignore_generic_tokens;
5479 ignore_sound_tokens =
5480 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5481 for (i = 0; i < num_ignore_generic_tokens; i++)
5482 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5483 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5485 /* dynamically determine list of music tokens to be ignored */
5486 num_ignore_music_tokens = num_ignore_generic_tokens;
5487 ignore_music_tokens =
5488 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5489 for (i = 0; i < num_ignore_generic_tokens; i++)
5490 ignore_music_tokens[i] = ignore_generic_tokens[i];
5491 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5493 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5494 image_id_prefix[i] = element_info[i].token_name;
5495 for (i = 0; i < NUM_FONTS; i++)
5496 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5497 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
5499 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5500 sound_id_prefix[i] = element_info[i].token_name;
5501 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5502 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5503 get_string_in_brackets(element_info[i].class_name);
5504 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
5506 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5507 music_id_prefix[i] = music_prefix_info[i].prefix;
5508 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
5510 for (i = 0; i < NUM_ACTIONS; i++)
5511 action_id_suffix[i] = element_action_info[i].suffix;
5512 action_id_suffix[NUM_ACTIONS] = NULL;
5514 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5515 direction_id_suffix[i] = element_direction_info[i].suffix;
5516 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5518 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5519 special_id_suffix[i] = special_suffix_info[i].suffix;
5520 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5522 for (i = 0; i < MAX_LEVELS; i++)
5523 level_id_suffix[i] = get_level_id_suffix(i);
5524 level_id_suffix[MAX_LEVELS] = NULL;
5526 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5527 image_id_prefix, action_id_suffix, direction_id_suffix,
5528 special_id_suffix, ignore_image_tokens);
5529 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5530 sound_id_prefix, action_id_suffix, dummy,
5531 special_id_suffix, ignore_sound_tokens);
5532 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5533 music_id_prefix, special_id_suffix, level_id_suffix,
5534 dummy, ignore_music_tokens);
5537 static void InitMixer()
5544 void InitGfxBuffers()
5546 /* create additional image buffers for double-buffering and cross-fading */
5547 ReCreateBitmap(&bitmap_db_store, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5548 ReCreateBitmap(&bitmap_db_cross, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5549 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE, DEFAULT_DEPTH);
5550 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE, DEFAULT_DEPTH);
5551 ReCreateBitmap(&bitmap_db_door, 3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
5552 ReCreateBitmap(&bitmap_db_toons, FULL_SXSIZE, FULL_SYSIZE, DEFAULT_DEPTH);
5554 /* initialize screen properties */
5555 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5556 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5558 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5559 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5560 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5561 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5562 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5563 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5565 InitGfxBuffers_EM();
5566 InitGfxBuffers_SP();
5571 struct GraphicInfo *graphic_info_last = graphic_info;
5572 char *filename_font_initial = NULL;
5573 char *filename_anim_initial = NULL;
5574 Bitmap *bitmap_font_initial = NULL;
5578 /* determine settings for initial font (for displaying startup messages) */
5579 for (i = 0; image_config[i].token != NULL; i++)
5581 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5583 char font_token[128];
5586 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5587 len_font_token = strlen(font_token);
5589 if (strEqual(image_config[i].token, font_token))
5590 filename_font_initial = image_config[i].value;
5591 else if (strlen(image_config[i].token) > len_font_token &&
5592 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5594 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5595 font_initial[j].src_x = atoi(image_config[i].value);
5596 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5597 font_initial[j].src_y = atoi(image_config[i].value);
5598 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5599 font_initial[j].width = atoi(image_config[i].value);
5600 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5601 font_initial[j].height = atoi(image_config[i].value);
5606 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5608 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5609 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5612 if (filename_font_initial == NULL) /* should not happen */
5613 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5616 InitGfxCustomArtworkInfo();
5618 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5620 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5621 font_initial[j].bitmap = bitmap_font_initial;
5623 InitFontGraphicInfo();
5625 font_height = getFontHeight(FC_RED);
5628 DrawInitTextAlways(getWindowTitleString(), 20, FC_YELLOW);
5630 DrawInitTextAlways(getProgramInitString(), 20, FC_YELLOW);
5632 DrawInitTextAlways(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
5633 DrawInitTextAlways(PROGRAM_WEBSITE_STRING, WIN_YSIZE - 20 - font_height,
5636 DrawInitTextAlways("Loading graphics", 120, FC_GREEN);
5640 /* initialize busy animation with default values */
5641 int parameter[NUM_GFX_ARGS];
5642 for (i = 0; i < NUM_GFX_ARGS; i++)
5643 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5644 image_config_suffix[i].token,
5645 image_config_suffix[i].type);
5647 for (i = 0; i < NUM_GFX_ARGS; i++)
5648 printf("::: '%s' => %d\n", image_config_suffix[i].token, parameter[i]);
5652 /* determine settings for busy animation (when displaying startup messages) */
5653 for (i = 0; image_config[i].token != NULL; i++)
5655 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5656 int len_anim_token = strlen(anim_token);
5658 if (strEqual(image_config[i].token, anim_token))
5659 filename_anim_initial = image_config[i].value;
5660 else if (strlen(image_config[i].token) > len_anim_token &&
5661 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5664 for (j = 0; image_config_suffix[j].token != NULL; j++)
5666 if (strEqual(&image_config[i].token[len_anim_token],
5667 image_config_suffix[j].token))
5669 get_graphic_parameter_value(image_config[i].value,
5670 image_config_suffix[j].token,
5671 image_config_suffix[j].type);
5674 if (strEqual(&image_config[i].token[len_anim_token], ".x"))
5675 anim_initial.src_x = atoi(image_config[i].value);
5676 else if (strEqual(&image_config[i].token[len_anim_token], ".y"))
5677 anim_initial.src_y = atoi(image_config[i].value);
5678 else if (strEqual(&image_config[i].token[len_anim_token], ".width"))
5679 anim_initial.width = atoi(image_config[i].value);
5680 else if (strEqual(&image_config[i].token[len_anim_token], ".height"))
5681 anim_initial.height = atoi(image_config[i].value);
5682 else if (strEqual(&image_config[i].token[len_anim_token], ".frames"))
5683 anim_initial.anim_frames = atoi(image_config[i].value);
5684 else if (strEqual(&image_config[i].token[len_anim_token],
5685 ".frames_per_line"))
5686 anim_initial.anim_frames_per_line = atoi(image_config[i].value);
5687 else if (strEqual(&image_config[i].token[len_anim_token], ".delay"))
5688 anim_initial.anim_delay = atoi(image_config[i].value);
5693 #if defined(CREATE_SPECIAL_EDITION_RND_JUE)
5694 filename_anim_initial = "loading.pcx";
5696 parameter[GFX_ARG_X] = 0;
5697 parameter[GFX_ARG_Y] = 0;
5698 parameter[GFX_ARG_WIDTH] = 128;
5699 parameter[GFX_ARG_HEIGHT] = 40;
5700 parameter[GFX_ARG_FRAMES] = 32;
5701 parameter[GFX_ARG_DELAY] = 4;
5702 parameter[GFX_ARG_FRAMES_PER_LINE] = ARG_UNDEFINED_VALUE;
5705 if (filename_anim_initial == NULL) /* should not happen */
5706 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5708 anim_initial.bitmap = LoadCustomImage(filename_anim_initial);
5710 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
5712 set_graphic_parameters_ext(0, parameter, anim_initial.bitmap);
5715 printf("::: INIT_GFX: anim_frames_per_line == %d [%d / %d] [%d, %d]\n",
5716 graphic_info[0].anim_frames_per_line,
5717 get_scaled_graphic_width(0),
5718 graphic_info[0].width,
5719 getOriginalImageWidthFromImageID(0),
5720 graphic_info[0].scale_up_factor);
5723 graphic_info = graphic_info_last;
5725 init.busy.width = anim_initial.width;
5726 init.busy.height = anim_initial.height;
5728 InitMenuDesignSettings_Static();
5729 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5731 /* use copy of busy animation to prevent change while reloading artwork */
5736 void RedrawBackground()
5738 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
5739 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
5741 redraw_mask = REDRAW_ALL;
5744 void InitGfxBackground()
5748 fieldbuffer = bitmap_db_field;
5749 SetDrawtoField(DRAW_BACKBUFFER);
5752 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5756 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
5757 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
5760 for (x = 0; x < MAX_BUF_XSIZE; x++)
5761 for (y = 0; y < MAX_BUF_YSIZE; y++)
5764 redraw_mask = REDRAW_ALL;
5767 static void InitLevelInfo()
5769 LoadLevelInfo(); /* global level info */
5770 LoadLevelSetup_LastSeries(); /* last played series info */
5771 LoadLevelSetup_SeriesInfo(); /* last played level info */
5774 static void InitLevelArtworkInfo()
5776 LoadLevelArtworkInfo();
5779 static void InitImages()
5781 print_timestamp_init("InitImages");
5784 printf("::: leveldir_current->identifier == '%s'\n",
5785 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5786 printf("::: leveldir_current->graphics_path == '%s'\n",
5787 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5788 printf("::: leveldir_current->graphics_set == '%s'\n",
5789 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5790 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5791 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5794 setLevelArtworkDir(artwork.gfx_first);
5797 printf("::: leveldir_current->identifier == '%s'\n",
5798 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5799 printf("::: leveldir_current->graphics_path == '%s'\n",
5800 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5801 printf("::: leveldir_current->graphics_set == '%s'\n",
5802 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5803 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5804 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5808 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5809 leveldir_current->identifier,
5810 artwork.gfx_current_identifier,
5811 artwork.gfx_current->identifier,
5812 leveldir_current->graphics_set,
5813 leveldir_current->graphics_path);
5816 UPDATE_BUSY_STATE();
5818 ReloadCustomImages();
5819 print_timestamp_time("ReloadCustomImages");
5821 UPDATE_BUSY_STATE();
5823 LoadCustomElementDescriptions();
5824 print_timestamp_time("LoadCustomElementDescriptions");
5826 UPDATE_BUSY_STATE();
5828 LoadMenuDesignSettings();
5829 print_timestamp_time("LoadMenuDesignSettings");
5831 UPDATE_BUSY_STATE();
5833 ReinitializeGraphics();
5834 print_timestamp_time("ReinitializeGraphics");
5836 UPDATE_BUSY_STATE();
5838 print_timestamp_done("InitImages");
5841 static void InitSound(char *identifier)
5843 print_timestamp_init("InitSound");
5845 if (identifier == NULL)
5846 identifier = artwork.snd_current->identifier;
5848 /* set artwork path to send it to the sound server process */
5849 setLevelArtworkDir(artwork.snd_first);
5851 InitReloadCustomSounds(identifier);
5852 print_timestamp_time("InitReloadCustomSounds");
5854 ReinitializeSounds();
5855 print_timestamp_time("ReinitializeSounds");
5857 print_timestamp_done("InitSound");
5860 static void InitMusic(char *identifier)
5862 print_timestamp_init("InitMusic");
5864 if (identifier == NULL)
5865 identifier = artwork.mus_current->identifier;
5867 /* set artwork path to send it to the sound server process */
5868 setLevelArtworkDir(artwork.mus_first);
5870 InitReloadCustomMusic(identifier);
5871 print_timestamp_time("InitReloadCustomMusic");
5873 ReinitializeMusic();
5874 print_timestamp_time("ReinitializeMusic");
5876 print_timestamp_done("InitMusic");
5879 void InitNetworkServer()
5881 #if defined(NETWORK_AVALIABLE)
5885 if (!options.network)
5888 #if defined(NETWORK_AVALIABLE)
5889 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5891 if (!ConnectToServer(options.server_host, options.server_port))
5892 Error(ERR_EXIT, "cannot connect to network game server");
5894 SendToServer_PlayerName(setup.player_name);
5895 SendToServer_ProtocolVersion();
5898 SendToServer_NrWanted(nr_wanted);
5902 static boolean CheckArtworkConfigForCustomElements(char *filename)
5904 SetupFileHash *setup_file_hash;
5905 boolean redefined_ce_found = FALSE;
5907 /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */
5909 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5911 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5913 char *token = HASH_ITERATION_TOKEN(itr);
5915 if (strPrefix(token, "custom_"))
5917 redefined_ce_found = TRUE;
5922 END_HASH_ITERATION(setup_file_hash, itr)
5924 freeSetupFileHash(setup_file_hash);
5927 return redefined_ce_found;
5930 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5932 char *filename_base, *filename_local;
5933 boolean redefined_ce_found = FALSE;
5935 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5938 printf("::: leveldir_current->identifier == '%s'\n",
5939 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5940 printf("::: leveldir_current->graphics_path == '%s'\n",
5941 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5942 printf("::: leveldir_current->graphics_set == '%s'\n",
5943 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5944 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5945 leveldir_current == NULL ? "[NULL]" :
5946 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5949 /* first look for special artwork configured in level series config */
5950 filename_base = getCustomArtworkLevelConfigFilename(type);
5953 printf("::: filename_base == '%s'\n", filename_base);
5956 if (fileExists(filename_base))
5957 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5959 filename_local = getCustomArtworkConfigFilename(type);
5962 printf("::: filename_local == '%s'\n", filename_local);
5965 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5966 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5969 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5972 return redefined_ce_found;
5975 static void InitOverrideArtwork()
5977 boolean redefined_ce_found = FALSE;
5979 /* to check if this level set redefines any CEs, do not use overriding */
5980 gfx.override_level_graphics = FALSE;
5981 gfx.override_level_sounds = FALSE;
5982 gfx.override_level_music = FALSE;
5984 /* now check if this level set has definitions for custom elements */
5985 if (setup.override_level_graphics == AUTO ||
5986 setup.override_level_sounds == AUTO ||
5987 setup.override_level_music == AUTO)
5988 redefined_ce_found =
5989 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5990 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5991 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5994 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5997 if (redefined_ce_found)
5999 /* this level set has CE definitions: change "AUTO" to "FALSE" */
6000 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
6001 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
6002 gfx.override_level_music = (setup.override_level_music == TRUE);
6006 /* this level set has no CE definitions: change "AUTO" to "TRUE" */
6007 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
6008 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
6009 gfx.override_level_music = (setup.override_level_music != FALSE);
6013 printf("::: => %d, %d, %d\n",
6014 gfx.override_level_graphics,
6015 gfx.override_level_sounds,
6016 gfx.override_level_music);
6020 static char *getNewArtworkIdentifier(int type)
6022 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
6023 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
6024 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
6025 static boolean initialized[3] = { FALSE, FALSE, FALSE };
6026 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
6028 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
6030 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
6032 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
6033 char *leveldir_identifier = leveldir_current->identifier;
6035 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
6036 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
6038 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
6040 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
6041 char *artwork_current_identifier;
6042 char *artwork_new_identifier = NULL; /* default: nothing has changed */
6044 /* leveldir_current may be invalid (level group, parent link) */
6045 if (!validLevelSeries(leveldir_current))
6048 /* 1st step: determine artwork set to be activated in descending order:
6049 --------------------------------------------------------------------
6050 1. setup artwork (when configured to override everything else)
6051 2. artwork set configured in "levelinfo.conf" of current level set
6052 (artwork in level directory will have priority when loading later)
6053 3. artwork in level directory (stored in artwork sub-directory)
6054 4. setup artwork (currently configured in setup menu) */
6056 if (setup_override_artwork)
6057 artwork_current_identifier = setup_artwork_set;
6058 else if (leveldir_artwork_set != NULL)
6059 artwork_current_identifier = leveldir_artwork_set;
6060 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
6061 artwork_current_identifier = leveldir_identifier;
6063 artwork_current_identifier = setup_artwork_set;
6066 /* 2nd step: check if it is really needed to reload artwork set
6067 ------------------------------------------------------------ */
6070 if (type == ARTWORK_TYPE_GRAPHICS)
6071 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
6072 artwork_new_identifier,
6073 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
6074 artwork_current_identifier,
6075 leveldir_current->graphics_set,
6076 leveldir_current->identifier);
6079 /* ---------- reload if level set and also artwork set has changed ------- */
6080 if (leveldir_current_identifier[type] != leveldir_identifier &&
6081 (last_has_level_artwork_set[type] || has_level_artwork_set))
6082 artwork_new_identifier = artwork_current_identifier;
6084 leveldir_current_identifier[type] = leveldir_identifier;
6085 last_has_level_artwork_set[type] = has_level_artwork_set;
6088 if (type == ARTWORK_TYPE_GRAPHICS)
6089 printf("::: 1: '%s'\n", artwork_new_identifier);
6092 /* ---------- reload if "override artwork" setting has changed ----------- */
6093 if (last_override_level_artwork[type] != setup_override_artwork)
6094 artwork_new_identifier = artwork_current_identifier;
6096 last_override_level_artwork[type] = setup_override_artwork;
6099 if (type == ARTWORK_TYPE_GRAPHICS)
6100 printf("::: 2: '%s'\n", artwork_new_identifier);
6103 /* ---------- reload if current artwork identifier has changed ----------- */
6104 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
6105 artwork_current_identifier))
6106 artwork_new_identifier = artwork_current_identifier;
6108 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
6111 if (type == ARTWORK_TYPE_GRAPHICS)
6112 printf("::: 3: '%s'\n", artwork_new_identifier);
6115 /* ---------- do not reload directly after starting ---------------------- */
6116 if (!initialized[type])
6117 artwork_new_identifier = NULL;
6119 initialized[type] = TRUE;
6122 if (type == ARTWORK_TYPE_GRAPHICS)
6123 printf("::: 4: '%s'\n", artwork_new_identifier);
6127 if (type == ARTWORK_TYPE_GRAPHICS)
6128 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
6129 artwork.gfx_current_identifier, artwork_current_identifier,
6130 artwork.gfx_current->identifier, leveldir_current->graphics_set,
6131 artwork_new_identifier);
6134 return artwork_new_identifier;
6137 void ReloadCustomArtwork(int force_reload)
6139 int last_game_status = game_status; /* save current game status */
6140 char *gfx_new_identifier;
6141 char *snd_new_identifier;
6142 char *mus_new_identifier;
6143 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
6144 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
6145 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
6146 boolean reload_needed;
6148 InitOverrideArtwork();
6150 force_reload_gfx |= AdjustGraphicsForEMC();
6152 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
6153 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
6154 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
6156 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
6157 snd_new_identifier != NULL || force_reload_snd ||
6158 mus_new_identifier != NULL || force_reload_mus);
6163 print_timestamp_init("ReloadCustomArtwork");
6165 game_status = GAME_MODE_LOADING;
6167 FadeOut(REDRAW_ALL);
6170 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6172 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
6174 print_timestamp_time("ClearRectangle");
6177 printf("::: fading in ... %d\n", fading.fade_mode);
6181 printf("::: done\n");
6184 if (gfx_new_identifier != NULL || force_reload_gfx)
6187 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
6188 artwork.gfx_current_identifier,
6190 artwork.gfx_current->identifier,
6191 leveldir_current->graphics_set);
6195 print_timestamp_time("InitImages");
6198 if (snd_new_identifier != NULL || force_reload_snd)
6200 InitSound(snd_new_identifier);
6201 print_timestamp_time("InitSound");
6204 if (mus_new_identifier != NULL || force_reload_mus)
6206 InitMusic(mus_new_identifier);
6207 print_timestamp_time("InitMusic");
6210 game_status = last_game_status; /* restore current game status */
6212 init_last = init; /* switch to new busy animation */
6215 printf("::: ----------------DELAY 1 ...\n");
6220 printf("::: FadeOut @ ReloadCustomArtwork ...\n");
6222 FadeOut(REDRAW_ALL);
6224 printf("::: FadeOut @ ReloadCustomArtwork done\n");
6229 /* force redraw of (open or closed) door graphics */
6230 SetDoorState(DOOR_OPEN_ALL);
6231 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
6236 FadeSetEnterScreen();
6237 FadeSkipNextFadeOut();
6238 // FadeSetDisabled();
6243 fading = fading_none;
6248 redraw_mask = REDRAW_ALL;
6251 print_timestamp_done("ReloadCustomArtwork");
6253 LimitScreenUpdates(FALSE);
6256 void KeyboardAutoRepeatOffUnlessAutoplay()
6258 if (global.autoplay_leveldir == NULL)
6259 KeyboardAutoRepeatOff();
6262 void DisplayExitMessage(char *format, va_list ap)
6264 // check if draw buffer and fonts for exit message are already available
6265 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
6268 int font_1 = FC_RED;
6269 int font_2 = FC_YELLOW;
6270 int font_3 = FC_BLUE;
6271 int font_width = getFontWidth(font_2);
6272 int font_height = getFontHeight(font_2);
6275 int sxsize = WIN_XSIZE - 2 * sx;
6276 int sysize = WIN_YSIZE - 2 * sy;
6277 int line_length = sxsize / font_width;
6278 int max_lines = sysize / font_height;
6279 int num_lines_printed;
6283 gfx.sxsize = sxsize;
6284 gfx.sysize = sysize;
6288 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6290 DrawTextSCentered(sy, font_1, "Fatal error:");
6291 sy += 3 * font_height;;
6294 DrawTextBufferVA(sx, sy, format, ap, font_2,
6295 line_length, line_length, max_lines,
6296 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6297 sy += (num_lines_printed + 3) * font_height;
6299 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
6300 sy += 3 * font_height;
6303 DrawTextBuffer(sx, sy, program.error_filename, font_2,
6304 line_length, line_length, max_lines,
6305 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6307 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
6309 redraw_mask = REDRAW_ALL;
6313 /* deactivate toons on error message screen */
6314 setup.toons = FALSE;
6316 WaitForEventToContinue();
6320 /* ========================================================================= */
6322 /* ========================================================================= */
6326 print_timestamp_init("OpenAll");
6328 game_status = GAME_MODE_LOADING;
6334 InitGlobal(); /* initialize some global variables */
6336 print_timestamp_time("[init global stuff]");
6338 if (options.execute_command)
6339 Execute_Command(options.execute_command);
6341 if (options.serveronly)
6343 #if defined(PLATFORM_UNIX)
6344 NetworkServer(options.server_port, options.serveronly);
6346 Error(ERR_WARN, "networking only supported in Unix version");
6349 exit(0); /* never reached, server loops forever */
6354 print_timestamp_time("[init setup/config stuff (1)]");
6357 print_timestamp_time("[init setup/config stuff (2)]");
6359 print_timestamp_time("[init setup/config stuff (3)]");
6360 InitArtworkInfo(); /* needed before loading gfx, sound & music */
6361 print_timestamp_time("[init setup/config stuff (4)]");
6362 InitArtworkConfig(); /* needed before forking sound child process */
6363 print_timestamp_time("[init setup/config stuff (5)]");
6365 print_timestamp_time("[init setup/config stuff (6)]");
6371 InitRND(NEW_RANDOMIZE);
6372 InitSimpleRandom(NEW_RANDOMIZE);
6376 print_timestamp_time("[init setup/config stuff]");
6379 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
6381 InitEventFilter(FilterEvents);
6383 print_timestamp_time("[init video stuff]");
6385 InitElementPropertiesStatic();
6386 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
6387 InitElementPropertiesGfxElement();
6389 print_timestamp_time("[init element properties stuff]");
6393 print_timestamp_time("InitGfx");
6396 print_timestamp_time("InitLevelInfo");
6398 InitLevelArtworkInfo();
6399 print_timestamp_time("InitLevelArtworkInfo");
6401 InitOverrideArtwork(); /* needs to know current level directory */
6402 print_timestamp_time("InitOverrideArtwork");
6404 InitImages(); /* needs to know current level directory */
6405 print_timestamp_time("InitImages");
6407 InitSound(NULL); /* needs to know current level directory */
6408 print_timestamp_time("InitSound");
6410 InitMusic(NULL); /* needs to know current level directory */
6411 print_timestamp_time("InitMusic");
6413 InitGfxBackground();
6423 if (global.autoplay_leveldir)
6428 else if (global.convert_leveldir)
6433 else if (global.create_images_dir)
6435 CreateLevelSketchImages();
6439 game_status = GAME_MODE_MAIN;
6442 FadeSetEnterScreen();
6443 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
6444 FadeSkipNextFadeOut();
6445 // FadeSetDisabled();
6447 fading = fading_none;
6450 print_timestamp_time("[post-artwork]");
6452 print_timestamp_done("OpenAll");
6456 InitNetworkServer();
6459 Error(ERR_DEBUG, "::: SDL_GetBasePath() == '%s'",
6461 Error(ERR_DEBUG, "::: SDL_GetPrefPath() == '%s'",
6462 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
6463 #if defined(PLATFORM_ANDROID)
6464 Error(ERR_DEBUG, "::: SDL_AndroidGetInternalStoragePath() == '%s'",
6465 SDL_AndroidGetInternalStoragePath());
6466 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStoragePath() == '%s'",
6467 SDL_AndroidGetExternalStoragePath());
6468 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStorageState() == '%s'",
6469 (SDL_AndroidGetExternalStorageState() ==
6470 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "read" :
6471 SDL_AndroidGetExternalStorageState() ==
6472 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "write" : "not available"));
6477 void CloseAllAndExit(int exit_value)
6482 CloseAudio(); /* called after freeing sounds (needed for SDL) */
6494 #if defined(TARGET_SDL)
6495 #if defined(TARGET_SDL2)
6497 // set a flag to tell the network server thread to quit and wait for it
6498 // using SDL_WaitThread()
6500 if (network_server) /* terminate network server */
6501 SDL_KillThread(server_thread);
6505 CloseVideoDisplay();
6506 ClosePlatformDependentStuff();
6508 if (exit_value != 0)
6510 /* fall back to default level set (current set may have caused an error) */
6511 SaveLevelSetup_LastSeries_Deactivate();
6513 /* tell user where to find error log file which may contain more details */
6514 // (error notification now directly displayed on screen inside R'n'D
6515 // NotifyUserAboutErrorFile(); /* currently only works for Windows */