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,
1774 IMG_BACKGROUND_REQUEST,
1777 IMG_BACKGROUND_TITLE_INITIAL,
1778 IMG_BACKGROUND_TITLE,
1779 IMG_BACKGROUND_MAIN,
1780 IMG_BACKGROUND_LEVELS,
1781 IMG_BACKGROUND_LEVELNR,
1782 IMG_BACKGROUND_SCORES,
1783 IMG_BACKGROUND_EDITOR,
1784 IMG_BACKGROUND_INFO,
1785 IMG_BACKGROUND_INFO_ELEMENTS,
1786 IMG_BACKGROUND_INFO_MUSIC,
1787 IMG_BACKGROUND_INFO_CREDITS,
1788 IMG_BACKGROUND_INFO_PROGRAM,
1789 IMG_BACKGROUND_INFO_VERSION,
1790 IMG_BACKGROUND_INFO_LEVELSET,
1791 IMG_BACKGROUND_SETUP,
1792 IMG_BACKGROUND_PLAYING,
1793 IMG_BACKGROUND_DOOR,
1794 IMG_BACKGROUND_TAPE,
1795 IMG_BACKGROUND_PANEL,
1796 IMG_BACKGROUND_PALETTE,
1797 IMG_BACKGROUND_TOOLBOX,
1799 IMG_TITLESCREEN_INITIAL_1,
1800 IMG_TITLESCREEN_INITIAL_2,
1801 IMG_TITLESCREEN_INITIAL_3,
1802 IMG_TITLESCREEN_INITIAL_4,
1803 IMG_TITLESCREEN_INITIAL_5,
1810 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1,
1811 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2,
1812 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3,
1813 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4,
1814 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5,
1815 IMG_BACKGROUND_TITLEMESSAGE_1,
1816 IMG_BACKGROUND_TITLEMESSAGE_2,
1817 IMG_BACKGROUND_TITLEMESSAGE_3,
1818 IMG_BACKGROUND_TITLEMESSAGE_4,
1819 IMG_BACKGROUND_TITLEMESSAGE_5,
1824 checked_free(graphic_info);
1826 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1829 /* initialize "use_image_size" flag with default value */
1830 for (i = 0; i < num_images; i++)
1831 graphic_info[i].use_image_size = FALSE;
1833 /* initialize "use_image_size" flag from static configuration above */
1834 for (i = 0; full_size_graphics[i] != -1; i++)
1835 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1838 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1839 if (clipmasks_initialized)
1841 for (i = 0; i < num_images; i++)
1843 if (graphic_info[i].clip_mask)
1844 XFreePixmap(display, graphic_info[i].clip_mask);
1845 if (graphic_info[i].clip_gc)
1846 XFreeGC(display, graphic_info[i].clip_gc);
1848 graphic_info[i].clip_mask = None;
1849 graphic_info[i].clip_gc = None;
1854 /* first set all graphic paramaters ... */
1855 for (i = 0; i < num_images; i++)
1856 set_graphic_parameters(i);
1858 /* ... then copy these parameters for cloned graphics */
1859 for (i = 0; i < num_images; i++)
1860 if (graphic_info[i].clone_from != -1)
1861 set_cloned_graphic_parameters(i);
1863 for (i = 0; i < num_images; i++)
1868 int first_frame, last_frame;
1869 int src_bitmap_width, src_bitmap_height;
1871 /* now check if no animation frames are outside of the loaded image */
1873 if (graphic_info[i].bitmap == NULL)
1874 continue; /* skip check for optional images that are undefined */
1876 /* get image size (this can differ from the standard element tile size!) */
1877 width = graphic_info[i].width;
1878 height = graphic_info[i].height;
1880 /* get final bitmap size (with scaling, but without small images) */
1881 src_bitmap_width = graphic_info[i].src_image_width;
1882 src_bitmap_height = graphic_info[i].src_image_height;
1884 /* check if first animation frame is inside specified bitmap */
1887 getFixedGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1890 /* this avoids calculating wrong start position for out-of-bounds frame */
1891 src_x = graphic_info[i].src_x;
1892 src_y = graphic_info[i].src_y;
1895 if (src_x < 0 || src_y < 0 ||
1896 src_x + width > src_bitmap_width ||
1897 src_y + height > src_bitmap_height)
1899 Error(ERR_INFO_LINE, "-");
1900 Error(ERR_INFO, "warning: error found in config file:");
1901 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1902 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1903 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1905 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1906 src_x, src_y, src_bitmap_width, src_bitmap_height);
1907 Error(ERR_INFO, "custom graphic rejected for this element/action");
1909 if (i == fallback_graphic)
1910 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1912 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1913 Error(ERR_INFO_LINE, "-");
1915 graphic_info[i] = graphic_info[fallback_graphic];
1918 /* check if last animation frame is inside specified bitmap */
1920 last_frame = graphic_info[i].anim_frames - 1;
1921 getFixedGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1923 if (src_x < 0 || src_y < 0 ||
1924 src_x + width > src_bitmap_width ||
1925 src_y + height > src_bitmap_height)
1927 Error(ERR_INFO_LINE, "-");
1928 Error(ERR_INFO, "warning: error found in config file:");
1929 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1930 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1931 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1933 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1934 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1935 Error(ERR_INFO, "::: %d, %d", width, height);
1936 Error(ERR_INFO, "custom graphic rejected for this element/action");
1938 if (i == fallback_graphic)
1939 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1941 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1942 Error(ERR_INFO_LINE, "-");
1944 graphic_info[i] = graphic_info[fallback_graphic];
1947 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1948 /* currently we only need a tile clip mask from the first frame */
1949 getFixedGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1951 if (copy_clipmask_gc == None)
1953 clip_gc_values.graphics_exposures = False;
1954 clip_gc_valuemask = GCGraphicsExposures;
1955 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
1956 clip_gc_valuemask, &clip_gc_values);
1959 graphic_info[i].clip_mask =
1960 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
1962 src_pixmap = src_bitmap->clip_mask;
1963 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
1964 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
1966 clip_gc_values.graphics_exposures = False;
1967 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
1968 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
1970 graphic_info[i].clip_gc =
1971 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
1975 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1976 if (copy_clipmask_gc)
1977 XFreeGC(display, copy_clipmask_gc);
1979 clipmasks_initialized = TRUE;
1983 static void InitGraphicCompatibilityInfo()
1985 struct FileInfo *fi_global_door =
1986 getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1987 int num_images = getImageListSize();
1990 /* the following compatibility handling is needed for the following case:
1991 versions up to 3.3.0.0 used one large bitmap "global.door" for various
1992 graphics mainly used for door and panel graphics, like editor, tape and
1993 in-game buttons with hard-coded bitmap positions and button sizes; as
1994 these graphics now have individual definitions, redefining "global.door"
1995 to change all these graphics at once like before does not work anymore
1996 (because all those individual definitions still have their default values);
1997 to solve this, remap all those individual definitions that are not
1998 redefined to the new bitmap of "global.door" if it was redefined */
2000 /* special compatibility handling if image "global.door" was redefined */
2001 if (fi_global_door->redefined)
2003 for (i = 0; i < num_images; i++)
2005 struct FileInfo *fi = getImageListEntryFromImageID(i);
2007 /* process only those images that still use the default settings */
2010 /* process all images which default to same image as "global.door" */
2011 if (strEqual(fi->default_filename, fi_global_door->default_filename))
2013 // printf("::: special treatment needed for token '%s'\n", fi->token);
2015 graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2022 InitGraphicCompatibilityInfo_Doors();
2029 int *width, *height;
2034 { IMG_DOOR_1_WING_LEFT, &door_1.width, &door_1.height, FALSE },
2035 { IMG_DOOR_1_WING_RIGHT, &door_1.width, &door_1.height, TRUE },
2036 { IMG_DOOR_2_WING_LEFT, &door_2.width, &door_2.height, FALSE },
2037 { IMG_DOOR_2_WING_RIGHT, &door_2.width, &door_2.height, TRUE },
2039 { 0, NULL, NULL, FALSE }
2042 for (i = 0; doors[i].graphic != 0; i++)
2044 int graphic = doors[i].graphic;
2045 int *width = doors[i].width;
2046 int *height = doors[i].height;
2047 boolean right_wing = doors[i].right_wing;
2049 struct FileInfo *fi = getImageListEntryFromImageID(graphic);
2050 struct GraphicInfo *g = &graphic_info[graphic];
2056 // correct start position for right wing of "standard" door graphic
2058 g->src_x += g->width - *width;
2064 g->height = *height;
2070 for (i = 0; i < num_images; i++)
2072 struct FileInfo *fi = getImageListEntryFromImageID(i);
2074 if (i == IMG_GLOBAL_DOOR)
2076 printf("::: %s, %s, %d\n",
2077 fi->default_filename,
2085 static void InitElementSoundInfo()
2087 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
2088 int num_property_mappings = getSoundListPropertyMappingSize();
2091 /* set values to -1 to identify later as "uninitialized" values */
2092 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2093 for (act = 0; act < NUM_ACTIONS; act++)
2094 element_info[i].sound[act] = -1;
2096 /* initialize element/sound mapping from static configuration */
2097 for (i = 0; element_to_sound[i].element > -1; i++)
2099 int element = element_to_sound[i].element;
2100 int action = element_to_sound[i].action;
2101 int sound = element_to_sound[i].sound;
2102 boolean is_class = element_to_sound[i].is_class;
2105 action = ACTION_DEFAULT;
2108 element_info[element].sound[action] = sound;
2110 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2111 if (strEqual(element_info[j].class_name,
2112 element_info[element].class_name))
2113 element_info[j].sound[action] = sound;
2116 /* initialize element class/sound mapping from dynamic configuration */
2117 for (i = 0; i < num_property_mappings; i++)
2119 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
2120 int action = property_mapping[i].ext1_index;
2121 int sound = property_mapping[i].artwork_index;
2123 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
2127 action = ACTION_DEFAULT;
2129 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2130 if (strEqual(element_info[j].class_name,
2131 element_info[element_class].class_name))
2132 element_info[j].sound[action] = sound;
2135 /* initialize element/sound mapping from dynamic configuration */
2136 for (i = 0; i < num_property_mappings; i++)
2138 int element = property_mapping[i].base_index;
2139 int action = property_mapping[i].ext1_index;
2140 int sound = property_mapping[i].artwork_index;
2142 if (element >= MAX_NUM_ELEMENTS)
2146 action = ACTION_DEFAULT;
2148 element_info[element].sound[action] = sound;
2151 /* now set all '-1' values to element specific default values */
2152 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2154 for (act = 0; act < NUM_ACTIONS; act++)
2156 /* generic default action sound (defined by "[default]" directive) */
2157 int default_action_sound = element_info[EL_DEFAULT].sound[act];
2159 /* look for special default action sound (classic game specific) */
2160 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
2161 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
2162 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
2163 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
2164 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
2165 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
2167 /* !!! there's no such thing as a "default action sound" !!! */
2169 /* look for element specific default sound (independent from action) */
2170 if (element_info[i].sound[ACTION_DEFAULT] != -1)
2171 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
2175 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
2176 /* !!! make this better !!! */
2177 if (i == EL_EMPTY_SPACE)
2178 default_action_sound = element_info[EL_DEFAULT].sound[act];
2181 /* no sound for this specific action -- use default action sound */
2182 if (element_info[i].sound[act] == -1)
2183 element_info[i].sound[act] = default_action_sound;
2187 /* copy sound settings to some elements that are only stored in level file
2188 in native R'n'D levels, but are used by game engine in native EM levels */
2189 for (i = 0; copy_properties[i][0] != -1; i++)
2190 for (j = 1; j <= 4; j++)
2191 for (act = 0; act < NUM_ACTIONS; act++)
2192 element_info[copy_properties[i][j]].sound[act] =
2193 element_info[copy_properties[i][0]].sound[act];
2196 static void InitGameModeSoundInfo()
2200 /* set values to -1 to identify later as "uninitialized" values */
2201 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2204 /* initialize gamemode/sound mapping from static configuration */
2205 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
2207 int gamemode = gamemode_to_sound[i].gamemode;
2208 int sound = gamemode_to_sound[i].sound;
2211 gamemode = GAME_MODE_DEFAULT;
2213 menu.sound[gamemode] = sound;
2216 /* now set all '-1' values to levelset specific default values */
2217 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2218 if (menu.sound[i] == -1)
2219 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
2222 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2223 if (menu.sound[i] != -1)
2224 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
2228 static void set_sound_parameters(int sound, char **parameter_raw)
2230 int parameter[NUM_SND_ARGS];
2233 /* get integer values from string parameters */
2234 for (i = 0; i < NUM_SND_ARGS; i++)
2236 get_parameter_value(parameter_raw[i],
2237 sound_config_suffix[i].token,
2238 sound_config_suffix[i].type);
2240 /* explicit loop mode setting in configuration overrides default value */
2241 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2242 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
2244 /* sound volume to change the original volume when loading the sound file */
2245 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
2247 /* sound priority to give certain sounds a higher or lower priority */
2248 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
2251 static void InitSoundInfo()
2253 int *sound_effect_properties;
2254 int num_sounds = getSoundListSize();
2257 checked_free(sound_info);
2259 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
2260 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
2262 /* initialize sound effect for all elements to "no sound" */
2263 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2264 for (j = 0; j < NUM_ACTIONS; j++)
2265 element_info[i].sound[j] = SND_UNDEFINED;
2267 for (i = 0; i < num_sounds; i++)
2269 struct FileInfo *sound = getSoundListEntry(i);
2270 int len_effect_text = strlen(sound->token);
2272 sound_effect_properties[i] = ACTION_OTHER;
2273 sound_info[i].loop = FALSE; /* default: play sound only once */
2276 printf("::: sound %d: '%s'\n", i, sound->token);
2279 /* determine all loop sounds and identify certain sound classes */
2281 for (j = 0; element_action_info[j].suffix; j++)
2283 int len_action_text = strlen(element_action_info[j].suffix);
2285 if (len_action_text < len_effect_text &&
2286 strEqual(&sound->token[len_effect_text - len_action_text],
2287 element_action_info[j].suffix))
2289 sound_effect_properties[i] = element_action_info[j].value;
2290 sound_info[i].loop = element_action_info[j].is_loop_sound;
2296 /* associate elements and some selected sound actions */
2298 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2300 if (element_info[j].class_name)
2302 int len_class_text = strlen(element_info[j].class_name);
2304 if (len_class_text + 1 < len_effect_text &&
2305 strncmp(sound->token,
2306 element_info[j].class_name, len_class_text) == 0 &&
2307 sound->token[len_class_text] == '.')
2309 int sound_action_value = sound_effect_properties[i];
2311 element_info[j].sound[sound_action_value] = i;
2316 set_sound_parameters(i, sound->parameter);
2319 free(sound_effect_properties);
2322 static void InitGameModeMusicInfo()
2324 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
2325 int num_property_mappings = getMusicListPropertyMappingSize();
2326 int default_levelset_music = -1;
2329 /* set values to -1 to identify later as "uninitialized" values */
2330 for (i = 0; i < MAX_LEVELS; i++)
2331 levelset.music[i] = -1;
2332 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2335 /* initialize gamemode/music mapping from static configuration */
2336 for (i = 0; gamemode_to_music[i].music > -1; i++)
2338 int gamemode = gamemode_to_music[i].gamemode;
2339 int music = gamemode_to_music[i].music;
2342 printf("::: gamemode == %d, music == %d\n", gamemode, music);
2346 gamemode = GAME_MODE_DEFAULT;
2348 menu.music[gamemode] = music;
2351 /* initialize gamemode/music mapping from dynamic configuration */
2352 for (i = 0; i < num_property_mappings; i++)
2354 int prefix = property_mapping[i].base_index;
2355 int gamemode = property_mapping[i].ext1_index;
2356 int level = property_mapping[i].ext2_index;
2357 int music = property_mapping[i].artwork_index;
2360 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
2361 prefix, gamemode, level, music);
2364 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
2368 gamemode = GAME_MODE_DEFAULT;
2370 /* level specific music only allowed for in-game music */
2371 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
2372 gamemode = GAME_MODE_PLAYING;
2377 default_levelset_music = music;
2380 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
2381 levelset.music[level] = music;
2382 if (gamemode != GAME_MODE_PLAYING)
2383 menu.music[gamemode] = music;
2386 /* now set all '-1' values to menu specific default values */
2387 /* (undefined values of "levelset.music[]" might stay at "-1" to
2388 allow dynamic selection of music files from music directory!) */
2389 for (i = 0; i < MAX_LEVELS; i++)
2390 if (levelset.music[i] == -1)
2391 levelset.music[i] = default_levelset_music;
2392 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2393 if (menu.music[i] == -1)
2394 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
2397 for (i = 0; i < MAX_LEVELS; i++)
2398 if (levelset.music[i] != -1)
2399 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
2400 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2401 if (menu.music[i] != -1)
2402 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
2406 static void set_music_parameters(int music, char **parameter_raw)
2408 int parameter[NUM_MUS_ARGS];
2411 /* get integer values from string parameters */
2412 for (i = 0; i < NUM_MUS_ARGS; i++)
2414 get_parameter_value(parameter_raw[i],
2415 music_config_suffix[i].token,
2416 music_config_suffix[i].type);
2418 /* explicit loop mode setting in configuration overrides default value */
2419 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2420 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
2423 static void InitMusicInfo()
2425 int num_music = getMusicListSize();
2428 checked_free(music_info);
2430 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
2432 for (i = 0; i < num_music; i++)
2434 struct FileInfo *music = getMusicListEntry(i);
2435 int len_music_text = strlen(music->token);
2437 music_info[i].loop = TRUE; /* default: play music in loop mode */
2439 /* determine all loop music */
2441 for (j = 0; music_prefix_info[j].prefix; j++)
2443 int len_prefix_text = strlen(music_prefix_info[j].prefix);
2445 if (len_prefix_text < len_music_text &&
2446 strncmp(music->token,
2447 music_prefix_info[j].prefix, len_prefix_text) == 0)
2449 music_info[i].loop = music_prefix_info[j].is_loop_music;
2455 set_music_parameters(i, music->parameter);
2459 static void ReinitializeGraphics()
2461 print_timestamp_init("ReinitializeGraphics");
2463 InitGraphicInfo(); /* graphic properties mapping */
2464 print_timestamp_time("InitGraphicInfo");
2465 InitElementGraphicInfo(); /* element game graphic mapping */
2466 print_timestamp_time("InitElementGraphicInfo");
2467 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
2468 print_timestamp_time("InitElementSpecialGraphicInfo");
2470 InitElementSmallImages(); /* scale elements to all needed sizes */
2471 print_timestamp_time("InitElementSmallImages");
2472 InitScaledImages(); /* scale all other images, if needed */
2473 print_timestamp_time("InitScaledImages");
2474 InitFontGraphicInfo(); /* initialize text drawing functions */
2475 print_timestamp_time("InitFontGraphicInfo");
2477 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
2478 print_timestamp_time("InitGraphicInfo_EM");
2480 InitGraphicCompatibilityInfo();
2481 print_timestamp_time("InitGraphicCompatibilityInfo");
2483 SetMainBackgroundImage(IMG_BACKGROUND);
2484 print_timestamp_time("SetMainBackgroundImage");
2485 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2486 print_timestamp_time("SetDoorBackgroundImage");
2489 print_timestamp_time("InitGadgets");
2491 print_timestamp_time("InitToons");
2493 print_timestamp_time("InitDoors");
2495 print_timestamp_done("ReinitializeGraphics");
2498 static void ReinitializeSounds()
2500 InitSoundInfo(); /* sound properties mapping */
2501 InitElementSoundInfo(); /* element game sound mapping */
2502 InitGameModeSoundInfo(); /* game mode sound mapping */
2504 InitPlayLevelSound(); /* internal game sound settings */
2507 static void ReinitializeMusic()
2509 InitMusicInfo(); /* music properties mapping */
2510 InitGameModeMusicInfo(); /* game mode music mapping */
2513 static int get_special_property_bit(int element, int property_bit_nr)
2515 struct PropertyBitInfo
2521 static struct PropertyBitInfo pb_can_move_into_acid[] =
2523 /* the player may be able fall into acid when gravity is activated */
2528 { EL_SP_MURPHY, 0 },
2529 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2531 /* all elements that can move may be able to also move into acid */
2534 { EL_BUG_RIGHT, 1 },
2537 { EL_SPACESHIP, 2 },
2538 { EL_SPACESHIP_LEFT, 2 },
2539 { EL_SPACESHIP_RIGHT, 2 },
2540 { EL_SPACESHIP_UP, 2 },
2541 { EL_SPACESHIP_DOWN, 2 },
2542 { EL_BD_BUTTERFLY, 3 },
2543 { EL_BD_BUTTERFLY_LEFT, 3 },
2544 { EL_BD_BUTTERFLY_RIGHT, 3 },
2545 { EL_BD_BUTTERFLY_UP, 3 },
2546 { EL_BD_BUTTERFLY_DOWN, 3 },
2547 { EL_BD_FIREFLY, 4 },
2548 { EL_BD_FIREFLY_LEFT, 4 },
2549 { EL_BD_FIREFLY_RIGHT, 4 },
2550 { EL_BD_FIREFLY_UP, 4 },
2551 { EL_BD_FIREFLY_DOWN, 4 },
2553 { EL_YAMYAM_LEFT, 5 },
2554 { EL_YAMYAM_RIGHT, 5 },
2555 { EL_YAMYAM_UP, 5 },
2556 { EL_YAMYAM_DOWN, 5 },
2557 { EL_DARK_YAMYAM, 6 },
2560 { EL_PACMAN_LEFT, 8 },
2561 { EL_PACMAN_RIGHT, 8 },
2562 { EL_PACMAN_UP, 8 },
2563 { EL_PACMAN_DOWN, 8 },
2565 { EL_MOLE_LEFT, 9 },
2566 { EL_MOLE_RIGHT, 9 },
2568 { EL_MOLE_DOWN, 9 },
2572 { EL_SATELLITE, 13 },
2573 { EL_SP_SNIKSNAK, 14 },
2574 { EL_SP_ELECTRON, 15 },
2577 { EL_EMC_ANDROID, 18 },
2582 static struct PropertyBitInfo pb_dont_collide_with[] =
2584 { EL_SP_SNIKSNAK, 0 },
2585 { EL_SP_ELECTRON, 1 },
2593 struct PropertyBitInfo *pb_info;
2596 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2597 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2602 struct PropertyBitInfo *pb_info = NULL;
2605 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2606 if (pb_definition[i].bit_nr == property_bit_nr)
2607 pb_info = pb_definition[i].pb_info;
2609 if (pb_info == NULL)
2612 for (i = 0; pb_info[i].element != -1; i++)
2613 if (pb_info[i].element == element)
2614 return pb_info[i].bit_nr;
2619 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2620 boolean property_value)
2622 int bit_nr = get_special_property_bit(element, property_bit_nr);
2627 *bitfield |= (1 << bit_nr);
2629 *bitfield &= ~(1 << bit_nr);
2633 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2635 int bit_nr = get_special_property_bit(element, property_bit_nr);
2638 return ((*bitfield & (1 << bit_nr)) != 0);
2643 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2645 static int group_nr;
2646 static struct ElementGroupInfo *group;
2647 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2650 if (actual_group == NULL) /* not yet initialized */
2653 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
2655 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2656 group_element - EL_GROUP_START + 1);
2658 /* replace element which caused too deep recursion by question mark */
2659 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2664 if (recursion_depth == 0) /* initialization */
2666 group = actual_group;
2667 group_nr = GROUP_NR(group_element);
2669 group->num_elements_resolved = 0;
2670 group->choice_pos = 0;
2672 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2673 element_info[i].in_group[group_nr] = FALSE;
2676 for (i = 0; i < actual_group->num_elements; i++)
2678 int element = actual_group->element[i];
2680 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2683 if (IS_GROUP_ELEMENT(element))
2684 ResolveGroupElementExt(element, recursion_depth + 1);
2687 group->element_resolved[group->num_elements_resolved++] = element;
2688 element_info[element].in_group[group_nr] = TRUE;
2693 void ResolveGroupElement(int group_element)
2695 ResolveGroupElementExt(group_element, 0);
2698 void InitElementPropertiesStatic()
2700 static boolean clipboard_elements_initialized = FALSE;
2702 static int ep_diggable[] =
2707 EL_SP_BUGGY_BASE_ACTIVATING,
2710 EL_INVISIBLE_SAND_ACTIVE,
2713 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2714 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2719 EL_SP_BUGGY_BASE_ACTIVE,
2726 static int ep_collectible_only[] =
2748 EL_DYNABOMB_INCREASE_NUMBER,
2749 EL_DYNABOMB_INCREASE_SIZE,
2750 EL_DYNABOMB_INCREASE_POWER,
2768 /* !!! handle separately !!! */
2769 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2775 static int ep_dont_run_into[] =
2777 /* same elements as in 'ep_dont_touch' */
2783 /* same elements as in 'ep_dont_collide_with' */
2795 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2800 EL_SP_BUGGY_BASE_ACTIVE,
2807 static int ep_dont_collide_with[] =
2809 /* same elements as in 'ep_dont_touch' */
2826 static int ep_dont_touch[] =
2836 static int ep_indestructible[] =
2840 EL_ACID_POOL_TOPLEFT,
2841 EL_ACID_POOL_TOPRIGHT,
2842 EL_ACID_POOL_BOTTOMLEFT,
2843 EL_ACID_POOL_BOTTOM,
2844 EL_ACID_POOL_BOTTOMRIGHT,
2845 EL_SP_HARDWARE_GRAY,
2846 EL_SP_HARDWARE_GREEN,
2847 EL_SP_HARDWARE_BLUE,
2849 EL_SP_HARDWARE_YELLOW,
2850 EL_SP_HARDWARE_BASE_1,
2851 EL_SP_HARDWARE_BASE_2,
2852 EL_SP_HARDWARE_BASE_3,
2853 EL_SP_HARDWARE_BASE_4,
2854 EL_SP_HARDWARE_BASE_5,
2855 EL_SP_HARDWARE_BASE_6,
2856 EL_INVISIBLE_STEELWALL,
2857 EL_INVISIBLE_STEELWALL_ACTIVE,
2858 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2859 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2860 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2861 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2862 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2863 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2864 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2865 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2866 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2867 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2868 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2869 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2871 EL_LIGHT_SWITCH_ACTIVE,
2872 EL_SIGN_EXCLAMATION,
2873 EL_SIGN_RADIOACTIVITY,
2880 EL_SIGN_ENTRY_FORBIDDEN,
2881 EL_SIGN_EMERGENCY_EXIT,
2889 EL_STEEL_EXIT_CLOSED,
2891 EL_STEEL_EXIT_OPENING,
2892 EL_STEEL_EXIT_CLOSING,
2893 EL_EM_STEEL_EXIT_CLOSED,
2894 EL_EM_STEEL_EXIT_OPEN,
2895 EL_EM_STEEL_EXIT_OPENING,
2896 EL_EM_STEEL_EXIT_CLOSING,
2897 EL_DC_STEELWALL_1_LEFT,
2898 EL_DC_STEELWALL_1_RIGHT,
2899 EL_DC_STEELWALL_1_TOP,
2900 EL_DC_STEELWALL_1_BOTTOM,
2901 EL_DC_STEELWALL_1_HORIZONTAL,
2902 EL_DC_STEELWALL_1_VERTICAL,
2903 EL_DC_STEELWALL_1_TOPLEFT,
2904 EL_DC_STEELWALL_1_TOPRIGHT,
2905 EL_DC_STEELWALL_1_BOTTOMLEFT,
2906 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2907 EL_DC_STEELWALL_1_TOPLEFT_2,
2908 EL_DC_STEELWALL_1_TOPRIGHT_2,
2909 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2910 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2911 EL_DC_STEELWALL_2_LEFT,
2912 EL_DC_STEELWALL_2_RIGHT,
2913 EL_DC_STEELWALL_2_TOP,
2914 EL_DC_STEELWALL_2_BOTTOM,
2915 EL_DC_STEELWALL_2_HORIZONTAL,
2916 EL_DC_STEELWALL_2_VERTICAL,
2917 EL_DC_STEELWALL_2_MIDDLE,
2918 EL_DC_STEELWALL_2_SINGLE,
2919 EL_STEELWALL_SLIPPERY,
2933 EL_GATE_1_GRAY_ACTIVE,
2934 EL_GATE_2_GRAY_ACTIVE,
2935 EL_GATE_3_GRAY_ACTIVE,
2936 EL_GATE_4_GRAY_ACTIVE,
2945 EL_EM_GATE_1_GRAY_ACTIVE,
2946 EL_EM_GATE_2_GRAY_ACTIVE,
2947 EL_EM_GATE_3_GRAY_ACTIVE,
2948 EL_EM_GATE_4_GRAY_ACTIVE,
2957 EL_EMC_GATE_5_GRAY_ACTIVE,
2958 EL_EMC_GATE_6_GRAY_ACTIVE,
2959 EL_EMC_GATE_7_GRAY_ACTIVE,
2960 EL_EMC_GATE_8_GRAY_ACTIVE,
2962 EL_DC_GATE_WHITE_GRAY,
2963 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2964 EL_DC_GATE_FAKE_GRAY,
2966 EL_SWITCHGATE_OPENING,
2967 EL_SWITCHGATE_CLOSED,
2968 EL_SWITCHGATE_CLOSING,
2970 EL_DC_SWITCHGATE_SWITCH_UP,
2971 EL_DC_SWITCHGATE_SWITCH_DOWN,
2974 EL_TIMEGATE_OPENING,
2976 EL_TIMEGATE_CLOSING,
2978 EL_DC_TIMEGATE_SWITCH,
2979 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2984 EL_TUBE_VERTICAL_LEFT,
2985 EL_TUBE_VERTICAL_RIGHT,
2986 EL_TUBE_HORIZONTAL_UP,
2987 EL_TUBE_HORIZONTAL_DOWN,
2992 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2993 EL_EXPANDABLE_STEELWALL_VERTICAL,
2994 EL_EXPANDABLE_STEELWALL_ANY,
2999 static int ep_slippery[] =
3013 EL_ROBOT_WHEEL_ACTIVE,
3019 EL_ACID_POOL_TOPLEFT,
3020 EL_ACID_POOL_TOPRIGHT,
3030 EL_STEELWALL_SLIPPERY,
3033 EL_EMC_WALL_SLIPPERY_1,
3034 EL_EMC_WALL_SLIPPERY_2,
3035 EL_EMC_WALL_SLIPPERY_3,
3036 EL_EMC_WALL_SLIPPERY_4,
3038 EL_EMC_MAGIC_BALL_ACTIVE,
3043 static int ep_can_change[] =
3048 static int ep_can_move[] =
3050 /* same elements as in 'pb_can_move_into_acid' */
3073 static int ep_can_fall[] =
3087 EL_QUICKSAND_FAST_FULL,
3089 EL_BD_MAGIC_WALL_FULL,
3090 EL_DC_MAGIC_WALL_FULL,
3104 static int ep_can_smash_player[] =
3130 static int ep_can_smash_enemies[] =
3139 static int ep_can_smash_everything[] =
3148 static int ep_explodes_by_fire[] =
3150 /* same elements as in 'ep_explodes_impact' */
3155 /* same elements as in 'ep_explodes_smashed' */
3165 EL_EM_DYNAMITE_ACTIVE,
3166 EL_DYNABOMB_PLAYER_1_ACTIVE,
3167 EL_DYNABOMB_PLAYER_2_ACTIVE,
3168 EL_DYNABOMB_PLAYER_3_ACTIVE,
3169 EL_DYNABOMB_PLAYER_4_ACTIVE,
3170 EL_DYNABOMB_INCREASE_NUMBER,
3171 EL_DYNABOMB_INCREASE_SIZE,
3172 EL_DYNABOMB_INCREASE_POWER,
3173 EL_SP_DISK_RED_ACTIVE,
3187 static int ep_explodes_smashed[] =
3189 /* same elements as in 'ep_explodes_impact' */
3203 static int ep_explodes_impact[] =
3212 static int ep_walkable_over[] =
3216 EL_SOKOBAN_FIELD_EMPTY,
3225 EL_EM_STEEL_EXIT_OPEN,
3227 EL_EM_STEEL_EXIT_OPENING,
3237 EL_GATE_1_GRAY_ACTIVE,
3238 EL_GATE_2_GRAY_ACTIVE,
3239 EL_GATE_3_GRAY_ACTIVE,
3240 EL_GATE_4_GRAY_ACTIVE,
3248 static int ep_walkable_inside[] =
3253 EL_TUBE_VERTICAL_LEFT,
3254 EL_TUBE_VERTICAL_RIGHT,
3255 EL_TUBE_HORIZONTAL_UP,
3256 EL_TUBE_HORIZONTAL_DOWN,
3265 static int ep_walkable_under[] =
3270 static int ep_passable_over[] =
3280 EL_EM_GATE_1_GRAY_ACTIVE,
3281 EL_EM_GATE_2_GRAY_ACTIVE,
3282 EL_EM_GATE_3_GRAY_ACTIVE,
3283 EL_EM_GATE_4_GRAY_ACTIVE,
3292 EL_EMC_GATE_5_GRAY_ACTIVE,
3293 EL_EMC_GATE_6_GRAY_ACTIVE,
3294 EL_EMC_GATE_7_GRAY_ACTIVE,
3295 EL_EMC_GATE_8_GRAY_ACTIVE,
3297 EL_DC_GATE_WHITE_GRAY,
3298 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3305 static int ep_passable_inside[] =
3311 EL_SP_PORT_HORIZONTAL,
3312 EL_SP_PORT_VERTICAL,
3314 EL_SP_GRAVITY_PORT_LEFT,
3315 EL_SP_GRAVITY_PORT_RIGHT,
3316 EL_SP_GRAVITY_PORT_UP,
3317 EL_SP_GRAVITY_PORT_DOWN,
3318 EL_SP_GRAVITY_ON_PORT_LEFT,
3319 EL_SP_GRAVITY_ON_PORT_RIGHT,
3320 EL_SP_GRAVITY_ON_PORT_UP,
3321 EL_SP_GRAVITY_ON_PORT_DOWN,
3322 EL_SP_GRAVITY_OFF_PORT_LEFT,
3323 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3324 EL_SP_GRAVITY_OFF_PORT_UP,
3325 EL_SP_GRAVITY_OFF_PORT_DOWN,
3330 static int ep_passable_under[] =
3335 static int ep_droppable[] =
3340 static int ep_explodes_1x1_old[] =
3345 static int ep_pushable[] =
3357 EL_SOKOBAN_FIELD_FULL,
3366 static int ep_explodes_cross_old[] =
3371 static int ep_protected[] =
3373 /* same elements as in 'ep_walkable_inside' */
3377 EL_TUBE_VERTICAL_LEFT,
3378 EL_TUBE_VERTICAL_RIGHT,
3379 EL_TUBE_HORIZONTAL_UP,
3380 EL_TUBE_HORIZONTAL_DOWN,
3386 /* same elements as in 'ep_passable_over' */
3395 EL_EM_GATE_1_GRAY_ACTIVE,
3396 EL_EM_GATE_2_GRAY_ACTIVE,
3397 EL_EM_GATE_3_GRAY_ACTIVE,
3398 EL_EM_GATE_4_GRAY_ACTIVE,
3407 EL_EMC_GATE_5_GRAY_ACTIVE,
3408 EL_EMC_GATE_6_GRAY_ACTIVE,
3409 EL_EMC_GATE_7_GRAY_ACTIVE,
3410 EL_EMC_GATE_8_GRAY_ACTIVE,
3412 EL_DC_GATE_WHITE_GRAY,
3413 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3417 /* same elements as in 'ep_passable_inside' */
3422 EL_SP_PORT_HORIZONTAL,
3423 EL_SP_PORT_VERTICAL,
3425 EL_SP_GRAVITY_PORT_LEFT,
3426 EL_SP_GRAVITY_PORT_RIGHT,
3427 EL_SP_GRAVITY_PORT_UP,
3428 EL_SP_GRAVITY_PORT_DOWN,
3429 EL_SP_GRAVITY_ON_PORT_LEFT,
3430 EL_SP_GRAVITY_ON_PORT_RIGHT,
3431 EL_SP_GRAVITY_ON_PORT_UP,
3432 EL_SP_GRAVITY_ON_PORT_DOWN,
3433 EL_SP_GRAVITY_OFF_PORT_LEFT,
3434 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3435 EL_SP_GRAVITY_OFF_PORT_UP,
3436 EL_SP_GRAVITY_OFF_PORT_DOWN,
3441 static int ep_throwable[] =
3446 static int ep_can_explode[] =
3448 /* same elements as in 'ep_explodes_impact' */
3453 /* same elements as in 'ep_explodes_smashed' */
3459 /* elements that can explode by explosion or by dragonfire */
3463 EL_EM_DYNAMITE_ACTIVE,
3464 EL_DYNABOMB_PLAYER_1_ACTIVE,
3465 EL_DYNABOMB_PLAYER_2_ACTIVE,
3466 EL_DYNABOMB_PLAYER_3_ACTIVE,
3467 EL_DYNABOMB_PLAYER_4_ACTIVE,
3468 EL_DYNABOMB_INCREASE_NUMBER,
3469 EL_DYNABOMB_INCREASE_SIZE,
3470 EL_DYNABOMB_INCREASE_POWER,
3471 EL_SP_DISK_RED_ACTIVE,
3479 /* elements that can explode only by explosion */
3485 static int ep_gravity_reachable[] =
3491 EL_INVISIBLE_SAND_ACTIVE,
3496 EL_SP_PORT_HORIZONTAL,
3497 EL_SP_PORT_VERTICAL,
3499 EL_SP_GRAVITY_PORT_LEFT,
3500 EL_SP_GRAVITY_PORT_RIGHT,
3501 EL_SP_GRAVITY_PORT_UP,
3502 EL_SP_GRAVITY_PORT_DOWN,
3503 EL_SP_GRAVITY_ON_PORT_LEFT,
3504 EL_SP_GRAVITY_ON_PORT_RIGHT,
3505 EL_SP_GRAVITY_ON_PORT_UP,
3506 EL_SP_GRAVITY_ON_PORT_DOWN,
3507 EL_SP_GRAVITY_OFF_PORT_LEFT,
3508 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3509 EL_SP_GRAVITY_OFF_PORT_UP,
3510 EL_SP_GRAVITY_OFF_PORT_DOWN,
3516 static int ep_player[] =
3523 EL_SOKOBAN_FIELD_PLAYER,
3529 static int ep_can_pass_magic_wall[] =
3543 static int ep_can_pass_dc_magic_wall[] =
3559 static int ep_switchable[] =
3563 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3564 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3565 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3566 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3567 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3568 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3569 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3570 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3571 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3572 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3573 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3574 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3575 EL_SWITCHGATE_SWITCH_UP,
3576 EL_SWITCHGATE_SWITCH_DOWN,
3577 EL_DC_SWITCHGATE_SWITCH_UP,
3578 EL_DC_SWITCHGATE_SWITCH_DOWN,
3580 EL_LIGHT_SWITCH_ACTIVE,
3582 EL_DC_TIMEGATE_SWITCH,
3583 EL_BALLOON_SWITCH_LEFT,
3584 EL_BALLOON_SWITCH_RIGHT,
3585 EL_BALLOON_SWITCH_UP,
3586 EL_BALLOON_SWITCH_DOWN,
3587 EL_BALLOON_SWITCH_ANY,
3588 EL_BALLOON_SWITCH_NONE,
3591 EL_EMC_MAGIC_BALL_SWITCH,
3592 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3597 static int ep_bd_element[] =
3631 static int ep_sp_element[] =
3633 /* should always be valid */
3636 /* standard classic Supaplex elements */
3643 EL_SP_HARDWARE_GRAY,
3651 EL_SP_GRAVITY_PORT_RIGHT,
3652 EL_SP_GRAVITY_PORT_DOWN,
3653 EL_SP_GRAVITY_PORT_LEFT,
3654 EL_SP_GRAVITY_PORT_UP,
3659 EL_SP_PORT_VERTICAL,
3660 EL_SP_PORT_HORIZONTAL,
3666 EL_SP_HARDWARE_BASE_1,
3667 EL_SP_HARDWARE_GREEN,
3668 EL_SP_HARDWARE_BLUE,
3670 EL_SP_HARDWARE_YELLOW,
3671 EL_SP_HARDWARE_BASE_2,
3672 EL_SP_HARDWARE_BASE_3,
3673 EL_SP_HARDWARE_BASE_4,
3674 EL_SP_HARDWARE_BASE_5,
3675 EL_SP_HARDWARE_BASE_6,
3679 /* additional elements that appeared in newer Supaplex levels */
3682 /* additional gravity port elements (not switching, but setting gravity) */
3683 EL_SP_GRAVITY_ON_PORT_LEFT,
3684 EL_SP_GRAVITY_ON_PORT_RIGHT,
3685 EL_SP_GRAVITY_ON_PORT_UP,
3686 EL_SP_GRAVITY_ON_PORT_DOWN,
3687 EL_SP_GRAVITY_OFF_PORT_LEFT,
3688 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3689 EL_SP_GRAVITY_OFF_PORT_UP,
3690 EL_SP_GRAVITY_OFF_PORT_DOWN,
3692 /* more than one Murphy in a level results in an inactive clone */
3695 /* runtime Supaplex elements */
3696 EL_SP_DISK_RED_ACTIVE,
3697 EL_SP_TERMINAL_ACTIVE,
3698 EL_SP_BUGGY_BASE_ACTIVATING,
3699 EL_SP_BUGGY_BASE_ACTIVE,
3706 static int ep_sb_element[] =
3711 EL_SOKOBAN_FIELD_EMPTY,
3712 EL_SOKOBAN_FIELD_FULL,
3713 EL_SOKOBAN_FIELD_PLAYER,
3718 EL_INVISIBLE_STEELWALL,
3723 static int ep_gem[] =
3735 static int ep_food_dark_yamyam[] =
3763 static int ep_food_penguin[] =
3777 static int ep_food_pig[] =
3789 static int ep_historic_wall[] =
3800 EL_GATE_1_GRAY_ACTIVE,
3801 EL_GATE_2_GRAY_ACTIVE,
3802 EL_GATE_3_GRAY_ACTIVE,
3803 EL_GATE_4_GRAY_ACTIVE,
3812 EL_EM_GATE_1_GRAY_ACTIVE,
3813 EL_EM_GATE_2_GRAY_ACTIVE,
3814 EL_EM_GATE_3_GRAY_ACTIVE,
3815 EL_EM_GATE_4_GRAY_ACTIVE,
3822 EL_EXPANDABLE_WALL_HORIZONTAL,
3823 EL_EXPANDABLE_WALL_VERTICAL,
3824 EL_EXPANDABLE_WALL_ANY,
3825 EL_EXPANDABLE_WALL_GROWING,
3826 EL_BD_EXPANDABLE_WALL,
3833 EL_SP_HARDWARE_GRAY,
3834 EL_SP_HARDWARE_GREEN,
3835 EL_SP_HARDWARE_BLUE,
3837 EL_SP_HARDWARE_YELLOW,
3838 EL_SP_HARDWARE_BASE_1,
3839 EL_SP_HARDWARE_BASE_2,
3840 EL_SP_HARDWARE_BASE_3,
3841 EL_SP_HARDWARE_BASE_4,
3842 EL_SP_HARDWARE_BASE_5,
3843 EL_SP_HARDWARE_BASE_6,
3845 EL_SP_TERMINAL_ACTIVE,
3848 EL_INVISIBLE_STEELWALL,
3849 EL_INVISIBLE_STEELWALL_ACTIVE,
3851 EL_INVISIBLE_WALL_ACTIVE,
3852 EL_STEELWALL_SLIPPERY,
3869 static int ep_historic_solid[] =
3873 EL_EXPANDABLE_WALL_HORIZONTAL,
3874 EL_EXPANDABLE_WALL_VERTICAL,
3875 EL_EXPANDABLE_WALL_ANY,
3876 EL_BD_EXPANDABLE_WALL,
3889 EL_QUICKSAND_FILLING,
3890 EL_QUICKSAND_EMPTYING,
3892 EL_MAGIC_WALL_ACTIVE,
3893 EL_MAGIC_WALL_EMPTYING,
3894 EL_MAGIC_WALL_FILLING,
3898 EL_BD_MAGIC_WALL_ACTIVE,
3899 EL_BD_MAGIC_WALL_EMPTYING,
3900 EL_BD_MAGIC_WALL_FULL,
3901 EL_BD_MAGIC_WALL_FILLING,
3902 EL_BD_MAGIC_WALL_DEAD,
3911 EL_SP_TERMINAL_ACTIVE,
3915 EL_INVISIBLE_WALL_ACTIVE,
3916 EL_SWITCHGATE_SWITCH_UP,
3917 EL_SWITCHGATE_SWITCH_DOWN,
3918 EL_DC_SWITCHGATE_SWITCH_UP,
3919 EL_DC_SWITCHGATE_SWITCH_DOWN,
3921 EL_TIMEGATE_SWITCH_ACTIVE,
3922 EL_DC_TIMEGATE_SWITCH,
3923 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3935 /* the following elements are a direct copy of "indestructible" elements,
3936 except "EL_ACID", which is "indestructible", but not "solid"! */
3941 EL_ACID_POOL_TOPLEFT,
3942 EL_ACID_POOL_TOPRIGHT,
3943 EL_ACID_POOL_BOTTOMLEFT,
3944 EL_ACID_POOL_BOTTOM,
3945 EL_ACID_POOL_BOTTOMRIGHT,
3946 EL_SP_HARDWARE_GRAY,
3947 EL_SP_HARDWARE_GREEN,
3948 EL_SP_HARDWARE_BLUE,
3950 EL_SP_HARDWARE_YELLOW,
3951 EL_SP_HARDWARE_BASE_1,
3952 EL_SP_HARDWARE_BASE_2,
3953 EL_SP_HARDWARE_BASE_3,
3954 EL_SP_HARDWARE_BASE_4,
3955 EL_SP_HARDWARE_BASE_5,
3956 EL_SP_HARDWARE_BASE_6,
3957 EL_INVISIBLE_STEELWALL,
3958 EL_INVISIBLE_STEELWALL_ACTIVE,
3959 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3960 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3961 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3962 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3963 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3964 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3965 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3966 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3967 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3968 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3969 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3970 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3972 EL_LIGHT_SWITCH_ACTIVE,
3973 EL_SIGN_EXCLAMATION,
3974 EL_SIGN_RADIOACTIVITY,
3981 EL_SIGN_ENTRY_FORBIDDEN,
3982 EL_SIGN_EMERGENCY_EXIT,
3990 EL_STEEL_EXIT_CLOSED,
3992 EL_DC_STEELWALL_1_LEFT,
3993 EL_DC_STEELWALL_1_RIGHT,
3994 EL_DC_STEELWALL_1_TOP,
3995 EL_DC_STEELWALL_1_BOTTOM,
3996 EL_DC_STEELWALL_1_HORIZONTAL,
3997 EL_DC_STEELWALL_1_VERTICAL,
3998 EL_DC_STEELWALL_1_TOPLEFT,
3999 EL_DC_STEELWALL_1_TOPRIGHT,
4000 EL_DC_STEELWALL_1_BOTTOMLEFT,
4001 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4002 EL_DC_STEELWALL_1_TOPLEFT_2,
4003 EL_DC_STEELWALL_1_TOPRIGHT_2,
4004 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4005 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4006 EL_DC_STEELWALL_2_LEFT,
4007 EL_DC_STEELWALL_2_RIGHT,
4008 EL_DC_STEELWALL_2_TOP,
4009 EL_DC_STEELWALL_2_BOTTOM,
4010 EL_DC_STEELWALL_2_HORIZONTAL,
4011 EL_DC_STEELWALL_2_VERTICAL,
4012 EL_DC_STEELWALL_2_MIDDLE,
4013 EL_DC_STEELWALL_2_SINGLE,
4014 EL_STEELWALL_SLIPPERY,
4028 EL_GATE_1_GRAY_ACTIVE,
4029 EL_GATE_2_GRAY_ACTIVE,
4030 EL_GATE_3_GRAY_ACTIVE,
4031 EL_GATE_4_GRAY_ACTIVE,
4040 EL_EM_GATE_1_GRAY_ACTIVE,
4041 EL_EM_GATE_2_GRAY_ACTIVE,
4042 EL_EM_GATE_3_GRAY_ACTIVE,
4043 EL_EM_GATE_4_GRAY_ACTIVE,
4045 EL_SWITCHGATE_OPENING,
4046 EL_SWITCHGATE_CLOSED,
4047 EL_SWITCHGATE_CLOSING,
4049 EL_TIMEGATE_OPENING,
4051 EL_TIMEGATE_CLOSING,
4055 EL_TUBE_VERTICAL_LEFT,
4056 EL_TUBE_VERTICAL_RIGHT,
4057 EL_TUBE_HORIZONTAL_UP,
4058 EL_TUBE_HORIZONTAL_DOWN,
4067 static int ep_classic_enemy[] =
4084 static int ep_belt[] =
4086 EL_CONVEYOR_BELT_1_LEFT,
4087 EL_CONVEYOR_BELT_1_MIDDLE,
4088 EL_CONVEYOR_BELT_1_RIGHT,
4089 EL_CONVEYOR_BELT_2_LEFT,
4090 EL_CONVEYOR_BELT_2_MIDDLE,
4091 EL_CONVEYOR_BELT_2_RIGHT,
4092 EL_CONVEYOR_BELT_3_LEFT,
4093 EL_CONVEYOR_BELT_3_MIDDLE,
4094 EL_CONVEYOR_BELT_3_RIGHT,
4095 EL_CONVEYOR_BELT_4_LEFT,
4096 EL_CONVEYOR_BELT_4_MIDDLE,
4097 EL_CONVEYOR_BELT_4_RIGHT,
4102 static int ep_belt_active[] =
4104 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
4105 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
4106 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
4107 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
4108 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
4109 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
4110 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
4111 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
4112 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
4113 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
4114 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
4115 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
4120 static int ep_belt_switch[] =
4122 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4123 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4124 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4125 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4126 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4127 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4128 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4129 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4130 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4131 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4132 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4133 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4138 static int ep_tube[] =
4145 EL_TUBE_HORIZONTAL_UP,
4146 EL_TUBE_HORIZONTAL_DOWN,
4148 EL_TUBE_VERTICAL_LEFT,
4149 EL_TUBE_VERTICAL_RIGHT,
4155 static int ep_acid_pool[] =
4157 EL_ACID_POOL_TOPLEFT,
4158 EL_ACID_POOL_TOPRIGHT,
4159 EL_ACID_POOL_BOTTOMLEFT,
4160 EL_ACID_POOL_BOTTOM,
4161 EL_ACID_POOL_BOTTOMRIGHT,
4166 static int ep_keygate[] =
4176 EL_GATE_1_GRAY_ACTIVE,
4177 EL_GATE_2_GRAY_ACTIVE,
4178 EL_GATE_3_GRAY_ACTIVE,
4179 EL_GATE_4_GRAY_ACTIVE,
4188 EL_EM_GATE_1_GRAY_ACTIVE,
4189 EL_EM_GATE_2_GRAY_ACTIVE,
4190 EL_EM_GATE_3_GRAY_ACTIVE,
4191 EL_EM_GATE_4_GRAY_ACTIVE,
4200 EL_EMC_GATE_5_GRAY_ACTIVE,
4201 EL_EMC_GATE_6_GRAY_ACTIVE,
4202 EL_EMC_GATE_7_GRAY_ACTIVE,
4203 EL_EMC_GATE_8_GRAY_ACTIVE,
4205 EL_DC_GATE_WHITE_GRAY,
4206 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4211 static int ep_amoeboid[] =
4223 static int ep_amoebalive[] =
4234 static int ep_has_editor_content[] =
4240 EL_SOKOBAN_FIELD_PLAYER,
4257 static int ep_can_turn_each_move[] =
4259 /* !!! do something with this one !!! */
4263 static int ep_can_grow[] =
4277 static int ep_active_bomb[] =
4280 EL_EM_DYNAMITE_ACTIVE,
4281 EL_DYNABOMB_PLAYER_1_ACTIVE,
4282 EL_DYNABOMB_PLAYER_2_ACTIVE,
4283 EL_DYNABOMB_PLAYER_3_ACTIVE,
4284 EL_DYNABOMB_PLAYER_4_ACTIVE,
4285 EL_SP_DISK_RED_ACTIVE,
4290 static int ep_inactive[] =
4300 EL_QUICKSAND_FAST_EMPTY,
4323 EL_GATE_1_GRAY_ACTIVE,
4324 EL_GATE_2_GRAY_ACTIVE,
4325 EL_GATE_3_GRAY_ACTIVE,
4326 EL_GATE_4_GRAY_ACTIVE,
4335 EL_EM_GATE_1_GRAY_ACTIVE,
4336 EL_EM_GATE_2_GRAY_ACTIVE,
4337 EL_EM_GATE_3_GRAY_ACTIVE,
4338 EL_EM_GATE_4_GRAY_ACTIVE,
4347 EL_EMC_GATE_5_GRAY_ACTIVE,
4348 EL_EMC_GATE_6_GRAY_ACTIVE,
4349 EL_EMC_GATE_7_GRAY_ACTIVE,
4350 EL_EMC_GATE_8_GRAY_ACTIVE,
4352 EL_DC_GATE_WHITE_GRAY,
4353 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4354 EL_DC_GATE_FAKE_GRAY,
4357 EL_INVISIBLE_STEELWALL,
4365 EL_WALL_EMERALD_YELLOW,
4366 EL_DYNABOMB_INCREASE_NUMBER,
4367 EL_DYNABOMB_INCREASE_SIZE,
4368 EL_DYNABOMB_INCREASE_POWER,
4372 EL_SOKOBAN_FIELD_EMPTY,
4373 EL_SOKOBAN_FIELD_FULL,
4374 EL_WALL_EMERALD_RED,
4375 EL_WALL_EMERALD_PURPLE,
4376 EL_ACID_POOL_TOPLEFT,
4377 EL_ACID_POOL_TOPRIGHT,
4378 EL_ACID_POOL_BOTTOMLEFT,
4379 EL_ACID_POOL_BOTTOM,
4380 EL_ACID_POOL_BOTTOMRIGHT,
4384 EL_BD_MAGIC_WALL_DEAD,
4386 EL_DC_MAGIC_WALL_DEAD,
4387 EL_AMOEBA_TO_DIAMOND,
4395 EL_SP_GRAVITY_PORT_RIGHT,
4396 EL_SP_GRAVITY_PORT_DOWN,
4397 EL_SP_GRAVITY_PORT_LEFT,
4398 EL_SP_GRAVITY_PORT_UP,
4399 EL_SP_PORT_HORIZONTAL,
4400 EL_SP_PORT_VERTICAL,
4411 EL_SP_HARDWARE_GRAY,
4412 EL_SP_HARDWARE_GREEN,
4413 EL_SP_HARDWARE_BLUE,
4415 EL_SP_HARDWARE_YELLOW,
4416 EL_SP_HARDWARE_BASE_1,
4417 EL_SP_HARDWARE_BASE_2,
4418 EL_SP_HARDWARE_BASE_3,
4419 EL_SP_HARDWARE_BASE_4,
4420 EL_SP_HARDWARE_BASE_5,
4421 EL_SP_HARDWARE_BASE_6,
4422 EL_SP_GRAVITY_ON_PORT_LEFT,
4423 EL_SP_GRAVITY_ON_PORT_RIGHT,
4424 EL_SP_GRAVITY_ON_PORT_UP,
4425 EL_SP_GRAVITY_ON_PORT_DOWN,
4426 EL_SP_GRAVITY_OFF_PORT_LEFT,
4427 EL_SP_GRAVITY_OFF_PORT_RIGHT,
4428 EL_SP_GRAVITY_OFF_PORT_UP,
4429 EL_SP_GRAVITY_OFF_PORT_DOWN,
4430 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4431 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4432 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4433 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4434 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4435 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4436 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4437 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4438 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4439 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4440 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4441 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4442 EL_SIGN_EXCLAMATION,
4443 EL_SIGN_RADIOACTIVITY,
4450 EL_SIGN_ENTRY_FORBIDDEN,
4451 EL_SIGN_EMERGENCY_EXIT,
4459 EL_DC_STEELWALL_1_LEFT,
4460 EL_DC_STEELWALL_1_RIGHT,
4461 EL_DC_STEELWALL_1_TOP,
4462 EL_DC_STEELWALL_1_BOTTOM,
4463 EL_DC_STEELWALL_1_HORIZONTAL,
4464 EL_DC_STEELWALL_1_VERTICAL,
4465 EL_DC_STEELWALL_1_TOPLEFT,
4466 EL_DC_STEELWALL_1_TOPRIGHT,
4467 EL_DC_STEELWALL_1_BOTTOMLEFT,
4468 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4469 EL_DC_STEELWALL_1_TOPLEFT_2,
4470 EL_DC_STEELWALL_1_TOPRIGHT_2,
4471 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4472 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4473 EL_DC_STEELWALL_2_LEFT,
4474 EL_DC_STEELWALL_2_RIGHT,
4475 EL_DC_STEELWALL_2_TOP,
4476 EL_DC_STEELWALL_2_BOTTOM,
4477 EL_DC_STEELWALL_2_HORIZONTAL,
4478 EL_DC_STEELWALL_2_VERTICAL,
4479 EL_DC_STEELWALL_2_MIDDLE,
4480 EL_DC_STEELWALL_2_SINGLE,
4481 EL_STEELWALL_SLIPPERY,
4486 EL_EMC_WALL_SLIPPERY_1,
4487 EL_EMC_WALL_SLIPPERY_2,
4488 EL_EMC_WALL_SLIPPERY_3,
4489 EL_EMC_WALL_SLIPPERY_4,
4510 static int ep_em_slippery_wall[] =
4515 static int ep_gfx_crumbled[] =
4526 static int ep_editor_cascade_active[] =
4528 EL_INTERNAL_CASCADE_BD_ACTIVE,
4529 EL_INTERNAL_CASCADE_EM_ACTIVE,
4530 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4531 EL_INTERNAL_CASCADE_RND_ACTIVE,
4532 EL_INTERNAL_CASCADE_SB_ACTIVE,
4533 EL_INTERNAL_CASCADE_SP_ACTIVE,
4534 EL_INTERNAL_CASCADE_DC_ACTIVE,
4535 EL_INTERNAL_CASCADE_DX_ACTIVE,
4536 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4537 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4538 EL_INTERNAL_CASCADE_CE_ACTIVE,
4539 EL_INTERNAL_CASCADE_GE_ACTIVE,
4540 EL_INTERNAL_CASCADE_REF_ACTIVE,
4541 EL_INTERNAL_CASCADE_USER_ACTIVE,
4542 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4547 static int ep_editor_cascade_inactive[] =
4549 EL_INTERNAL_CASCADE_BD,
4550 EL_INTERNAL_CASCADE_EM,
4551 EL_INTERNAL_CASCADE_EMC,
4552 EL_INTERNAL_CASCADE_RND,
4553 EL_INTERNAL_CASCADE_SB,
4554 EL_INTERNAL_CASCADE_SP,
4555 EL_INTERNAL_CASCADE_DC,
4556 EL_INTERNAL_CASCADE_DX,
4557 EL_INTERNAL_CASCADE_CHARS,
4558 EL_INTERNAL_CASCADE_STEEL_CHARS,
4559 EL_INTERNAL_CASCADE_CE,
4560 EL_INTERNAL_CASCADE_GE,
4561 EL_INTERNAL_CASCADE_REF,
4562 EL_INTERNAL_CASCADE_USER,
4563 EL_INTERNAL_CASCADE_DYNAMIC,
4568 static int ep_obsolete[] =
4572 EL_EM_KEY_1_FILE_OBSOLETE,
4573 EL_EM_KEY_2_FILE_OBSOLETE,
4574 EL_EM_KEY_3_FILE_OBSOLETE,
4575 EL_EM_KEY_4_FILE_OBSOLETE,
4576 EL_ENVELOPE_OBSOLETE,
4585 } element_properties[] =
4587 { ep_diggable, EP_DIGGABLE },
4588 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4589 { ep_dont_run_into, EP_DONT_RUN_INTO },
4590 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4591 { ep_dont_touch, EP_DONT_TOUCH },
4592 { ep_indestructible, EP_INDESTRUCTIBLE },
4593 { ep_slippery, EP_SLIPPERY },
4594 { ep_can_change, EP_CAN_CHANGE },
4595 { ep_can_move, EP_CAN_MOVE },
4596 { ep_can_fall, EP_CAN_FALL },
4597 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4598 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4599 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4600 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4601 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4602 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4603 { ep_walkable_over, EP_WALKABLE_OVER },
4604 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4605 { ep_walkable_under, EP_WALKABLE_UNDER },
4606 { ep_passable_over, EP_PASSABLE_OVER },
4607 { ep_passable_inside, EP_PASSABLE_INSIDE },
4608 { ep_passable_under, EP_PASSABLE_UNDER },
4609 { ep_droppable, EP_DROPPABLE },
4610 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4611 { ep_pushable, EP_PUSHABLE },
4612 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4613 { ep_protected, EP_PROTECTED },
4614 { ep_throwable, EP_THROWABLE },
4615 { ep_can_explode, EP_CAN_EXPLODE },
4616 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4618 { ep_player, EP_PLAYER },
4619 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4620 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4621 { ep_switchable, EP_SWITCHABLE },
4622 { ep_bd_element, EP_BD_ELEMENT },
4623 { ep_sp_element, EP_SP_ELEMENT },
4624 { ep_sb_element, EP_SB_ELEMENT },
4626 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4627 { ep_food_penguin, EP_FOOD_PENGUIN },
4628 { ep_food_pig, EP_FOOD_PIG },
4629 { ep_historic_wall, EP_HISTORIC_WALL },
4630 { ep_historic_solid, EP_HISTORIC_SOLID },
4631 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4632 { ep_belt, EP_BELT },
4633 { ep_belt_active, EP_BELT_ACTIVE },
4634 { ep_belt_switch, EP_BELT_SWITCH },
4635 { ep_tube, EP_TUBE },
4636 { ep_acid_pool, EP_ACID_POOL },
4637 { ep_keygate, EP_KEYGATE },
4638 { ep_amoeboid, EP_AMOEBOID },
4639 { ep_amoebalive, EP_AMOEBALIVE },
4640 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4641 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4642 { ep_can_grow, EP_CAN_GROW },
4643 { ep_active_bomb, EP_ACTIVE_BOMB },
4644 { ep_inactive, EP_INACTIVE },
4646 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4648 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4650 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4651 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4653 { ep_obsolete, EP_OBSOLETE },
4660 /* always start with reliable default values (element has no properties) */
4661 /* (but never initialize clipboard elements after the very first time) */
4662 /* (to be able to use clipboard elements between several levels) */
4663 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4664 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4665 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4666 SET_PROPERTY(i, j, FALSE);
4668 /* set all base element properties from above array definitions */
4669 for (i = 0; element_properties[i].elements != NULL; i++)
4670 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4671 SET_PROPERTY((element_properties[i].elements)[j],
4672 element_properties[i].property, TRUE);
4674 /* copy properties to some elements that are only stored in level file */
4675 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4676 for (j = 0; copy_properties[j][0] != -1; j++)
4677 if (HAS_PROPERTY(copy_properties[j][0], i))
4678 for (k = 1; k <= 4; k++)
4679 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4681 /* set static element properties that are not listed in array definitions */
4682 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4683 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4685 clipboard_elements_initialized = TRUE;
4688 void InitElementPropertiesEngine(int engine_version)
4690 static int no_wall_properties[] =
4693 EP_COLLECTIBLE_ONLY,
4695 EP_DONT_COLLIDE_WITH,
4698 EP_CAN_SMASH_PLAYER,
4699 EP_CAN_SMASH_ENEMIES,
4700 EP_CAN_SMASH_EVERYTHING,
4705 EP_FOOD_DARK_YAMYAM,
4721 /* important: after initialization in InitElementPropertiesStatic(), the
4722 elements are not again initialized to a default value; therefore all
4723 changes have to make sure that they leave the element with a defined
4724 property (which means that conditional property changes must be set to
4725 a reliable default value before) */
4727 /* resolve group elements */
4728 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4729 ResolveGroupElement(EL_GROUP_START + i);
4731 /* set all special, combined or engine dependent element properties */
4732 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4734 /* do not change (already initialized) clipboard elements here */
4735 if (IS_CLIPBOARD_ELEMENT(i))
4738 /* ---------- INACTIVE ------------------------------------------------- */
4739 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4740 i <= EL_CHAR_END) ||
4741 (i >= EL_STEEL_CHAR_START &&
4742 i <= EL_STEEL_CHAR_END)));
4744 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4745 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4746 IS_WALKABLE_INSIDE(i) ||
4747 IS_WALKABLE_UNDER(i)));
4749 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4750 IS_PASSABLE_INSIDE(i) ||
4751 IS_PASSABLE_UNDER(i)));
4753 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4754 IS_PASSABLE_OVER(i)));
4756 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4757 IS_PASSABLE_INSIDE(i)));
4759 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4760 IS_PASSABLE_UNDER(i)));
4762 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4765 /* ---------- COLLECTIBLE ---------------------------------------------- */
4766 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4770 /* ---------- SNAPPABLE ------------------------------------------------ */
4771 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4772 IS_COLLECTIBLE(i) ||
4776 /* ---------- WALL ----------------------------------------------------- */
4777 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4779 for (j = 0; no_wall_properties[j] != -1; j++)
4780 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4781 i >= EL_FIRST_RUNTIME_UNREAL)
4782 SET_PROPERTY(i, EP_WALL, FALSE);
4784 if (IS_HISTORIC_WALL(i))
4785 SET_PROPERTY(i, EP_WALL, TRUE);
4787 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4788 if (engine_version < VERSION_IDENT(2,2,0,0))
4789 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4791 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4793 !IS_COLLECTIBLE(i)));
4795 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4796 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4797 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4799 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4800 IS_INDESTRUCTIBLE(i)));
4802 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4804 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4805 else if (engine_version < VERSION_IDENT(2,2,0,0))
4806 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4808 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4812 if (IS_CUSTOM_ELEMENT(i))
4814 /* these are additional properties which are initially false when set */
4816 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4818 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4819 if (DONT_COLLIDE_WITH(i))
4820 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4822 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4823 if (CAN_SMASH_EVERYTHING(i))
4824 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4825 if (CAN_SMASH_ENEMIES(i))
4826 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4829 /* ---------- CAN_SMASH ------------------------------------------------ */
4830 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4831 CAN_SMASH_ENEMIES(i) ||
4832 CAN_SMASH_EVERYTHING(i)));
4834 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4835 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4836 EXPLODES_BY_FIRE(i)));
4838 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4839 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4840 EXPLODES_SMASHED(i)));
4842 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4843 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4844 EXPLODES_IMPACT(i)));
4846 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4847 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4849 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4850 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4851 i == EL_BLACK_ORB));
4853 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4854 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4856 IS_CUSTOM_ELEMENT(i)));
4858 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4859 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4860 i == EL_SP_ELECTRON));
4862 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4863 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4864 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4865 getMoveIntoAcidProperty(&level, i));
4867 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4868 if (MAYBE_DONT_COLLIDE_WITH(i))
4869 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4870 getDontCollideWithProperty(&level, i));
4872 /* ---------- SP_PORT -------------------------------------------------- */
4873 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4874 IS_PASSABLE_INSIDE(i)));
4876 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4877 for (j = 0; j < level.num_android_clone_elements; j++)
4878 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4880 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4882 /* ---------- CAN_CHANGE ----------------------------------------------- */
4883 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4884 for (j = 0; j < element_info[i].num_change_pages; j++)
4885 if (element_info[i].change_page[j].can_change)
4886 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4888 /* ---------- HAS_ACTION ----------------------------------------------- */
4889 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4890 for (j = 0; j < element_info[i].num_change_pages; j++)
4891 if (element_info[i].change_page[j].has_action)
4892 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4894 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4895 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4898 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4900 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4901 element_info[i].crumbled[ACTION_DEFAULT] !=
4902 element_info[i].graphic[ACTION_DEFAULT]);
4904 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
4905 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4906 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
4909 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4910 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4911 IS_EDITOR_CASCADE_INACTIVE(i)));
4914 /* dynamically adjust element properties according to game engine version */
4916 static int ep_em_slippery_wall[] =
4921 EL_EXPANDABLE_WALL_HORIZONTAL,
4922 EL_EXPANDABLE_WALL_VERTICAL,
4923 EL_EXPANDABLE_WALL_ANY,
4924 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4925 EL_EXPANDABLE_STEELWALL_VERTICAL,
4926 EL_EXPANDABLE_STEELWALL_ANY,
4927 EL_EXPANDABLE_STEELWALL_GROWING,
4931 static int ep_em_explodes_by_fire[] =
4934 EL_EM_DYNAMITE_ACTIVE,
4939 /* special EM style gems behaviour */
4940 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4941 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4942 level.em_slippery_gems);
4944 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4945 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4946 (level.em_slippery_gems &&
4947 engine_version > VERSION_IDENT(2,0,1,0)));
4949 /* special EM style explosion behaviour regarding chain reactions */
4950 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4951 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4952 level.em_explodes_by_fire);
4955 /* this is needed because some graphics depend on element properties */
4956 if (game_status == GAME_MODE_PLAYING)
4957 InitElementGraphicInfo();
4960 void InitElementPropertiesAfterLoading(int engine_version)
4964 /* set some other uninitialized values of custom elements in older levels */
4965 if (engine_version < VERSION_IDENT(3,1,0,0))
4967 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4969 int element = EL_CUSTOM_START + i;
4971 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4973 element_info[element].explosion_delay = 17;
4974 element_info[element].ignition_delay = 8;
4979 void InitElementPropertiesGfxElement()
4983 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4985 struct ElementInfo *ei = &element_info[i];
4987 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4991 static void InitGlobal()
4996 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4998 /* check if element_name_info entry defined for each element in "main.h" */
4999 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
5000 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
5002 element_info[i].token_name = element_name_info[i].token_name;
5003 element_info[i].class_name = element_name_info[i].class_name;
5004 element_info[i].editor_description= element_name_info[i].editor_description;
5007 printf("%04d: %s\n", i, element_name_info[i].token_name);
5011 /* create hash from image config list */
5012 image_config_hash = newSetupFileHash();
5013 for (i = 0; image_config[i].token != NULL; i++)
5014 setHashEntry(image_config_hash,
5015 image_config[i].token,
5016 image_config[i].value);
5018 /* create hash from element token list */
5019 element_token_hash = newSetupFileHash();
5020 for (i = 0; element_name_info[i].token_name != NULL; i++)
5021 setHashEntry(element_token_hash,
5022 element_name_info[i].token_name,
5025 /* create hash from graphic token list */
5026 graphic_token_hash = newSetupFileHash();
5027 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
5028 if (strSuffix(image_config[i].value, ".png") ||
5029 strSuffix(image_config[i].value, ".pcx") ||
5030 strSuffix(image_config[i].value, ".wav") ||
5031 strEqual(image_config[i].value, UNDEFINED_FILENAME))
5032 setHashEntry(graphic_token_hash,
5033 image_config[i].token,
5034 int2str(graphic++, 0));
5036 /* create hash from font token list */
5037 font_token_hash = newSetupFileHash();
5038 for (i = 0; font_info[i].token_name != NULL; i++)
5039 setHashEntry(font_token_hash,
5040 font_info[i].token_name,
5043 /* always start with reliable default values (all elements) */
5044 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5045 ActiveElement[i] = i;
5047 /* now add all entries that have an active state (active elements) */
5048 for (i = 0; element_with_active_state[i].element != -1; i++)
5050 int element = element_with_active_state[i].element;
5051 int element_active = element_with_active_state[i].element_active;
5053 ActiveElement[element] = element_active;
5056 /* always start with reliable default values (all buttons) */
5057 for (i = 0; i < NUM_IMAGE_FILES; i++)
5058 ActiveButton[i] = i;
5060 /* now add all entries that have an active state (active buttons) */
5061 for (i = 0; button_with_active_state[i].button != -1; i++)
5063 int button = button_with_active_state[i].button;
5064 int button_active = button_with_active_state[i].button_active;
5066 ActiveButton[button] = button_active;
5069 /* always start with reliable default values (all fonts) */
5070 for (i = 0; i < NUM_FONTS; i++)
5073 /* now add all entries that have an active state (active fonts) */
5074 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
5076 int font = font_with_active_state[i].font_nr;
5077 int font_active = font_with_active_state[i].font_nr_active;
5079 ActiveFont[font] = font_active;
5082 global.autoplay_leveldir = NULL;
5083 global.convert_leveldir = NULL;
5084 global.create_images_dir = NULL;
5086 global.frames_per_second = 0;
5087 global.fps_slowdown = FALSE;
5088 global.fps_slowdown_factor = 1;
5090 global.border_status = GAME_MODE_MAIN;
5092 global.fading_status = GAME_MODE_MAIN;
5093 global.fading_type = TYPE_ENTER_MENU;
5096 global.use_envelope_request = FALSE;
5099 void Execute_Command(char *command)
5103 if (strEqual(command, "print graphicsinfo.conf"))
5105 printf("# You can configure additional/alternative image files here.\n");
5106 printf("# (The entries below are default and therefore commented out.)\n");
5108 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
5110 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5113 for (i = 0; image_config[i].token != NULL; i++)
5114 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
5115 image_config[i].value));
5119 else if (strEqual(command, "print soundsinfo.conf"))
5121 printf("# You can configure additional/alternative sound files here.\n");
5122 printf("# (The entries below are default and therefore commented out.)\n");
5124 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
5126 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5129 for (i = 0; sound_config[i].token != NULL; i++)
5130 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
5131 sound_config[i].value));
5135 else if (strEqual(command, "print musicinfo.conf"))
5137 printf("# You can configure additional/alternative music files here.\n");
5138 printf("# (The entries below are default and therefore commented out.)\n");
5140 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
5142 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5145 for (i = 0; music_config[i].token != NULL; i++)
5146 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
5147 music_config[i].value));
5151 else if (strEqual(command, "print editorsetup.conf"))
5153 printf("# You can configure your personal editor element list here.\n");
5154 printf("# (The entries below are default and therefore commented out.)\n");
5157 /* this is needed to be able to check element list for cascade elements */
5158 InitElementPropertiesStatic();
5159 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5161 PrintEditorElementList();
5165 else if (strEqual(command, "print helpanim.conf"))
5167 printf("# You can configure different element help animations here.\n");
5168 printf("# (The entries below are default and therefore commented out.)\n");
5171 for (i = 0; helpanim_config[i].token != NULL; i++)
5173 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
5174 helpanim_config[i].value));
5176 if (strEqual(helpanim_config[i].token, "end"))
5182 else if (strEqual(command, "print helptext.conf"))
5184 printf("# You can configure different element help text here.\n");
5185 printf("# (The entries below are default and therefore commented out.)\n");
5188 for (i = 0; helptext_config[i].token != NULL; i++)
5189 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
5190 helptext_config[i].value));
5194 else if (strPrefix(command, "dump level "))
5196 char *filename = &command[11];
5198 if (!fileExists(filename))
5199 Error(ERR_EXIT, "cannot open file '%s'", filename);
5201 LoadLevelFromFilename(&level, filename);
5206 else if (strPrefix(command, "dump tape "))
5208 char *filename = &command[10];
5210 if (!fileExists(filename))
5211 Error(ERR_EXIT, "cannot open file '%s'", filename);
5213 LoadTapeFromFilename(filename);
5218 else if (strPrefix(command, "autoplay "))
5220 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
5222 while (*str_ptr != '\0') /* continue parsing string */
5224 /* cut leading whitespace from string, replace it by string terminator */
5225 while (*str_ptr == ' ' || *str_ptr == '\t')
5228 if (*str_ptr == '\0') /* end of string reached */
5231 if (global.autoplay_leveldir == NULL) /* read level set string */
5233 global.autoplay_leveldir = str_ptr;
5234 global.autoplay_all = TRUE; /* default: play all tapes */
5236 for (i = 0; i < MAX_TAPES_PER_SET; i++)
5237 global.autoplay_level[i] = FALSE;
5239 else /* read level number string */
5241 int level_nr = atoi(str_ptr); /* get level_nr value */
5243 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5244 global.autoplay_level[level_nr] = TRUE;
5246 global.autoplay_all = FALSE;
5249 /* advance string pointer to the next whitespace (or end of string) */
5250 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5254 else if (strPrefix(command, "convert "))
5256 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
5257 char *str_ptr = strchr(str_copy, ' ');
5259 global.convert_leveldir = str_copy;
5260 global.convert_level_nr = -1;
5262 if (str_ptr != NULL) /* level number follows */
5264 *str_ptr++ = '\0'; /* terminate leveldir string */
5265 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
5268 else if (strPrefix(command, "create images "))
5270 #if defined(TARGET_SDL)
5271 global.create_images_dir = getStringCopy(&command[14]);
5273 if (access(global.create_images_dir, W_OK) != 0)
5274 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
5275 global.create_images_dir);
5277 Error(ERR_EXIT, "command only available for SDL target");
5282 #if defined(TARGET_SDL2)
5283 else if (strEqual(command, "SDL_ListModes"))
5285 SDL_Init(SDL_INIT_VIDEO);
5287 int num_displays = SDL_GetNumVideoDisplays();
5289 // check if there are any displays available
5290 if (num_displays < 0)
5292 printf("No displays available: %s\n", SDL_GetError());
5297 for (i = 0; i < num_displays; i++)
5299 int num_modes = SDL_GetNumDisplayModes(i);
5302 printf("Available display modes for display %d:\n", i);
5304 // check if there are any display modes available for this display
5307 printf("No display modes available for display %d: %s\n",
5313 for (j = 0; j < num_modes; j++)
5315 SDL_DisplayMode mode;
5317 if (SDL_GetDisplayMode(i, j, &mode) < 0)
5319 printf("Cannot get display mode %d for display %d: %s\n",
5320 j, i, SDL_GetError());
5325 printf("- %d x %d\n", mode.w, mode.h);
5331 #elif defined(TARGET_SDL)
5332 else if (strEqual(command, "SDL_ListModes"))
5337 SDL_Init(SDL_INIT_VIDEO);
5339 /* get available fullscreen/hardware modes */
5340 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
5342 /* check if there are any modes available */
5345 printf("No modes available!\n");
5350 /* check if our resolution is restricted */
5351 if (modes == (SDL_Rect **)-1)
5353 printf("All resolutions available.\n");
5357 printf("Available display modes:\n");
5359 for (i = 0; modes[i]; i++)
5360 printf("- %d x %d\n", modes[i]->w, modes[i]->h);
5370 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
5374 static void InitSetup()
5376 LoadSetup(); /* global setup info */
5378 /* set some options from setup file */
5380 if (setup.options.verbose)
5381 options.verbose = TRUE;
5384 static void InitGameInfo()
5386 game.restart_level = FALSE;
5389 static void InitPlayerInfo()
5393 /* choose default local player */
5394 local_player = &stored_player[0];
5396 for (i = 0; i < MAX_PLAYERS; i++)
5397 stored_player[i].connected = FALSE;
5399 local_player->connected = TRUE;
5402 static void InitArtworkInfo()
5407 static char *get_string_in_brackets(char *string)
5409 char *string_in_brackets = checked_malloc(strlen(string) + 3);
5411 sprintf(string_in_brackets, "[%s]", string);
5413 return string_in_brackets;
5416 static char *get_level_id_suffix(int id_nr)
5418 char *id_suffix = checked_malloc(1 + 3 + 1);
5420 if (id_nr < 0 || id_nr > 999)
5423 sprintf(id_suffix, ".%03d", id_nr);
5429 static char *get_element_class_token(int element)
5431 char *element_class_name = element_info[element].class_name;
5432 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
5434 sprintf(element_class_token, "[%s]", element_class_name);
5436 return element_class_token;
5439 static char *get_action_class_token(int action)
5441 char *action_class_name = &element_action_info[action].suffix[1];
5442 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
5444 sprintf(action_class_token, "[%s]", action_class_name);
5446 return action_class_token;
5450 static void InitArtworkConfig()
5452 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
5453 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
5454 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
5455 static char *action_id_suffix[NUM_ACTIONS + 1];
5456 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5457 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5458 static char *level_id_suffix[MAX_LEVELS + 1];
5459 static char *dummy[1] = { NULL };
5460 static char *ignore_generic_tokens[] =
5466 static char **ignore_image_tokens;
5467 static char **ignore_sound_tokens;
5468 static char **ignore_music_tokens;
5469 int num_ignore_generic_tokens;
5470 int num_ignore_image_tokens;
5471 int num_ignore_sound_tokens;
5472 int num_ignore_music_tokens;
5475 /* dynamically determine list of generic tokens to be ignored */
5476 num_ignore_generic_tokens = 0;
5477 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5478 num_ignore_generic_tokens++;
5480 /* dynamically determine list of image tokens to be ignored */
5481 num_ignore_image_tokens = num_ignore_generic_tokens;
5482 for (i = 0; image_config_vars[i].token != NULL; i++)
5483 num_ignore_image_tokens++;
5484 ignore_image_tokens =
5485 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5486 for (i = 0; i < num_ignore_generic_tokens; i++)
5487 ignore_image_tokens[i] = ignore_generic_tokens[i];
5488 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5489 ignore_image_tokens[num_ignore_generic_tokens + i] =
5490 image_config_vars[i].token;
5491 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5493 /* dynamically determine list of sound tokens to be ignored */
5494 num_ignore_sound_tokens = num_ignore_generic_tokens;
5495 ignore_sound_tokens =
5496 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5497 for (i = 0; i < num_ignore_generic_tokens; i++)
5498 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5499 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5501 /* dynamically determine list of music tokens to be ignored */
5502 num_ignore_music_tokens = num_ignore_generic_tokens;
5503 ignore_music_tokens =
5504 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5505 for (i = 0; i < num_ignore_generic_tokens; i++)
5506 ignore_music_tokens[i] = ignore_generic_tokens[i];
5507 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5509 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5510 image_id_prefix[i] = element_info[i].token_name;
5511 for (i = 0; i < NUM_FONTS; i++)
5512 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5513 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
5515 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5516 sound_id_prefix[i] = element_info[i].token_name;
5517 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5518 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5519 get_string_in_brackets(element_info[i].class_name);
5520 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
5522 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5523 music_id_prefix[i] = music_prefix_info[i].prefix;
5524 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
5526 for (i = 0; i < NUM_ACTIONS; i++)
5527 action_id_suffix[i] = element_action_info[i].suffix;
5528 action_id_suffix[NUM_ACTIONS] = NULL;
5530 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5531 direction_id_suffix[i] = element_direction_info[i].suffix;
5532 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5534 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5535 special_id_suffix[i] = special_suffix_info[i].suffix;
5536 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5538 for (i = 0; i < MAX_LEVELS; i++)
5539 level_id_suffix[i] = get_level_id_suffix(i);
5540 level_id_suffix[MAX_LEVELS] = NULL;
5542 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5543 image_id_prefix, action_id_suffix, direction_id_suffix,
5544 special_id_suffix, ignore_image_tokens);
5545 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5546 sound_id_prefix, action_id_suffix, dummy,
5547 special_id_suffix, ignore_sound_tokens);
5548 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5549 music_id_prefix, special_id_suffix, level_id_suffix,
5550 dummy, ignore_music_tokens);
5553 static void InitMixer()
5560 void InitGfxBuffers()
5562 /* create additional image buffers for double-buffering and cross-fading */
5563 ReCreateBitmap(&bitmap_db_store, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5564 ReCreateBitmap(&bitmap_db_cross, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5565 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE, DEFAULT_DEPTH);
5566 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE, DEFAULT_DEPTH);
5568 ReCreateBitmap(&bitmap_db_door, 3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
5570 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE, DEFAULT_DEPTH);
5571 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE, DEFAULT_DEPTH);
5572 ReCreateBitmap(&bitmap_db_toons, FULL_SXSIZE, FULL_SYSIZE, DEFAULT_DEPTH);
5574 /* initialize screen properties */
5575 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5576 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5578 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5579 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5580 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5581 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5582 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5583 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5585 InitGfxBuffers_EM();
5586 InitGfxBuffers_SP();
5591 struct GraphicInfo *graphic_info_last = graphic_info;
5592 char *filename_font_initial = NULL;
5593 char *filename_anim_initial = NULL;
5594 Bitmap *bitmap_font_initial = NULL;
5598 /* determine settings for initial font (for displaying startup messages) */
5599 for (i = 0; image_config[i].token != NULL; i++)
5601 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5603 char font_token[128];
5606 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5607 len_font_token = strlen(font_token);
5609 if (strEqual(image_config[i].token, font_token))
5610 filename_font_initial = image_config[i].value;
5611 else if (strlen(image_config[i].token) > len_font_token &&
5612 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5614 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5615 font_initial[j].src_x = atoi(image_config[i].value);
5616 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5617 font_initial[j].src_y = atoi(image_config[i].value);
5618 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5619 font_initial[j].width = atoi(image_config[i].value);
5620 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5621 font_initial[j].height = atoi(image_config[i].value);
5626 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5628 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5629 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5632 if (filename_font_initial == NULL) /* should not happen */
5633 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5636 InitGfxCustomArtworkInfo();
5638 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5640 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5641 font_initial[j].bitmap = bitmap_font_initial;
5643 InitFontGraphicInfo();
5645 font_height = getFontHeight(FC_RED);
5648 DrawInitTextAlways(getWindowTitleString(), 20, FC_YELLOW);
5650 DrawInitTextAlways(getProgramInitString(), 20, FC_YELLOW);
5652 DrawInitTextAlways(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
5653 DrawInitTextAlways(PROGRAM_WEBSITE_STRING, WIN_YSIZE - 20 - font_height,
5656 DrawInitTextAlways("Loading graphics", 120, FC_GREEN);
5660 /* initialize busy animation with default values */
5661 int parameter[NUM_GFX_ARGS];
5662 for (i = 0; i < NUM_GFX_ARGS; i++)
5663 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5664 image_config_suffix[i].token,
5665 image_config_suffix[i].type);
5667 for (i = 0; i < NUM_GFX_ARGS; i++)
5668 printf("::: '%s' => %d\n", image_config_suffix[i].token, parameter[i]);
5672 /* determine settings for busy animation (when displaying startup messages) */
5673 for (i = 0; image_config[i].token != NULL; i++)
5675 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5676 int len_anim_token = strlen(anim_token);
5678 if (strEqual(image_config[i].token, anim_token))
5679 filename_anim_initial = image_config[i].value;
5680 else if (strlen(image_config[i].token) > len_anim_token &&
5681 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5684 for (j = 0; image_config_suffix[j].token != NULL; j++)
5686 if (strEqual(&image_config[i].token[len_anim_token],
5687 image_config_suffix[j].token))
5689 get_graphic_parameter_value(image_config[i].value,
5690 image_config_suffix[j].token,
5691 image_config_suffix[j].type);
5694 if (strEqual(&image_config[i].token[len_anim_token], ".x"))
5695 anim_initial.src_x = atoi(image_config[i].value);
5696 else if (strEqual(&image_config[i].token[len_anim_token], ".y"))
5697 anim_initial.src_y = atoi(image_config[i].value);
5698 else if (strEqual(&image_config[i].token[len_anim_token], ".width"))
5699 anim_initial.width = atoi(image_config[i].value);
5700 else if (strEqual(&image_config[i].token[len_anim_token], ".height"))
5701 anim_initial.height = atoi(image_config[i].value);
5702 else if (strEqual(&image_config[i].token[len_anim_token], ".frames"))
5703 anim_initial.anim_frames = atoi(image_config[i].value);
5704 else if (strEqual(&image_config[i].token[len_anim_token],
5705 ".frames_per_line"))
5706 anim_initial.anim_frames_per_line = atoi(image_config[i].value);
5707 else if (strEqual(&image_config[i].token[len_anim_token], ".delay"))
5708 anim_initial.anim_delay = atoi(image_config[i].value);
5713 #if defined(CREATE_SPECIAL_EDITION_RND_JUE)
5714 filename_anim_initial = "loading.pcx";
5716 parameter[GFX_ARG_X] = 0;
5717 parameter[GFX_ARG_Y] = 0;
5718 parameter[GFX_ARG_WIDTH] = 128;
5719 parameter[GFX_ARG_HEIGHT] = 40;
5720 parameter[GFX_ARG_FRAMES] = 32;
5721 parameter[GFX_ARG_DELAY] = 4;
5722 parameter[GFX_ARG_FRAMES_PER_LINE] = ARG_UNDEFINED_VALUE;
5725 if (filename_anim_initial == NULL) /* should not happen */
5726 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5728 anim_initial.bitmap = LoadCustomImage(filename_anim_initial);
5730 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
5732 set_graphic_parameters_ext(0, parameter, anim_initial.bitmap);
5735 printf("::: INIT_GFX: anim_frames_per_line == %d [%d / %d] [%d, %d]\n",
5736 graphic_info[0].anim_frames_per_line,
5737 get_scaled_graphic_width(0),
5738 graphic_info[0].width,
5739 getOriginalImageWidthFromImageID(0),
5740 graphic_info[0].scale_up_factor);
5743 graphic_info = graphic_info_last;
5745 init.busy.width = anim_initial.width;
5746 init.busy.height = anim_initial.height;
5748 InitMenuDesignSettings_Static();
5749 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5751 /* use copy of busy animation to prevent change while reloading artwork */
5756 void RedrawBackground()
5758 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
5759 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
5761 redraw_mask = REDRAW_ALL;
5764 void InitGfxBackground()
5768 fieldbuffer = bitmap_db_field;
5769 SetDrawtoField(DRAW_BACKBUFFER);
5772 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5776 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
5777 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
5780 for (x = 0; x < MAX_BUF_XSIZE; x++)
5781 for (y = 0; y < MAX_BUF_YSIZE; y++)
5784 redraw_mask = REDRAW_ALL;
5787 static void InitLevelInfo()
5789 LoadLevelInfo(); /* global level info */
5790 LoadLevelSetup_LastSeries(); /* last played series info */
5791 LoadLevelSetup_SeriesInfo(); /* last played level info */
5794 static void InitLevelArtworkInfo()
5796 LoadLevelArtworkInfo();
5799 static void InitImages()
5801 print_timestamp_init("InitImages");
5804 printf("::: leveldir_current->identifier == '%s'\n",
5805 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5806 printf("::: leveldir_current->graphics_path == '%s'\n",
5807 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5808 printf("::: leveldir_current->graphics_set == '%s'\n",
5809 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5810 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5811 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5814 setLevelArtworkDir(artwork.gfx_first);
5817 printf("::: leveldir_current->identifier == '%s'\n",
5818 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5819 printf("::: leveldir_current->graphics_path == '%s'\n",
5820 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5821 printf("::: leveldir_current->graphics_set == '%s'\n",
5822 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5823 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5824 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5828 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5829 leveldir_current->identifier,
5830 artwork.gfx_current_identifier,
5831 artwork.gfx_current->identifier,
5832 leveldir_current->graphics_set,
5833 leveldir_current->graphics_path);
5836 UPDATE_BUSY_STATE();
5838 ReloadCustomImages();
5839 print_timestamp_time("ReloadCustomImages");
5841 UPDATE_BUSY_STATE();
5843 LoadCustomElementDescriptions();
5844 print_timestamp_time("LoadCustomElementDescriptions");
5846 UPDATE_BUSY_STATE();
5848 LoadMenuDesignSettings();
5849 print_timestamp_time("LoadMenuDesignSettings");
5851 UPDATE_BUSY_STATE();
5853 ReinitializeGraphics();
5854 print_timestamp_time("ReinitializeGraphics");
5856 UPDATE_BUSY_STATE();
5858 print_timestamp_done("InitImages");
5861 static void InitSound(char *identifier)
5863 print_timestamp_init("InitSound");
5865 if (identifier == NULL)
5866 identifier = artwork.snd_current->identifier;
5868 /* set artwork path to send it to the sound server process */
5869 setLevelArtworkDir(artwork.snd_first);
5871 InitReloadCustomSounds(identifier);
5872 print_timestamp_time("InitReloadCustomSounds");
5874 ReinitializeSounds();
5875 print_timestamp_time("ReinitializeSounds");
5877 print_timestamp_done("InitSound");
5880 static void InitMusic(char *identifier)
5882 print_timestamp_init("InitMusic");
5884 if (identifier == NULL)
5885 identifier = artwork.mus_current->identifier;
5887 /* set artwork path to send it to the sound server process */
5888 setLevelArtworkDir(artwork.mus_first);
5890 InitReloadCustomMusic(identifier);
5891 print_timestamp_time("InitReloadCustomMusic");
5893 ReinitializeMusic();
5894 print_timestamp_time("ReinitializeMusic");
5896 print_timestamp_done("InitMusic");
5899 void InitNetworkServer()
5901 #if defined(NETWORK_AVALIABLE)
5905 if (!options.network)
5908 #if defined(NETWORK_AVALIABLE)
5909 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5911 if (!ConnectToServer(options.server_host, options.server_port))
5912 Error(ERR_EXIT, "cannot connect to network game server");
5914 SendToServer_PlayerName(setup.player_name);
5915 SendToServer_ProtocolVersion();
5918 SendToServer_NrWanted(nr_wanted);
5922 static boolean CheckArtworkConfigForCustomElements(char *filename)
5924 SetupFileHash *setup_file_hash;
5925 boolean redefined_ce_found = FALSE;
5927 /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */
5929 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5931 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5933 char *token = HASH_ITERATION_TOKEN(itr);
5935 if (strPrefix(token, "custom_"))
5937 redefined_ce_found = TRUE;
5942 END_HASH_ITERATION(setup_file_hash, itr)
5944 freeSetupFileHash(setup_file_hash);
5947 return redefined_ce_found;
5950 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5952 char *filename_base, *filename_local;
5953 boolean redefined_ce_found = FALSE;
5955 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5958 printf("::: leveldir_current->identifier == '%s'\n",
5959 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5960 printf("::: leveldir_current->graphics_path == '%s'\n",
5961 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5962 printf("::: leveldir_current->graphics_set == '%s'\n",
5963 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5964 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5965 leveldir_current == NULL ? "[NULL]" :
5966 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5969 /* first look for special artwork configured in level series config */
5970 filename_base = getCustomArtworkLevelConfigFilename(type);
5973 printf("::: filename_base == '%s'\n", filename_base);
5976 if (fileExists(filename_base))
5977 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5979 filename_local = getCustomArtworkConfigFilename(type);
5982 printf("::: filename_local == '%s'\n", filename_local);
5985 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5986 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5989 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5992 return redefined_ce_found;
5995 static void InitOverrideArtwork()
5997 boolean redefined_ce_found = FALSE;
5999 /* to check if this level set redefines any CEs, do not use overriding */
6000 gfx.override_level_graphics = FALSE;
6001 gfx.override_level_sounds = FALSE;
6002 gfx.override_level_music = FALSE;
6004 /* now check if this level set has definitions for custom elements */
6005 if (setup.override_level_graphics == AUTO ||
6006 setup.override_level_sounds == AUTO ||
6007 setup.override_level_music == AUTO)
6008 redefined_ce_found =
6009 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
6010 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
6011 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
6014 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
6017 if (redefined_ce_found)
6019 /* this level set has CE definitions: change "AUTO" to "FALSE" */
6020 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
6021 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
6022 gfx.override_level_music = (setup.override_level_music == TRUE);
6026 /* this level set has no CE definitions: change "AUTO" to "TRUE" */
6027 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
6028 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
6029 gfx.override_level_music = (setup.override_level_music != FALSE);
6033 printf("::: => %d, %d, %d\n",
6034 gfx.override_level_graphics,
6035 gfx.override_level_sounds,
6036 gfx.override_level_music);
6040 static char *getNewArtworkIdentifier(int type)
6042 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
6043 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
6044 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
6045 static boolean initialized[3] = { FALSE, FALSE, FALSE };
6046 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
6048 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
6050 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
6052 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
6053 char *leveldir_identifier = leveldir_current->identifier;
6055 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
6056 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
6058 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
6060 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
6061 char *artwork_current_identifier;
6062 char *artwork_new_identifier = NULL; /* default: nothing has changed */
6064 /* leveldir_current may be invalid (level group, parent link) */
6065 if (!validLevelSeries(leveldir_current))
6068 /* 1st step: determine artwork set to be activated in descending order:
6069 --------------------------------------------------------------------
6070 1. setup artwork (when configured to override everything else)
6071 2. artwork set configured in "levelinfo.conf" of current level set
6072 (artwork in level directory will have priority when loading later)
6073 3. artwork in level directory (stored in artwork sub-directory)
6074 4. setup artwork (currently configured in setup menu) */
6076 if (setup_override_artwork)
6077 artwork_current_identifier = setup_artwork_set;
6078 else if (leveldir_artwork_set != NULL)
6079 artwork_current_identifier = leveldir_artwork_set;
6080 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
6081 artwork_current_identifier = leveldir_identifier;
6083 artwork_current_identifier = setup_artwork_set;
6086 /* 2nd step: check if it is really needed to reload artwork set
6087 ------------------------------------------------------------ */
6090 if (type == ARTWORK_TYPE_GRAPHICS)
6091 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
6092 artwork_new_identifier,
6093 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
6094 artwork_current_identifier,
6095 leveldir_current->graphics_set,
6096 leveldir_current->identifier);
6099 /* ---------- reload if level set and also artwork set has changed ------- */
6100 if (leveldir_current_identifier[type] != leveldir_identifier &&
6101 (last_has_level_artwork_set[type] || has_level_artwork_set))
6102 artwork_new_identifier = artwork_current_identifier;
6104 leveldir_current_identifier[type] = leveldir_identifier;
6105 last_has_level_artwork_set[type] = has_level_artwork_set;
6108 if (type == ARTWORK_TYPE_GRAPHICS)
6109 printf("::: 1: '%s'\n", artwork_new_identifier);
6112 /* ---------- reload if "override artwork" setting has changed ----------- */
6113 if (last_override_level_artwork[type] != setup_override_artwork)
6114 artwork_new_identifier = artwork_current_identifier;
6116 last_override_level_artwork[type] = setup_override_artwork;
6119 if (type == ARTWORK_TYPE_GRAPHICS)
6120 printf("::: 2: '%s'\n", artwork_new_identifier);
6123 /* ---------- reload if current artwork identifier has changed ----------- */
6124 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
6125 artwork_current_identifier))
6126 artwork_new_identifier = artwork_current_identifier;
6128 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
6131 if (type == ARTWORK_TYPE_GRAPHICS)
6132 printf("::: 3: '%s'\n", artwork_new_identifier);
6135 /* ---------- do not reload directly after starting ---------------------- */
6136 if (!initialized[type])
6137 artwork_new_identifier = NULL;
6139 initialized[type] = TRUE;
6142 if (type == ARTWORK_TYPE_GRAPHICS)
6143 printf("::: 4: '%s'\n", artwork_new_identifier);
6147 if (type == ARTWORK_TYPE_GRAPHICS)
6148 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
6149 artwork.gfx_current_identifier, artwork_current_identifier,
6150 artwork.gfx_current->identifier, leveldir_current->graphics_set,
6151 artwork_new_identifier);
6154 return artwork_new_identifier;
6157 void ReloadCustomArtwork(int force_reload)
6159 int last_game_status = game_status; /* save current game status */
6160 char *gfx_new_identifier;
6161 char *snd_new_identifier;
6162 char *mus_new_identifier;
6163 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
6164 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
6165 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
6166 boolean reload_needed;
6168 InitOverrideArtwork();
6170 force_reload_gfx |= AdjustGraphicsForEMC();
6172 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
6173 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
6174 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
6176 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
6177 snd_new_identifier != NULL || force_reload_snd ||
6178 mus_new_identifier != NULL || force_reload_mus);
6183 print_timestamp_init("ReloadCustomArtwork");
6185 game_status = GAME_MODE_LOADING;
6187 FadeOut(REDRAW_ALL);
6190 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6192 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
6194 print_timestamp_time("ClearRectangle");
6197 printf("::: fading in ... %d\n", fading.fade_mode);
6201 printf("::: done\n");
6204 if (gfx_new_identifier != NULL || force_reload_gfx)
6207 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
6208 artwork.gfx_current_identifier,
6210 artwork.gfx_current->identifier,
6211 leveldir_current->graphics_set);
6215 print_timestamp_time("InitImages");
6218 if (snd_new_identifier != NULL || force_reload_snd)
6220 InitSound(snd_new_identifier);
6221 print_timestamp_time("InitSound");
6224 if (mus_new_identifier != NULL || force_reload_mus)
6226 InitMusic(mus_new_identifier);
6227 print_timestamp_time("InitMusic");
6230 game_status = last_game_status; /* restore current game status */
6232 init_last = init; /* switch to new busy animation */
6235 printf("::: ----------------DELAY 1 ...\n");
6240 printf("::: FadeOut @ ReloadCustomArtwork ...\n");
6242 FadeOut(REDRAW_ALL);
6244 printf("::: FadeOut @ ReloadCustomArtwork done\n");
6249 /* force redraw of (open or closed) door graphics */
6250 SetDoorState(DOOR_OPEN_ALL);
6251 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
6256 FadeSetEnterScreen();
6257 FadeSkipNextFadeOut();
6258 // FadeSetDisabled();
6263 fading = fading_none;
6268 redraw_mask = REDRAW_ALL;
6271 print_timestamp_done("ReloadCustomArtwork");
6273 LimitScreenUpdates(FALSE);
6276 void KeyboardAutoRepeatOffUnlessAutoplay()
6278 if (global.autoplay_leveldir == NULL)
6279 KeyboardAutoRepeatOff();
6282 void DisplayExitMessage(char *format, va_list ap)
6284 // check if draw buffer and fonts for exit message are already available
6285 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
6288 int font_1 = FC_RED;
6289 int font_2 = FC_YELLOW;
6290 int font_3 = FC_BLUE;
6291 int font_width = getFontWidth(font_2);
6292 int font_height = getFontHeight(font_2);
6295 int sxsize = WIN_XSIZE - 2 * sx;
6296 int sysize = WIN_YSIZE - 2 * sy;
6297 int line_length = sxsize / font_width;
6298 int max_lines = sysize / font_height;
6299 int num_lines_printed;
6303 gfx.sxsize = sxsize;
6304 gfx.sysize = sysize;
6308 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6310 DrawTextSCentered(sy, font_1, "Fatal error:");
6311 sy += 3 * font_height;;
6314 DrawTextBufferVA(sx, sy, format, ap, font_2,
6315 line_length, line_length, max_lines,
6316 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6317 sy += (num_lines_printed + 3) * font_height;
6319 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
6320 sy += 3 * font_height;
6323 DrawTextBuffer(sx, sy, program.error_filename, font_2,
6324 line_length, line_length, max_lines,
6325 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6327 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
6329 redraw_mask = REDRAW_ALL;
6333 /* deactivate toons on error message screen */
6334 setup.toons = FALSE;
6336 WaitForEventToContinue();
6340 /* ========================================================================= */
6342 /* ========================================================================= */
6346 print_timestamp_init("OpenAll");
6348 game_status = GAME_MODE_LOADING;
6354 InitGlobal(); /* initialize some global variables */
6356 print_timestamp_time("[init global stuff]");
6358 if (options.execute_command)
6359 Execute_Command(options.execute_command);
6361 if (options.serveronly)
6363 #if defined(PLATFORM_UNIX)
6364 NetworkServer(options.server_port, options.serveronly);
6366 Error(ERR_WARN, "networking only supported in Unix version");
6369 exit(0); /* never reached, server loops forever */
6374 print_timestamp_time("[init setup/config stuff (1)]");
6377 print_timestamp_time("[init setup/config stuff (2)]");
6379 print_timestamp_time("[init setup/config stuff (3)]");
6380 InitArtworkInfo(); /* needed before loading gfx, sound & music */
6381 print_timestamp_time("[init setup/config stuff (4)]");
6382 InitArtworkConfig(); /* needed before forking sound child process */
6383 print_timestamp_time("[init setup/config stuff (5)]");
6385 print_timestamp_time("[init setup/config stuff (6)]");
6391 InitRND(NEW_RANDOMIZE);
6392 InitSimpleRandom(NEW_RANDOMIZE);
6396 print_timestamp_time("[init setup/config stuff]");
6399 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
6401 InitEventFilter(FilterEvents);
6403 print_timestamp_time("[init video stuff]");
6405 InitElementPropertiesStatic();
6406 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
6407 InitElementPropertiesGfxElement();
6409 print_timestamp_time("[init element properties stuff]");
6413 print_timestamp_time("InitGfx");
6416 print_timestamp_time("InitLevelInfo");
6418 InitLevelArtworkInfo();
6419 print_timestamp_time("InitLevelArtworkInfo");
6421 InitOverrideArtwork(); /* needs to know current level directory */
6422 print_timestamp_time("InitOverrideArtwork");
6424 InitImages(); /* needs to know current level directory */
6425 print_timestamp_time("InitImages");
6427 InitSound(NULL); /* needs to know current level directory */
6428 print_timestamp_time("InitSound");
6430 InitMusic(NULL); /* needs to know current level directory */
6431 print_timestamp_time("InitMusic");
6433 InitGfxBackground();
6443 if (global.autoplay_leveldir)
6448 else if (global.convert_leveldir)
6453 else if (global.create_images_dir)
6455 CreateLevelSketchImages();
6459 game_status = GAME_MODE_MAIN;
6462 FadeSetEnterScreen();
6463 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
6464 FadeSkipNextFadeOut();
6465 // FadeSetDisabled();
6467 fading = fading_none;
6470 print_timestamp_time("[post-artwork]");
6472 print_timestamp_done("OpenAll");
6476 InitNetworkServer();
6479 Error(ERR_DEBUG, "::: SDL_GetBasePath() == '%s'",
6481 Error(ERR_DEBUG, "::: SDL_GetPrefPath() == '%s'",
6482 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
6483 #if defined(PLATFORM_ANDROID)
6484 Error(ERR_DEBUG, "::: SDL_AndroidGetInternalStoragePath() == '%s'",
6485 SDL_AndroidGetInternalStoragePath());
6486 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStoragePath() == '%s'",
6487 SDL_AndroidGetExternalStoragePath());
6488 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStorageState() == '%s'",
6489 (SDL_AndroidGetExternalStorageState() ==
6490 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "read" :
6491 SDL_AndroidGetExternalStorageState() ==
6492 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "write" : "not available"));
6497 void CloseAllAndExit(int exit_value)
6502 CloseAudio(); /* called after freeing sounds (needed for SDL) */
6514 #if defined(TARGET_SDL)
6515 #if defined(TARGET_SDL2)
6517 // set a flag to tell the network server thread to quit and wait for it
6518 // using SDL_WaitThread()
6520 if (network_server) /* terminate network server */
6521 SDL_KillThread(server_thread);
6525 CloseVideoDisplay();
6526 ClosePlatformDependentStuff();
6528 if (exit_value != 0)
6530 /* fall back to default level set (current set may have caused an error) */
6531 SaveLevelSetup_LastSeries_Deactivate();
6533 /* tell user where to find error log file which may contain more details */
6534 // (error notification now directly displayed on screen inside R'n'D
6535 // NotifyUserAboutErrorFile(); /* currently only works for Windows */