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;
1131 if (type == TYPE_ELEMENT)
1133 char *value = getHashEntry(element_token_hash, value_raw);
1135 return (value != NULL ? atoi(value) : EL_UNDEFINED);
1137 else if (type == TYPE_GRAPHIC)
1139 char *value = getHashEntry(graphic_token_hash, value_raw);
1141 return (value != NULL ? atoi(value) : IMG_UNDEFINED);
1149 /* !!! THIS IS BUGGY !!! NOT SURE IF YOU GET ELEMENT ID OR GRAPHIC ID !!! */
1150 /* !!! (possible reason why ".clone_from" with elements doesn't work) !!! */
1152 /* !!! OPTIMIZE THIS BY USING HASH !!! */
1153 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1154 if (strEqual(element_info[i].token_name, value_raw))
1157 /* !!! OPTIMIZE THIS BY USING HASH !!! */
1158 for (i = 0; image_config[i].token != NULL; i++)
1160 int len_config_value = strlen(image_config[i].value);
1162 if (!strEqual(&image_config[i].value[len_config_value - 4], ".pcx") &&
1163 !strEqual(&image_config[i].value[len_config_value - 4], ".wav") &&
1164 !strEqual(image_config[i].value, UNDEFINED_FILENAME))
1167 if (strEqual(image_config[i].token, value_raw))
1177 static int get_scaled_graphic_width(int graphic)
1179 int original_width = getOriginalImageWidthFromImageID(graphic);
1180 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1182 return original_width * scale_up_factor;
1185 static int get_scaled_graphic_height(int graphic)
1187 int original_height = getOriginalImageHeightFromImageID(graphic);
1188 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1190 return original_height * scale_up_factor;
1193 static void set_graphic_parameters_ext(int graphic, int *parameter,
1196 struct GraphicInfo *g = &graphic_info[graphic];
1197 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1198 int anim_frames_per_line = 1;
1200 /* always start with reliable default values */
1201 g->src_image_width = 0;
1202 g->src_image_height = 0;
1205 g->width = TILEX; /* default for element graphics */
1206 g->height = TILEY; /* default for element graphics */
1207 g->offset_x = 0; /* one or both of these values ... */
1208 g->offset_y = 0; /* ... will be corrected later */
1209 g->offset2_x = 0; /* one or both of these values ... */
1210 g->offset2_y = 0; /* ... will be corrected later */
1211 g->swap_double_tiles = -1; /* auto-detect tile swapping */
1212 g->crumbled_like = -1; /* do not use clone element */
1213 g->diggable_like = -1; /* do not use clone element */
1214 g->border_size = TILEX / 8; /* "CRUMBLED" border size */
1215 g->scale_up_factor = 1; /* default: no scaling up */
1216 g->clone_from = -1; /* do not use clone graphic */
1217 g->anim_delay_fixed = 0;
1218 g->anim_delay_random = 0;
1219 g->post_delay_fixed = 0;
1220 g->post_delay_random = 0;
1221 g->fade_mode = FADE_MODE_DEFAULT;
1225 g->align = ALIGN_CENTER; /* default for title screens */
1226 g->valign = VALIGN_MIDDLE; /* default for title screens */
1227 g->sort_priority = 0; /* default for title screens */
1229 g->style = STYLE_DEFAULT;
1231 g->bitmap = src_bitmap;
1234 /* optional zoom factor for scaling up the image to a larger size */
1235 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1236 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1237 if (g->scale_up_factor < 1)
1238 g->scale_up_factor = 1; /* no scaling */
1242 if (g->use_image_size)
1244 /* set new default bitmap size (with scaling, but without small images) */
1245 g->width = get_scaled_graphic_width(graphic);
1246 g->height = get_scaled_graphic_height(graphic);
1250 /* optional x and y tile position of animation frame sequence */
1251 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1252 g->src_x = parameter[GFX_ARG_XPOS] * TILEX;
1253 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1254 g->src_y = parameter[GFX_ARG_YPOS] * TILEY;
1256 /* optional x and y pixel position of animation frame sequence */
1257 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1258 g->src_x = parameter[GFX_ARG_X];
1259 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1260 g->src_y = parameter[GFX_ARG_Y];
1262 /* optional width and height of each animation frame */
1263 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1264 g->width = parameter[GFX_ARG_WIDTH];
1265 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1266 g->height = parameter[GFX_ARG_HEIGHT];
1272 Error(ERR_INFO_LINE, "-");
1273 Error(ERR_WARN, "invalid value %d for '%s.width' (fallback done to %d)",
1274 g->width, getTokenFromImageID(graphic), TILEX);
1275 Error(ERR_INFO_LINE, "-");
1277 g->width = TILEX; /* will be checked to be inside bitmap later */
1282 Error(ERR_INFO_LINE, "-");
1283 Error(ERR_WARN, "invalid value %d for '%s.height' (fallback done to %d)",
1284 g->height, getTokenFromImageID(graphic), TILEY);
1285 Error(ERR_INFO_LINE, "-");
1287 g->height = TILEY; /* will be checked to be inside bitmap later */
1292 /* optional zoom factor for scaling up the image to a larger size */
1293 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1294 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1295 if (g->scale_up_factor < 1)
1296 g->scale_up_factor = 1; /* no scaling */
1301 /* get final bitmap size (with scaling, but without small images) */
1302 int src_image_width = get_scaled_graphic_width(graphic);
1303 int src_image_height = get_scaled_graphic_height(graphic);
1305 if (src_image_width == 0 || src_image_height == 0)
1307 /* only happens when loaded outside artwork system (like "global.busy") */
1308 src_image_width = src_bitmap->width;
1309 src_image_height = src_bitmap->height;
1312 anim_frames_per_row = src_image_width / g->width;
1313 anim_frames_per_col = src_image_height / g->height;
1315 g->src_image_width = src_image_width;
1316 g->src_image_height = src_image_height;
1319 /* correct x or y offset dependent of vertical or horizontal frame order */
1320 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1322 g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1323 parameter[GFX_ARG_OFFSET] : g->height);
1324 anim_frames_per_line = anim_frames_per_col;
1326 else /* frames are ordered horizontally */
1328 g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1329 parameter[GFX_ARG_OFFSET] : g->width);
1330 anim_frames_per_line = anim_frames_per_row;
1333 /* optionally, the x and y offset of frames can be specified directly */
1334 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1335 g->offset_x = parameter[GFX_ARG_XOFFSET];
1336 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1337 g->offset_y = parameter[GFX_ARG_YOFFSET];
1339 /* optionally, moving animations may have separate start and end graphics */
1340 g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1342 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1343 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1345 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1346 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1347 g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1348 parameter[GFX_ARG_2ND_OFFSET] : g->height);
1349 else /* frames are ordered horizontally */
1350 g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1351 parameter[GFX_ARG_2ND_OFFSET] : g->width);
1353 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1354 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1355 g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1356 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1357 g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1359 /* optionally, the second movement tile can be specified as start tile */
1360 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1361 g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1363 /* automatically determine correct number of frames, if not defined */
1364 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1365 g->anim_frames = parameter[GFX_ARG_FRAMES];
1366 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1367 g->anim_frames = anim_frames_per_row;
1368 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1369 g->anim_frames = anim_frames_per_col;
1373 if (g->anim_frames == 0) /* frames must be at least 1 */
1376 g->anim_frames_per_line =
1377 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1378 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1380 g->anim_delay = parameter[GFX_ARG_DELAY];
1381 if (g->anim_delay == 0) /* delay must be at least 1 */
1384 g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1386 if (g->anim_frames == 1)
1387 g->anim_mode = ANIM_NONE;
1390 /* automatically determine correct start frame, if not defined */
1391 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1392 g->anim_start_frame = 0;
1393 else if (g->anim_mode & ANIM_REVERSE)
1394 g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1396 g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1398 /* animation synchronized with global frame counter, not move position */
1399 g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1401 /* optional element for cloning crumble graphics */
1402 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1403 g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1405 /* optional element for cloning digging graphics */
1406 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1407 g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1409 /* optional border size for "crumbling" diggable graphics */
1410 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1411 g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1413 /* this is only used for player "boring" and "sleeping" actions */
1414 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1415 g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1416 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1417 g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1418 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1419 g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1420 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1421 g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1423 /* this is only used for toon animations */
1424 g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1425 g->step_delay = parameter[GFX_ARG_STEP_DELAY];
1427 /* this is only used for drawing font characters */
1428 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1429 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1431 /* this is only used for drawing envelope graphics */
1432 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1434 /* optional graphic for cloning all graphics settings */
1435 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1436 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1438 /* optional settings for drawing title screens and title messages */
1439 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1440 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1441 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1442 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1443 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1444 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1445 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1446 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1447 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1448 g->align = parameter[GFX_ARG_ALIGN];
1449 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1450 g->valign = parameter[GFX_ARG_VALIGN];
1451 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1452 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1454 if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
1455 g->class = parameter[GFX_ARG_CLASS];
1456 if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
1457 g->style = parameter[GFX_ARG_STYLE];
1459 /* this is only used for drawing menu buttons and text */
1460 g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
1461 g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
1462 g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
1463 g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
1466 static void set_graphic_parameters(int graphic)
1469 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1470 char **parameter_raw = image->parameter;
1471 Bitmap *src_bitmap = getBitmapFromImageID(graphic);
1472 int parameter[NUM_GFX_ARGS];
1475 /* if fallback to default artwork is done, also use the default parameters */
1476 if (image->fallback_to_default)
1477 parameter_raw = image->default_parameter;
1479 /* get integer values from string parameters */
1480 for (i = 0; i < NUM_GFX_ARGS; i++)
1481 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1482 image_config_suffix[i].token,
1483 image_config_suffix[i].type);
1485 set_graphic_parameters_ext(graphic, parameter, src_bitmap);
1489 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1490 char **parameter_raw = image->parameter;
1491 Bitmap *src_bitmap = getBitmapFromImageID(graphic);
1492 int parameter[NUM_GFX_ARGS];
1493 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1494 int anim_frames_per_line = 1;
1497 /* if fallback to default artwork is done, also use the default parameters */
1498 if (image->fallback_to_default)
1499 parameter_raw = image->default_parameter;
1501 /* get integer values from string parameters */
1502 for (i = 0; i < NUM_GFX_ARGS; i++)
1503 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1504 image_config_suffix[i].token,
1505 image_config_suffix[i].type);
1507 graphic_info[graphic].bitmap = src_bitmap;
1509 /* always start with reliable default values */
1510 graphic_info[graphic].src_image_width = 0;
1511 graphic_info[graphic].src_image_height = 0;
1512 graphic_info[graphic].src_x = 0;
1513 graphic_info[graphic].src_y = 0;
1514 graphic_info[graphic].width = TILEX; /* default for element graphics */
1515 graphic_info[graphic].height = TILEY; /* default for element graphics */
1516 graphic_info[graphic].offset_x = 0; /* one or both of these values ... */
1517 graphic_info[graphic].offset_y = 0; /* ... will be corrected later */
1518 graphic_info[graphic].offset2_x = 0; /* one or both of these values ... */
1519 graphic_info[graphic].offset2_y = 0; /* ... will be corrected later */
1520 graphic_info[graphic].swap_double_tiles = -1; /* auto-detect tile swapping */
1521 graphic_info[graphic].crumbled_like = -1; /* do not use clone element */
1522 graphic_info[graphic].diggable_like = -1; /* do not use clone element */
1523 graphic_info[graphic].border_size = TILEX / 8; /* "CRUMBLED" border size */
1524 graphic_info[graphic].scale_up_factor = 1; /* default: no scaling up */
1525 graphic_info[graphic].clone_from = -1; /* do not use clone graphic */
1526 graphic_info[graphic].anim_delay_fixed = 0;
1527 graphic_info[graphic].anim_delay_random = 0;
1528 graphic_info[graphic].post_delay_fixed = 0;
1529 graphic_info[graphic].post_delay_random = 0;
1530 graphic_info[graphic].fade_mode = FADE_MODE_DEFAULT;
1531 graphic_info[graphic].fade_delay = -1;
1532 graphic_info[graphic].post_delay = -1;
1533 graphic_info[graphic].auto_delay = -1;
1534 graphic_info[graphic].align = ALIGN_CENTER; /* default for title screens */
1535 graphic_info[graphic].valign = VALIGN_MIDDLE; /* default for title screens */
1536 graphic_info[graphic].sort_priority = 0; /* default for title screens */
1539 /* optional zoom factor for scaling up the image to a larger size */
1540 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1541 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1542 if (graphic_info[graphic].scale_up_factor < 1)
1543 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
1547 if (graphic_info[graphic].use_image_size)
1549 /* set new default bitmap size (with scaling, but without small images) */
1550 graphic_info[graphic].width = get_scaled_graphic_width(graphic);
1551 graphic_info[graphic].height = get_scaled_graphic_height(graphic);
1555 /* optional x and y tile position of animation frame sequence */
1556 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1557 graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
1558 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1559 graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
1561 /* optional x and y pixel position of animation frame sequence */
1562 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1563 graphic_info[graphic].src_x = parameter[GFX_ARG_X];
1564 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1565 graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
1567 /* optional width and height of each animation frame */
1568 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1569 graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
1570 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1571 graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
1574 /* optional zoom factor for scaling up the image to a larger size */
1575 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1576 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1577 if (graphic_info[graphic].scale_up_factor < 1)
1578 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
1583 /* get final bitmap size (with scaling, but without small images) */
1584 int src_image_width = get_scaled_graphic_width(graphic);
1585 int src_image_height = get_scaled_graphic_height(graphic);
1587 anim_frames_per_row = src_image_width / graphic_info[graphic].width;
1588 anim_frames_per_col = src_image_height / graphic_info[graphic].height;
1590 graphic_info[graphic].src_image_width = src_image_width;
1591 graphic_info[graphic].src_image_height = src_image_height;
1594 /* correct x or y offset dependent of vertical or horizontal frame order */
1595 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1597 graphic_info[graphic].offset_y =
1598 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1599 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
1600 anim_frames_per_line = anim_frames_per_col;
1602 else /* frames are ordered horizontally */
1604 graphic_info[graphic].offset_x =
1605 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1606 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
1607 anim_frames_per_line = anim_frames_per_row;
1610 /* optionally, the x and y offset of frames can be specified directly */
1611 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1612 graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
1613 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1614 graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
1616 /* optionally, moving animations may have separate start and end graphics */
1617 graphic_info[graphic].double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1619 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1620 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1622 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1623 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1624 graphic_info[graphic].offset2_y =
1625 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1626 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].height);
1627 else /* frames are ordered horizontally */
1628 graphic_info[graphic].offset2_x =
1629 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1630 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].width);
1632 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1633 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1634 graphic_info[graphic].offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1635 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1636 graphic_info[graphic].offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1638 /* optionally, the second movement tile can be specified as start tile */
1639 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1640 graphic_info[graphic].swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1642 /* automatically determine correct number of frames, if not defined */
1643 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1644 graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
1645 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1646 graphic_info[graphic].anim_frames = anim_frames_per_row;
1647 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1648 graphic_info[graphic].anim_frames = anim_frames_per_col;
1650 graphic_info[graphic].anim_frames = 1;
1652 if (graphic_info[graphic].anim_frames == 0) /* frames must be at least 1 */
1653 graphic_info[graphic].anim_frames = 1;
1655 graphic_info[graphic].anim_frames_per_line =
1656 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1657 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1659 graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
1660 if (graphic_info[graphic].anim_delay == 0) /* delay must be at least 1 */
1661 graphic_info[graphic].anim_delay = 1;
1663 graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
1665 if (graphic_info[graphic].anim_frames == 1)
1666 graphic_info[graphic].anim_mode = ANIM_NONE;
1669 /* automatically determine correct start frame, if not defined */
1670 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1671 graphic_info[graphic].anim_start_frame = 0;
1672 else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
1673 graphic_info[graphic].anim_start_frame =
1674 graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1676 graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
1678 /* animation synchronized with global frame counter, not move position */
1679 graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1681 /* optional element for cloning crumble graphics */
1682 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1683 graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1685 /* optional element for cloning digging graphics */
1686 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1687 graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1689 /* optional border size for "crumbling" diggable graphics */
1690 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1691 graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
1693 /* this is only used for player "boring" and "sleeping" actions */
1694 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1695 graphic_info[graphic].anim_delay_fixed =
1696 parameter[GFX_ARG_ANIM_DELAY_FIXED];
1697 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1698 graphic_info[graphic].anim_delay_random =
1699 parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1700 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1701 graphic_info[graphic].post_delay_fixed =
1702 parameter[GFX_ARG_POST_DELAY_FIXED];
1703 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1704 graphic_info[graphic].post_delay_random =
1705 parameter[GFX_ARG_POST_DELAY_RANDOM];
1707 /* this is only used for toon animations */
1708 graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
1709 graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY];
1711 /* this is only used for drawing font characters */
1712 graphic_info[graphic].draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1713 graphic_info[graphic].draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1715 /* this is only used for drawing envelope graphics */
1716 graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1718 /* optional graphic for cloning all graphics settings */
1719 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1720 graphic_info[graphic].clone_from = parameter[GFX_ARG_CLONE_FROM];
1722 /* optional settings for drawing title screens and title messages */
1723 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1724 graphic_info[graphic].fade_mode = parameter[GFX_ARG_FADE_MODE];
1725 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1726 graphic_info[graphic].fade_delay = parameter[GFX_ARG_FADE_DELAY];
1727 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1728 graphic_info[graphic].post_delay = parameter[GFX_ARG_POST_DELAY];
1729 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1730 graphic_info[graphic].auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1731 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1732 graphic_info[graphic].align = parameter[GFX_ARG_ALIGN];
1733 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1734 graphic_info[graphic].valign = parameter[GFX_ARG_VALIGN];
1735 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1736 graphic_info[graphic].sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1739 UPDATE_BUSY_STATE();
1742 static void set_cloned_graphic_parameters(int graphic)
1744 int fallback_graphic = IMG_CHAR_EXCLAM;
1745 int max_num_images = getImageListSize();
1746 int clone_graphic = graphic_info[graphic].clone_from;
1747 int num_references_followed = 1;
1749 while (graphic_info[clone_graphic].clone_from != -1 &&
1750 num_references_followed < max_num_images)
1752 clone_graphic = graphic_info[clone_graphic].clone_from;
1754 num_references_followed++;
1757 if (num_references_followed >= max_num_images)
1759 Error(ERR_INFO_LINE, "-");
1760 Error(ERR_INFO, "warning: error found in config file:");
1761 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1762 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1763 Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1764 Error(ERR_INFO, "custom graphic rejected for this element/action");
1766 if (graphic == fallback_graphic)
1767 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1769 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1770 Error(ERR_INFO_LINE, "-");
1772 graphic_info[graphic] = graphic_info[fallback_graphic];
1776 graphic_info[graphic] = graphic_info[clone_graphic];
1777 graphic_info[graphic].clone_from = clone_graphic;
1781 static void InitGraphicInfo()
1783 int fallback_graphic = IMG_CHAR_EXCLAM;
1784 int num_images = getImageListSize();
1787 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1788 static boolean clipmasks_initialized = FALSE;
1790 XGCValues clip_gc_values;
1791 unsigned int clip_gc_valuemask;
1792 GC copy_clipmask_gc = None;
1795 /* use image size as default values for width and height for these images */
1796 static int full_size_graphics[] =
1801 IMG_BACKGROUND_ENVELOPE_1,
1802 IMG_BACKGROUND_ENVELOPE_2,
1803 IMG_BACKGROUND_ENVELOPE_3,
1804 IMG_BACKGROUND_ENVELOPE_4,
1807 IMG_BACKGROUND_TITLE_INITIAL,
1808 IMG_BACKGROUND_TITLE,
1809 IMG_BACKGROUND_MAIN,
1810 IMG_BACKGROUND_LEVELS,
1811 IMG_BACKGROUND_LEVELNR,
1812 IMG_BACKGROUND_SCORES,
1813 IMG_BACKGROUND_EDITOR,
1814 IMG_BACKGROUND_INFO,
1815 IMG_BACKGROUND_INFO_ELEMENTS,
1816 IMG_BACKGROUND_INFO_MUSIC,
1817 IMG_BACKGROUND_INFO_CREDITS,
1818 IMG_BACKGROUND_INFO_PROGRAM,
1819 IMG_BACKGROUND_INFO_LEVELSET,
1820 IMG_BACKGROUND_SETUP,
1821 IMG_BACKGROUND_DOOR,
1822 IMG_BACKGROUND_TAPE,
1823 IMG_BACKGROUND_PANEL,
1825 IMG_TITLESCREEN_INITIAL_1,
1826 IMG_TITLESCREEN_INITIAL_2,
1827 IMG_TITLESCREEN_INITIAL_3,
1828 IMG_TITLESCREEN_INITIAL_4,
1829 IMG_TITLESCREEN_INITIAL_5,
1839 checked_free(graphic_info);
1841 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1844 /* initialize "use_image_size" flag with default value */
1845 for (i = 0; i < num_images; i++)
1846 graphic_info[i].use_image_size = FALSE;
1848 /* initialize "use_image_size" flag from static configuration above */
1849 for (i = 0; full_size_graphics[i] != -1; i++)
1850 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1853 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1854 if (clipmasks_initialized)
1856 for (i = 0; i < num_images; i++)
1858 if (graphic_info[i].clip_mask)
1859 XFreePixmap(display, graphic_info[i].clip_mask);
1860 if (graphic_info[i].clip_gc)
1861 XFreeGC(display, graphic_info[i].clip_gc);
1863 graphic_info[i].clip_mask = None;
1864 graphic_info[i].clip_gc = None;
1869 /* first set all graphic paramaters ... */
1870 for (i = 0; i < num_images; i++)
1871 set_graphic_parameters(i);
1873 /* ... then copy these parameters for cloned graphics */
1874 for (i = 0; i < num_images; i++)
1875 if (graphic_info[i].clone_from != -1)
1876 set_cloned_graphic_parameters(i);
1878 for (i = 0; i < num_images; i++)
1883 int first_frame, last_frame;
1884 int src_bitmap_width, src_bitmap_height;
1886 /* now check if no animation frames are outside of the loaded image */
1888 if (graphic_info[i].bitmap == NULL)
1889 continue; /* skip check for optional images that are undefined */
1891 /* get image size (this can differ from the standard element tile size!) */
1892 width = graphic_info[i].width;
1893 height = graphic_info[i].height;
1895 /* get final bitmap size (with scaling, but without small images) */
1896 src_bitmap_width = graphic_info[i].src_image_width;
1897 src_bitmap_height = graphic_info[i].src_image_height;
1899 /* check if first animation frame is inside specified bitmap */
1902 getFixedGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1905 /* this avoids calculating wrong start position for out-of-bounds frame */
1906 src_x = graphic_info[i].src_x;
1907 src_y = graphic_info[i].src_y;
1910 if (src_x < 0 || src_y < 0 ||
1911 src_x + width > src_bitmap_width ||
1912 src_y + height > src_bitmap_height)
1914 Error(ERR_INFO_LINE, "-");
1915 Error(ERR_INFO, "warning: error found in config file:");
1916 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1917 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1918 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1920 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1921 src_x, src_y, src_bitmap_width, src_bitmap_height);
1922 Error(ERR_INFO, "custom graphic rejected for this element/action");
1924 if (i == fallback_graphic)
1925 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1927 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1928 Error(ERR_INFO_LINE, "-");
1930 graphic_info[i] = graphic_info[fallback_graphic];
1933 /* check if last animation frame is inside specified bitmap */
1935 last_frame = graphic_info[i].anim_frames - 1;
1936 getFixedGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1938 if (src_x < 0 || src_y < 0 ||
1939 src_x + width > src_bitmap_width ||
1940 src_y + height > src_bitmap_height)
1942 Error(ERR_INFO_LINE, "-");
1943 Error(ERR_INFO, "warning: error found in config file:");
1944 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1945 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1946 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1948 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1949 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1950 Error(ERR_INFO, "::: %d, %d", width, height);
1951 Error(ERR_INFO, "custom graphic rejected for this element/action");
1953 if (i == fallback_graphic)
1954 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1956 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1957 Error(ERR_INFO_LINE, "-");
1959 graphic_info[i] = graphic_info[fallback_graphic];
1962 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1963 /* currently we only need a tile clip mask from the first frame */
1964 getFixedGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1966 if (copy_clipmask_gc == None)
1968 clip_gc_values.graphics_exposures = False;
1969 clip_gc_valuemask = GCGraphicsExposures;
1970 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
1971 clip_gc_valuemask, &clip_gc_values);
1974 graphic_info[i].clip_mask =
1975 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
1977 src_pixmap = src_bitmap->clip_mask;
1978 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
1979 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
1981 clip_gc_values.graphics_exposures = False;
1982 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
1983 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
1985 graphic_info[i].clip_gc =
1986 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
1990 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1991 if (copy_clipmask_gc)
1992 XFreeGC(display, copy_clipmask_gc);
1994 clipmasks_initialized = TRUE;
1998 static void InitGraphicCompatibilityInfo()
2000 struct FileInfo *fi_global_door =
2001 getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
2002 int num_images = getImageListSize();
2005 /* the following compatibility handling is needed for the following case:
2006 versions up to 3.3.0.0 used one large bitmap "global.door" for various
2007 graphics mainly used for door and panel graphics, like editor, tape and
2008 in-game buttons with hard-coded bitmap positions and button sizes; as
2009 these graphics now have individual definitions, redefining "global.door"
2010 to change all these graphics at once like before does not work anymore
2011 (because all those individual definitions still have their default values);
2012 to solve this, remap all those individual definitions that are not
2013 redefined to the new bitmap of "global.door" if it was redefined */
2015 /* special compatibility handling if image "global.door" was redefined */
2016 if (fi_global_door->redefined)
2018 for (i = 0; i < num_images; i++)
2020 struct FileInfo *fi = getImageListEntryFromImageID(i);
2022 /* process only those images that still use the default settings */
2025 /* process all images which default to same image as "global.door" */
2026 if (strEqual(fi->default_filename, fi_global_door->default_filename))
2028 // printf("::: special treatment needed for token '%s'\n", fi->token);
2030 graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2037 for (i = 0; i < num_images; i++)
2039 struct FileInfo *fi = getImageListEntryFromImageID(i);
2041 if (i == IMG_GLOBAL_DOOR)
2043 printf("::: %s, %s, %d\n",
2044 fi->default_filename,
2052 static void InitElementSoundInfo()
2054 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
2055 int num_property_mappings = getSoundListPropertyMappingSize();
2058 /* set values to -1 to identify later as "uninitialized" values */
2059 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2060 for (act = 0; act < NUM_ACTIONS; act++)
2061 element_info[i].sound[act] = -1;
2063 /* initialize element/sound mapping from static configuration */
2064 for (i = 0; element_to_sound[i].element > -1; i++)
2066 int element = element_to_sound[i].element;
2067 int action = element_to_sound[i].action;
2068 int sound = element_to_sound[i].sound;
2069 boolean is_class = element_to_sound[i].is_class;
2072 action = ACTION_DEFAULT;
2075 element_info[element].sound[action] = sound;
2077 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2078 if (strEqual(element_info[j].class_name,
2079 element_info[element].class_name))
2080 element_info[j].sound[action] = sound;
2083 /* initialize element class/sound mapping from dynamic configuration */
2084 for (i = 0; i < num_property_mappings; i++)
2086 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
2087 int action = property_mapping[i].ext1_index;
2088 int sound = property_mapping[i].artwork_index;
2090 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
2094 action = ACTION_DEFAULT;
2096 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2097 if (strEqual(element_info[j].class_name,
2098 element_info[element_class].class_name))
2099 element_info[j].sound[action] = sound;
2102 /* initialize element/sound mapping from dynamic configuration */
2103 for (i = 0; i < num_property_mappings; i++)
2105 int element = property_mapping[i].base_index;
2106 int action = property_mapping[i].ext1_index;
2107 int sound = property_mapping[i].artwork_index;
2109 if (element >= MAX_NUM_ELEMENTS)
2113 action = ACTION_DEFAULT;
2115 element_info[element].sound[action] = sound;
2118 /* now set all '-1' values to element specific default values */
2119 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2121 for (act = 0; act < NUM_ACTIONS; act++)
2123 /* generic default action sound (defined by "[default]" directive) */
2124 int default_action_sound = element_info[EL_DEFAULT].sound[act];
2126 /* look for special default action sound (classic game specific) */
2127 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
2128 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
2129 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
2130 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
2131 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
2132 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
2134 /* !!! there's no such thing as a "default action sound" !!! */
2136 /* look for element specific default sound (independent from action) */
2137 if (element_info[i].sound[ACTION_DEFAULT] != -1)
2138 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
2142 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
2143 /* !!! make this better !!! */
2144 if (i == EL_EMPTY_SPACE)
2145 default_action_sound = element_info[EL_DEFAULT].sound[act];
2148 /* no sound for this specific action -- use default action sound */
2149 if (element_info[i].sound[act] == -1)
2150 element_info[i].sound[act] = default_action_sound;
2154 /* copy sound settings to some elements that are only stored in level file
2155 in native R'n'D levels, but are used by game engine in native EM levels */
2156 for (i = 0; copy_properties[i][0] != -1; i++)
2157 for (j = 1; j <= 4; j++)
2158 for (act = 0; act < NUM_ACTIONS; act++)
2159 element_info[copy_properties[i][j]].sound[act] =
2160 element_info[copy_properties[i][0]].sound[act];
2163 static void InitGameModeSoundInfo()
2167 /* set values to -1 to identify later as "uninitialized" values */
2168 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2171 /* initialize gamemode/sound mapping from static configuration */
2172 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
2174 int gamemode = gamemode_to_sound[i].gamemode;
2175 int sound = gamemode_to_sound[i].sound;
2178 gamemode = GAME_MODE_DEFAULT;
2180 menu.sound[gamemode] = sound;
2183 /* now set all '-1' values to levelset specific default values */
2184 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2185 if (menu.sound[i] == -1)
2186 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
2189 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2190 if (menu.sound[i] != -1)
2191 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
2195 static void set_sound_parameters(int sound, char **parameter_raw)
2197 int parameter[NUM_SND_ARGS];
2200 /* get integer values from string parameters */
2201 for (i = 0; i < NUM_SND_ARGS; i++)
2203 get_parameter_value(parameter_raw[i],
2204 sound_config_suffix[i].token,
2205 sound_config_suffix[i].type);
2207 /* explicit loop mode setting in configuration overrides default value */
2208 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2209 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
2211 /* sound volume to change the original volume when loading the sound file */
2212 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
2214 /* sound priority to give certain sounds a higher or lower priority */
2215 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
2218 static void InitSoundInfo()
2220 int *sound_effect_properties;
2221 int num_sounds = getSoundListSize();
2224 checked_free(sound_info);
2226 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
2227 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
2229 /* initialize sound effect for all elements to "no sound" */
2230 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2231 for (j = 0; j < NUM_ACTIONS; j++)
2232 element_info[i].sound[j] = SND_UNDEFINED;
2234 for (i = 0; i < num_sounds; i++)
2236 struct FileInfo *sound = getSoundListEntry(i);
2237 int len_effect_text = strlen(sound->token);
2239 sound_effect_properties[i] = ACTION_OTHER;
2240 sound_info[i].loop = FALSE; /* default: play sound only once */
2243 printf("::: sound %d: '%s'\n", i, sound->token);
2246 /* determine all loop sounds and identify certain sound classes */
2248 for (j = 0; element_action_info[j].suffix; j++)
2250 int len_action_text = strlen(element_action_info[j].suffix);
2252 if (len_action_text < len_effect_text &&
2253 strEqual(&sound->token[len_effect_text - len_action_text],
2254 element_action_info[j].suffix))
2256 sound_effect_properties[i] = element_action_info[j].value;
2257 sound_info[i].loop = element_action_info[j].is_loop_sound;
2263 /* associate elements and some selected sound actions */
2265 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2267 if (element_info[j].class_name)
2269 int len_class_text = strlen(element_info[j].class_name);
2271 if (len_class_text + 1 < len_effect_text &&
2272 strncmp(sound->token,
2273 element_info[j].class_name, len_class_text) == 0 &&
2274 sound->token[len_class_text] == '.')
2276 int sound_action_value = sound_effect_properties[i];
2278 element_info[j].sound[sound_action_value] = i;
2283 set_sound_parameters(i, sound->parameter);
2286 free(sound_effect_properties);
2289 static void InitGameModeMusicInfo()
2291 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
2292 int num_property_mappings = getMusicListPropertyMappingSize();
2293 int default_levelset_music = -1;
2296 /* set values to -1 to identify later as "uninitialized" values */
2297 for (i = 0; i < MAX_LEVELS; i++)
2298 levelset.music[i] = -1;
2299 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2302 /* initialize gamemode/music mapping from static configuration */
2303 for (i = 0; gamemode_to_music[i].music > -1; i++)
2305 int gamemode = gamemode_to_music[i].gamemode;
2306 int music = gamemode_to_music[i].music;
2309 printf("::: gamemode == %d, music == %d\n", gamemode, music);
2313 gamemode = GAME_MODE_DEFAULT;
2315 menu.music[gamemode] = music;
2318 /* initialize gamemode/music mapping from dynamic configuration */
2319 for (i = 0; i < num_property_mappings; i++)
2321 int prefix = property_mapping[i].base_index;
2322 int gamemode = property_mapping[i].ext1_index;
2323 int level = property_mapping[i].ext2_index;
2324 int music = property_mapping[i].artwork_index;
2327 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
2328 prefix, gamemode, level, music);
2331 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
2335 gamemode = GAME_MODE_DEFAULT;
2337 /* level specific music only allowed for in-game music */
2338 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
2339 gamemode = GAME_MODE_PLAYING;
2344 default_levelset_music = music;
2347 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
2348 levelset.music[level] = music;
2349 if (gamemode != GAME_MODE_PLAYING)
2350 menu.music[gamemode] = music;
2353 /* now set all '-1' values to menu specific default values */
2354 /* (undefined values of "levelset.music[]" might stay at "-1" to
2355 allow dynamic selection of music files from music directory!) */
2356 for (i = 0; i < MAX_LEVELS; i++)
2357 if (levelset.music[i] == -1)
2358 levelset.music[i] = default_levelset_music;
2359 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2360 if (menu.music[i] == -1)
2361 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
2364 for (i = 0; i < MAX_LEVELS; i++)
2365 if (levelset.music[i] != -1)
2366 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
2367 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2368 if (menu.music[i] != -1)
2369 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
2373 static void set_music_parameters(int music, char **parameter_raw)
2375 int parameter[NUM_MUS_ARGS];
2378 /* get integer values from string parameters */
2379 for (i = 0; i < NUM_MUS_ARGS; i++)
2381 get_parameter_value(parameter_raw[i],
2382 music_config_suffix[i].token,
2383 music_config_suffix[i].type);
2385 /* explicit loop mode setting in configuration overrides default value */
2386 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2387 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
2390 static void InitMusicInfo()
2392 int num_music = getMusicListSize();
2395 checked_free(music_info);
2397 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
2399 for (i = 0; i < num_music; i++)
2401 struct FileInfo *music = getMusicListEntry(i);
2402 int len_music_text = strlen(music->token);
2404 music_info[i].loop = TRUE; /* default: play music in loop mode */
2406 /* determine all loop music */
2408 for (j = 0; music_prefix_info[j].prefix; j++)
2410 int len_prefix_text = strlen(music_prefix_info[j].prefix);
2412 if (len_prefix_text < len_music_text &&
2413 strncmp(music->token,
2414 music_prefix_info[j].prefix, len_prefix_text) == 0)
2416 music_info[i].loop = music_prefix_info[j].is_loop_music;
2422 set_music_parameters(i, music->parameter);
2426 static void ReinitializeGraphics()
2428 print_timestamp_init("ReinitializeGraphics");
2430 InitGraphicInfo(); /* graphic properties mapping */
2431 print_timestamp_time("InitGraphicInfo");
2432 InitElementGraphicInfo(); /* element game graphic mapping */
2433 print_timestamp_time("InitElementGraphicInfo");
2434 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
2435 print_timestamp_time("InitElementSpecialGraphicInfo");
2437 InitElementSmallImages(); /* scale elements to all needed sizes */
2438 print_timestamp_time("InitElementSmallImages");
2439 InitScaledImages(); /* scale all other images, if needed */
2440 print_timestamp_time("InitScaledImages");
2441 InitFontGraphicInfo(); /* initialize text drawing functions */
2442 print_timestamp_time("InitFontGraphicInfo");
2444 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
2445 print_timestamp_time("InitGraphicInfo_EM");
2447 InitGraphicCompatibilityInfo();
2448 print_timestamp_time("InitGraphicCompatibilityInfo");
2450 SetMainBackgroundImage(IMG_BACKGROUND);
2451 print_timestamp_time("SetMainBackgroundImage");
2452 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2453 print_timestamp_time("SetDoorBackgroundImage");
2456 print_timestamp_time("InitGadgets");
2458 print_timestamp_time("InitToons");
2460 print_timestamp_done("ReinitializeGraphics");
2463 static void ReinitializeSounds()
2465 InitSoundInfo(); /* sound properties mapping */
2466 InitElementSoundInfo(); /* element game sound mapping */
2467 InitGameModeSoundInfo(); /* game mode sound mapping */
2469 InitPlayLevelSound(); /* internal game sound settings */
2472 static void ReinitializeMusic()
2474 InitMusicInfo(); /* music properties mapping */
2475 InitGameModeMusicInfo(); /* game mode music mapping */
2478 static int get_special_property_bit(int element, int property_bit_nr)
2480 struct PropertyBitInfo
2486 static struct PropertyBitInfo pb_can_move_into_acid[] =
2488 /* the player may be able fall into acid when gravity is activated */
2493 { EL_SP_MURPHY, 0 },
2494 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2496 /* all elements that can move may be able to also move into acid */
2499 { EL_BUG_RIGHT, 1 },
2502 { EL_SPACESHIP, 2 },
2503 { EL_SPACESHIP_LEFT, 2 },
2504 { EL_SPACESHIP_RIGHT, 2 },
2505 { EL_SPACESHIP_UP, 2 },
2506 { EL_SPACESHIP_DOWN, 2 },
2507 { EL_BD_BUTTERFLY, 3 },
2508 { EL_BD_BUTTERFLY_LEFT, 3 },
2509 { EL_BD_BUTTERFLY_RIGHT, 3 },
2510 { EL_BD_BUTTERFLY_UP, 3 },
2511 { EL_BD_BUTTERFLY_DOWN, 3 },
2512 { EL_BD_FIREFLY, 4 },
2513 { EL_BD_FIREFLY_LEFT, 4 },
2514 { EL_BD_FIREFLY_RIGHT, 4 },
2515 { EL_BD_FIREFLY_UP, 4 },
2516 { EL_BD_FIREFLY_DOWN, 4 },
2518 { EL_YAMYAM_LEFT, 5 },
2519 { EL_YAMYAM_RIGHT, 5 },
2520 { EL_YAMYAM_UP, 5 },
2521 { EL_YAMYAM_DOWN, 5 },
2522 { EL_DARK_YAMYAM, 6 },
2525 { EL_PACMAN_LEFT, 8 },
2526 { EL_PACMAN_RIGHT, 8 },
2527 { EL_PACMAN_UP, 8 },
2528 { EL_PACMAN_DOWN, 8 },
2530 { EL_MOLE_LEFT, 9 },
2531 { EL_MOLE_RIGHT, 9 },
2533 { EL_MOLE_DOWN, 9 },
2537 { EL_SATELLITE, 13 },
2538 { EL_SP_SNIKSNAK, 14 },
2539 { EL_SP_ELECTRON, 15 },
2542 { EL_EMC_ANDROID, 18 },
2547 static struct PropertyBitInfo pb_dont_collide_with[] =
2549 { EL_SP_SNIKSNAK, 0 },
2550 { EL_SP_ELECTRON, 1 },
2558 struct PropertyBitInfo *pb_info;
2561 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2562 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2567 struct PropertyBitInfo *pb_info = NULL;
2570 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2571 if (pb_definition[i].bit_nr == property_bit_nr)
2572 pb_info = pb_definition[i].pb_info;
2574 if (pb_info == NULL)
2577 for (i = 0; pb_info[i].element != -1; i++)
2578 if (pb_info[i].element == element)
2579 return pb_info[i].bit_nr;
2584 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2585 boolean property_value)
2587 int bit_nr = get_special_property_bit(element, property_bit_nr);
2592 *bitfield |= (1 << bit_nr);
2594 *bitfield &= ~(1 << bit_nr);
2598 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2600 int bit_nr = get_special_property_bit(element, property_bit_nr);
2603 return ((*bitfield & (1 << bit_nr)) != 0);
2608 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2610 static int group_nr;
2611 static struct ElementGroupInfo *group;
2612 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2615 if (actual_group == NULL) /* not yet initialized */
2618 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
2620 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2621 group_element - EL_GROUP_START + 1);
2623 /* replace element which caused too deep recursion by question mark */
2624 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2629 if (recursion_depth == 0) /* initialization */
2631 group = actual_group;
2632 group_nr = GROUP_NR(group_element);
2634 group->num_elements_resolved = 0;
2635 group->choice_pos = 0;
2637 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2638 element_info[i].in_group[group_nr] = FALSE;
2641 for (i = 0; i < actual_group->num_elements; i++)
2643 int element = actual_group->element[i];
2645 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2648 if (IS_GROUP_ELEMENT(element))
2649 ResolveGroupElementExt(element, recursion_depth + 1);
2652 group->element_resolved[group->num_elements_resolved++] = element;
2653 element_info[element].in_group[group_nr] = TRUE;
2658 void ResolveGroupElement(int group_element)
2660 ResolveGroupElementExt(group_element, 0);
2663 void InitElementPropertiesStatic()
2665 static boolean clipboard_elements_initialized = FALSE;
2667 static int ep_diggable[] =
2672 EL_SP_BUGGY_BASE_ACTIVATING,
2675 EL_INVISIBLE_SAND_ACTIVE,
2678 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2679 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2684 EL_SP_BUGGY_BASE_ACTIVE,
2691 static int ep_collectible_only[] =
2713 EL_DYNABOMB_INCREASE_NUMBER,
2714 EL_DYNABOMB_INCREASE_SIZE,
2715 EL_DYNABOMB_INCREASE_POWER,
2733 /* !!! handle separately !!! */
2734 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2740 static int ep_dont_run_into[] =
2742 /* same elements as in 'ep_dont_touch' */
2748 /* same elements as in 'ep_dont_collide_with' */
2760 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2765 EL_SP_BUGGY_BASE_ACTIVE,
2772 static int ep_dont_collide_with[] =
2774 /* same elements as in 'ep_dont_touch' */
2791 static int ep_dont_touch[] =
2801 static int ep_indestructible[] =
2805 EL_ACID_POOL_TOPLEFT,
2806 EL_ACID_POOL_TOPRIGHT,
2807 EL_ACID_POOL_BOTTOMLEFT,
2808 EL_ACID_POOL_BOTTOM,
2809 EL_ACID_POOL_BOTTOMRIGHT,
2810 EL_SP_HARDWARE_GRAY,
2811 EL_SP_HARDWARE_GREEN,
2812 EL_SP_HARDWARE_BLUE,
2814 EL_SP_HARDWARE_YELLOW,
2815 EL_SP_HARDWARE_BASE_1,
2816 EL_SP_HARDWARE_BASE_2,
2817 EL_SP_HARDWARE_BASE_3,
2818 EL_SP_HARDWARE_BASE_4,
2819 EL_SP_HARDWARE_BASE_5,
2820 EL_SP_HARDWARE_BASE_6,
2821 EL_INVISIBLE_STEELWALL,
2822 EL_INVISIBLE_STEELWALL_ACTIVE,
2823 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2824 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2825 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2826 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2827 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2828 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2829 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2830 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2831 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2832 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2833 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2834 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2836 EL_LIGHT_SWITCH_ACTIVE,
2837 EL_SIGN_EXCLAMATION,
2838 EL_SIGN_RADIOACTIVITY,
2845 EL_SIGN_ENTRY_FORBIDDEN,
2846 EL_SIGN_EMERGENCY_EXIT,
2854 EL_STEEL_EXIT_CLOSED,
2856 EL_STEEL_EXIT_OPENING,
2857 EL_STEEL_EXIT_CLOSING,
2858 EL_EM_STEEL_EXIT_CLOSED,
2859 EL_EM_STEEL_EXIT_OPEN,
2860 EL_EM_STEEL_EXIT_OPENING,
2861 EL_EM_STEEL_EXIT_CLOSING,
2862 EL_DC_STEELWALL_1_LEFT,
2863 EL_DC_STEELWALL_1_RIGHT,
2864 EL_DC_STEELWALL_1_TOP,
2865 EL_DC_STEELWALL_1_BOTTOM,
2866 EL_DC_STEELWALL_1_HORIZONTAL,
2867 EL_DC_STEELWALL_1_VERTICAL,
2868 EL_DC_STEELWALL_1_TOPLEFT,
2869 EL_DC_STEELWALL_1_TOPRIGHT,
2870 EL_DC_STEELWALL_1_BOTTOMLEFT,
2871 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2872 EL_DC_STEELWALL_1_TOPLEFT_2,
2873 EL_DC_STEELWALL_1_TOPRIGHT_2,
2874 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2875 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2876 EL_DC_STEELWALL_2_LEFT,
2877 EL_DC_STEELWALL_2_RIGHT,
2878 EL_DC_STEELWALL_2_TOP,
2879 EL_DC_STEELWALL_2_BOTTOM,
2880 EL_DC_STEELWALL_2_HORIZONTAL,
2881 EL_DC_STEELWALL_2_VERTICAL,
2882 EL_DC_STEELWALL_2_MIDDLE,
2883 EL_DC_STEELWALL_2_SINGLE,
2884 EL_STEELWALL_SLIPPERY,
2898 EL_GATE_1_GRAY_ACTIVE,
2899 EL_GATE_2_GRAY_ACTIVE,
2900 EL_GATE_3_GRAY_ACTIVE,
2901 EL_GATE_4_GRAY_ACTIVE,
2910 EL_EM_GATE_1_GRAY_ACTIVE,
2911 EL_EM_GATE_2_GRAY_ACTIVE,
2912 EL_EM_GATE_3_GRAY_ACTIVE,
2913 EL_EM_GATE_4_GRAY_ACTIVE,
2922 EL_EMC_GATE_5_GRAY_ACTIVE,
2923 EL_EMC_GATE_6_GRAY_ACTIVE,
2924 EL_EMC_GATE_7_GRAY_ACTIVE,
2925 EL_EMC_GATE_8_GRAY_ACTIVE,
2927 EL_DC_GATE_WHITE_GRAY,
2928 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2929 EL_DC_GATE_FAKE_GRAY,
2931 EL_SWITCHGATE_OPENING,
2932 EL_SWITCHGATE_CLOSED,
2933 EL_SWITCHGATE_CLOSING,
2935 EL_DC_SWITCHGATE_SWITCH_UP,
2936 EL_DC_SWITCHGATE_SWITCH_DOWN,
2939 EL_TIMEGATE_OPENING,
2941 EL_TIMEGATE_CLOSING,
2943 EL_DC_TIMEGATE_SWITCH,
2944 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2949 EL_TUBE_VERTICAL_LEFT,
2950 EL_TUBE_VERTICAL_RIGHT,
2951 EL_TUBE_HORIZONTAL_UP,
2952 EL_TUBE_HORIZONTAL_DOWN,
2957 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2958 EL_EXPANDABLE_STEELWALL_VERTICAL,
2959 EL_EXPANDABLE_STEELWALL_ANY,
2964 static int ep_slippery[] =
2978 EL_ROBOT_WHEEL_ACTIVE,
2984 EL_ACID_POOL_TOPLEFT,
2985 EL_ACID_POOL_TOPRIGHT,
2995 EL_STEELWALL_SLIPPERY,
2998 EL_EMC_WALL_SLIPPERY_1,
2999 EL_EMC_WALL_SLIPPERY_2,
3000 EL_EMC_WALL_SLIPPERY_3,
3001 EL_EMC_WALL_SLIPPERY_4,
3003 EL_EMC_MAGIC_BALL_ACTIVE,
3008 static int ep_can_change[] =
3013 static int ep_can_move[] =
3015 /* same elements as in 'pb_can_move_into_acid' */
3038 static int ep_can_fall[] =
3052 EL_QUICKSAND_FAST_FULL,
3054 EL_BD_MAGIC_WALL_FULL,
3055 EL_DC_MAGIC_WALL_FULL,
3069 static int ep_can_smash_player[] =
3095 static int ep_can_smash_enemies[] =
3104 static int ep_can_smash_everything[] =
3113 static int ep_explodes_by_fire[] =
3115 /* same elements as in 'ep_explodes_impact' */
3120 /* same elements as in 'ep_explodes_smashed' */
3130 EL_EM_DYNAMITE_ACTIVE,
3131 EL_DYNABOMB_PLAYER_1_ACTIVE,
3132 EL_DYNABOMB_PLAYER_2_ACTIVE,
3133 EL_DYNABOMB_PLAYER_3_ACTIVE,
3134 EL_DYNABOMB_PLAYER_4_ACTIVE,
3135 EL_DYNABOMB_INCREASE_NUMBER,
3136 EL_DYNABOMB_INCREASE_SIZE,
3137 EL_DYNABOMB_INCREASE_POWER,
3138 EL_SP_DISK_RED_ACTIVE,
3152 static int ep_explodes_smashed[] =
3154 /* same elements as in 'ep_explodes_impact' */
3168 static int ep_explodes_impact[] =
3177 static int ep_walkable_over[] =
3181 EL_SOKOBAN_FIELD_EMPTY,
3190 EL_EM_STEEL_EXIT_OPEN,
3192 EL_EM_STEEL_EXIT_OPENING,
3202 EL_GATE_1_GRAY_ACTIVE,
3203 EL_GATE_2_GRAY_ACTIVE,
3204 EL_GATE_3_GRAY_ACTIVE,
3205 EL_GATE_4_GRAY_ACTIVE,
3213 static int ep_walkable_inside[] =
3218 EL_TUBE_VERTICAL_LEFT,
3219 EL_TUBE_VERTICAL_RIGHT,
3220 EL_TUBE_HORIZONTAL_UP,
3221 EL_TUBE_HORIZONTAL_DOWN,
3230 static int ep_walkable_under[] =
3235 static int ep_passable_over[] =
3245 EL_EM_GATE_1_GRAY_ACTIVE,
3246 EL_EM_GATE_2_GRAY_ACTIVE,
3247 EL_EM_GATE_3_GRAY_ACTIVE,
3248 EL_EM_GATE_4_GRAY_ACTIVE,
3257 EL_EMC_GATE_5_GRAY_ACTIVE,
3258 EL_EMC_GATE_6_GRAY_ACTIVE,
3259 EL_EMC_GATE_7_GRAY_ACTIVE,
3260 EL_EMC_GATE_8_GRAY_ACTIVE,
3262 EL_DC_GATE_WHITE_GRAY,
3263 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3270 static int ep_passable_inside[] =
3276 EL_SP_PORT_HORIZONTAL,
3277 EL_SP_PORT_VERTICAL,
3279 EL_SP_GRAVITY_PORT_LEFT,
3280 EL_SP_GRAVITY_PORT_RIGHT,
3281 EL_SP_GRAVITY_PORT_UP,
3282 EL_SP_GRAVITY_PORT_DOWN,
3283 EL_SP_GRAVITY_ON_PORT_LEFT,
3284 EL_SP_GRAVITY_ON_PORT_RIGHT,
3285 EL_SP_GRAVITY_ON_PORT_UP,
3286 EL_SP_GRAVITY_ON_PORT_DOWN,
3287 EL_SP_GRAVITY_OFF_PORT_LEFT,
3288 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3289 EL_SP_GRAVITY_OFF_PORT_UP,
3290 EL_SP_GRAVITY_OFF_PORT_DOWN,
3295 static int ep_passable_under[] =
3300 static int ep_droppable[] =
3305 static int ep_explodes_1x1_old[] =
3310 static int ep_pushable[] =
3322 EL_SOKOBAN_FIELD_FULL,
3331 static int ep_explodes_cross_old[] =
3336 static int ep_protected[] =
3338 /* same elements as in 'ep_walkable_inside' */
3342 EL_TUBE_VERTICAL_LEFT,
3343 EL_TUBE_VERTICAL_RIGHT,
3344 EL_TUBE_HORIZONTAL_UP,
3345 EL_TUBE_HORIZONTAL_DOWN,
3351 /* same elements as in 'ep_passable_over' */
3360 EL_EM_GATE_1_GRAY_ACTIVE,
3361 EL_EM_GATE_2_GRAY_ACTIVE,
3362 EL_EM_GATE_3_GRAY_ACTIVE,
3363 EL_EM_GATE_4_GRAY_ACTIVE,
3372 EL_EMC_GATE_5_GRAY_ACTIVE,
3373 EL_EMC_GATE_6_GRAY_ACTIVE,
3374 EL_EMC_GATE_7_GRAY_ACTIVE,
3375 EL_EMC_GATE_8_GRAY_ACTIVE,
3377 EL_DC_GATE_WHITE_GRAY,
3378 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3382 /* same elements as in 'ep_passable_inside' */
3387 EL_SP_PORT_HORIZONTAL,
3388 EL_SP_PORT_VERTICAL,
3390 EL_SP_GRAVITY_PORT_LEFT,
3391 EL_SP_GRAVITY_PORT_RIGHT,
3392 EL_SP_GRAVITY_PORT_UP,
3393 EL_SP_GRAVITY_PORT_DOWN,
3394 EL_SP_GRAVITY_ON_PORT_LEFT,
3395 EL_SP_GRAVITY_ON_PORT_RIGHT,
3396 EL_SP_GRAVITY_ON_PORT_UP,
3397 EL_SP_GRAVITY_ON_PORT_DOWN,
3398 EL_SP_GRAVITY_OFF_PORT_LEFT,
3399 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3400 EL_SP_GRAVITY_OFF_PORT_UP,
3401 EL_SP_GRAVITY_OFF_PORT_DOWN,
3406 static int ep_throwable[] =
3411 static int ep_can_explode[] =
3413 /* same elements as in 'ep_explodes_impact' */
3418 /* same elements as in 'ep_explodes_smashed' */
3424 /* elements that can explode by explosion or by dragonfire */
3428 EL_EM_DYNAMITE_ACTIVE,
3429 EL_DYNABOMB_PLAYER_1_ACTIVE,
3430 EL_DYNABOMB_PLAYER_2_ACTIVE,
3431 EL_DYNABOMB_PLAYER_3_ACTIVE,
3432 EL_DYNABOMB_PLAYER_4_ACTIVE,
3433 EL_DYNABOMB_INCREASE_NUMBER,
3434 EL_DYNABOMB_INCREASE_SIZE,
3435 EL_DYNABOMB_INCREASE_POWER,
3436 EL_SP_DISK_RED_ACTIVE,
3444 /* elements that can explode only by explosion */
3450 static int ep_gravity_reachable[] =
3456 EL_INVISIBLE_SAND_ACTIVE,
3461 EL_SP_PORT_HORIZONTAL,
3462 EL_SP_PORT_VERTICAL,
3464 EL_SP_GRAVITY_PORT_LEFT,
3465 EL_SP_GRAVITY_PORT_RIGHT,
3466 EL_SP_GRAVITY_PORT_UP,
3467 EL_SP_GRAVITY_PORT_DOWN,
3468 EL_SP_GRAVITY_ON_PORT_LEFT,
3469 EL_SP_GRAVITY_ON_PORT_RIGHT,
3470 EL_SP_GRAVITY_ON_PORT_UP,
3471 EL_SP_GRAVITY_ON_PORT_DOWN,
3472 EL_SP_GRAVITY_OFF_PORT_LEFT,
3473 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3474 EL_SP_GRAVITY_OFF_PORT_UP,
3475 EL_SP_GRAVITY_OFF_PORT_DOWN,
3481 static int ep_player[] =
3488 EL_SOKOBAN_FIELD_PLAYER,
3494 static int ep_can_pass_magic_wall[] =
3508 static int ep_can_pass_dc_magic_wall[] =
3524 static int ep_switchable[] =
3528 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3529 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3530 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3531 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3532 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3533 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3534 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3535 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3536 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3537 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3538 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3539 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3540 EL_SWITCHGATE_SWITCH_UP,
3541 EL_SWITCHGATE_SWITCH_DOWN,
3542 EL_DC_SWITCHGATE_SWITCH_UP,
3543 EL_DC_SWITCHGATE_SWITCH_DOWN,
3545 EL_LIGHT_SWITCH_ACTIVE,
3547 EL_DC_TIMEGATE_SWITCH,
3548 EL_BALLOON_SWITCH_LEFT,
3549 EL_BALLOON_SWITCH_RIGHT,
3550 EL_BALLOON_SWITCH_UP,
3551 EL_BALLOON_SWITCH_DOWN,
3552 EL_BALLOON_SWITCH_ANY,
3553 EL_BALLOON_SWITCH_NONE,
3556 EL_EMC_MAGIC_BALL_SWITCH,
3557 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3562 static int ep_bd_element[] =
3596 static int ep_sp_element[] =
3598 /* should always be valid */
3601 /* standard classic Supaplex elements */
3608 EL_SP_HARDWARE_GRAY,
3616 EL_SP_GRAVITY_PORT_RIGHT,
3617 EL_SP_GRAVITY_PORT_DOWN,
3618 EL_SP_GRAVITY_PORT_LEFT,
3619 EL_SP_GRAVITY_PORT_UP,
3624 EL_SP_PORT_VERTICAL,
3625 EL_SP_PORT_HORIZONTAL,
3631 EL_SP_HARDWARE_BASE_1,
3632 EL_SP_HARDWARE_GREEN,
3633 EL_SP_HARDWARE_BLUE,
3635 EL_SP_HARDWARE_YELLOW,
3636 EL_SP_HARDWARE_BASE_2,
3637 EL_SP_HARDWARE_BASE_3,
3638 EL_SP_HARDWARE_BASE_4,
3639 EL_SP_HARDWARE_BASE_5,
3640 EL_SP_HARDWARE_BASE_6,
3644 /* additional elements that appeared in newer Supaplex levels */
3647 /* additional gravity port elements (not switching, but setting gravity) */
3648 EL_SP_GRAVITY_ON_PORT_LEFT,
3649 EL_SP_GRAVITY_ON_PORT_RIGHT,
3650 EL_SP_GRAVITY_ON_PORT_UP,
3651 EL_SP_GRAVITY_ON_PORT_DOWN,
3652 EL_SP_GRAVITY_OFF_PORT_LEFT,
3653 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3654 EL_SP_GRAVITY_OFF_PORT_UP,
3655 EL_SP_GRAVITY_OFF_PORT_DOWN,
3657 /* more than one Murphy in a level results in an inactive clone */
3660 /* runtime Supaplex elements */
3661 EL_SP_DISK_RED_ACTIVE,
3662 EL_SP_TERMINAL_ACTIVE,
3663 EL_SP_BUGGY_BASE_ACTIVATING,
3664 EL_SP_BUGGY_BASE_ACTIVE,
3671 static int ep_sb_element[] =
3676 EL_SOKOBAN_FIELD_EMPTY,
3677 EL_SOKOBAN_FIELD_FULL,
3678 EL_SOKOBAN_FIELD_PLAYER,
3683 EL_INVISIBLE_STEELWALL,
3688 static int ep_gem[] =
3700 static int ep_food_dark_yamyam[] =
3728 static int ep_food_penguin[] =
3742 static int ep_food_pig[] =
3754 static int ep_historic_wall[] =
3765 EL_GATE_1_GRAY_ACTIVE,
3766 EL_GATE_2_GRAY_ACTIVE,
3767 EL_GATE_3_GRAY_ACTIVE,
3768 EL_GATE_4_GRAY_ACTIVE,
3777 EL_EM_GATE_1_GRAY_ACTIVE,
3778 EL_EM_GATE_2_GRAY_ACTIVE,
3779 EL_EM_GATE_3_GRAY_ACTIVE,
3780 EL_EM_GATE_4_GRAY_ACTIVE,
3787 EL_EXPANDABLE_WALL_HORIZONTAL,
3788 EL_EXPANDABLE_WALL_VERTICAL,
3789 EL_EXPANDABLE_WALL_ANY,
3790 EL_EXPANDABLE_WALL_GROWING,
3791 EL_BD_EXPANDABLE_WALL,
3798 EL_SP_HARDWARE_GRAY,
3799 EL_SP_HARDWARE_GREEN,
3800 EL_SP_HARDWARE_BLUE,
3802 EL_SP_HARDWARE_YELLOW,
3803 EL_SP_HARDWARE_BASE_1,
3804 EL_SP_HARDWARE_BASE_2,
3805 EL_SP_HARDWARE_BASE_3,
3806 EL_SP_HARDWARE_BASE_4,
3807 EL_SP_HARDWARE_BASE_5,
3808 EL_SP_HARDWARE_BASE_6,
3810 EL_SP_TERMINAL_ACTIVE,
3813 EL_INVISIBLE_STEELWALL,
3814 EL_INVISIBLE_STEELWALL_ACTIVE,
3816 EL_INVISIBLE_WALL_ACTIVE,
3817 EL_STEELWALL_SLIPPERY,
3834 static int ep_historic_solid[] =
3838 EL_EXPANDABLE_WALL_HORIZONTAL,
3839 EL_EXPANDABLE_WALL_VERTICAL,
3840 EL_EXPANDABLE_WALL_ANY,
3841 EL_BD_EXPANDABLE_WALL,
3854 EL_QUICKSAND_FILLING,
3855 EL_QUICKSAND_EMPTYING,
3857 EL_MAGIC_WALL_ACTIVE,
3858 EL_MAGIC_WALL_EMPTYING,
3859 EL_MAGIC_WALL_FILLING,
3863 EL_BD_MAGIC_WALL_ACTIVE,
3864 EL_BD_MAGIC_WALL_EMPTYING,
3865 EL_BD_MAGIC_WALL_FULL,
3866 EL_BD_MAGIC_WALL_FILLING,
3867 EL_BD_MAGIC_WALL_DEAD,
3876 EL_SP_TERMINAL_ACTIVE,
3880 EL_INVISIBLE_WALL_ACTIVE,
3881 EL_SWITCHGATE_SWITCH_UP,
3882 EL_SWITCHGATE_SWITCH_DOWN,
3883 EL_DC_SWITCHGATE_SWITCH_UP,
3884 EL_DC_SWITCHGATE_SWITCH_DOWN,
3886 EL_TIMEGATE_SWITCH_ACTIVE,
3887 EL_DC_TIMEGATE_SWITCH,
3888 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3900 /* the following elements are a direct copy of "indestructible" elements,
3901 except "EL_ACID", which is "indestructible", but not "solid"! */
3906 EL_ACID_POOL_TOPLEFT,
3907 EL_ACID_POOL_TOPRIGHT,
3908 EL_ACID_POOL_BOTTOMLEFT,
3909 EL_ACID_POOL_BOTTOM,
3910 EL_ACID_POOL_BOTTOMRIGHT,
3911 EL_SP_HARDWARE_GRAY,
3912 EL_SP_HARDWARE_GREEN,
3913 EL_SP_HARDWARE_BLUE,
3915 EL_SP_HARDWARE_YELLOW,
3916 EL_SP_HARDWARE_BASE_1,
3917 EL_SP_HARDWARE_BASE_2,
3918 EL_SP_HARDWARE_BASE_3,
3919 EL_SP_HARDWARE_BASE_4,
3920 EL_SP_HARDWARE_BASE_5,
3921 EL_SP_HARDWARE_BASE_6,
3922 EL_INVISIBLE_STEELWALL,
3923 EL_INVISIBLE_STEELWALL_ACTIVE,
3924 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3925 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3926 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3927 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3928 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3929 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3930 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3931 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3932 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3933 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3934 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3935 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3937 EL_LIGHT_SWITCH_ACTIVE,
3938 EL_SIGN_EXCLAMATION,
3939 EL_SIGN_RADIOACTIVITY,
3946 EL_SIGN_ENTRY_FORBIDDEN,
3947 EL_SIGN_EMERGENCY_EXIT,
3955 EL_STEEL_EXIT_CLOSED,
3957 EL_DC_STEELWALL_1_LEFT,
3958 EL_DC_STEELWALL_1_RIGHT,
3959 EL_DC_STEELWALL_1_TOP,
3960 EL_DC_STEELWALL_1_BOTTOM,
3961 EL_DC_STEELWALL_1_HORIZONTAL,
3962 EL_DC_STEELWALL_1_VERTICAL,
3963 EL_DC_STEELWALL_1_TOPLEFT,
3964 EL_DC_STEELWALL_1_TOPRIGHT,
3965 EL_DC_STEELWALL_1_BOTTOMLEFT,
3966 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3967 EL_DC_STEELWALL_1_TOPLEFT_2,
3968 EL_DC_STEELWALL_1_TOPRIGHT_2,
3969 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3970 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3971 EL_DC_STEELWALL_2_LEFT,
3972 EL_DC_STEELWALL_2_RIGHT,
3973 EL_DC_STEELWALL_2_TOP,
3974 EL_DC_STEELWALL_2_BOTTOM,
3975 EL_DC_STEELWALL_2_HORIZONTAL,
3976 EL_DC_STEELWALL_2_VERTICAL,
3977 EL_DC_STEELWALL_2_MIDDLE,
3978 EL_DC_STEELWALL_2_SINGLE,
3979 EL_STEELWALL_SLIPPERY,
3993 EL_GATE_1_GRAY_ACTIVE,
3994 EL_GATE_2_GRAY_ACTIVE,
3995 EL_GATE_3_GRAY_ACTIVE,
3996 EL_GATE_4_GRAY_ACTIVE,
4005 EL_EM_GATE_1_GRAY_ACTIVE,
4006 EL_EM_GATE_2_GRAY_ACTIVE,
4007 EL_EM_GATE_3_GRAY_ACTIVE,
4008 EL_EM_GATE_4_GRAY_ACTIVE,
4010 EL_SWITCHGATE_OPENING,
4011 EL_SWITCHGATE_CLOSED,
4012 EL_SWITCHGATE_CLOSING,
4014 EL_TIMEGATE_OPENING,
4016 EL_TIMEGATE_CLOSING,
4020 EL_TUBE_VERTICAL_LEFT,
4021 EL_TUBE_VERTICAL_RIGHT,
4022 EL_TUBE_HORIZONTAL_UP,
4023 EL_TUBE_HORIZONTAL_DOWN,
4032 static int ep_classic_enemy[] =
4049 static int ep_belt[] =
4051 EL_CONVEYOR_BELT_1_LEFT,
4052 EL_CONVEYOR_BELT_1_MIDDLE,
4053 EL_CONVEYOR_BELT_1_RIGHT,
4054 EL_CONVEYOR_BELT_2_LEFT,
4055 EL_CONVEYOR_BELT_2_MIDDLE,
4056 EL_CONVEYOR_BELT_2_RIGHT,
4057 EL_CONVEYOR_BELT_3_LEFT,
4058 EL_CONVEYOR_BELT_3_MIDDLE,
4059 EL_CONVEYOR_BELT_3_RIGHT,
4060 EL_CONVEYOR_BELT_4_LEFT,
4061 EL_CONVEYOR_BELT_4_MIDDLE,
4062 EL_CONVEYOR_BELT_4_RIGHT,
4067 static int ep_belt_active[] =
4069 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
4070 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
4071 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
4072 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
4073 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
4074 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
4075 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
4076 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
4077 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
4078 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
4079 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
4080 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
4085 static int ep_belt_switch[] =
4087 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4088 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4089 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4090 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4091 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4092 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4093 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4094 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4095 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4096 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4097 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4098 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4103 static int ep_tube[] =
4110 EL_TUBE_HORIZONTAL_UP,
4111 EL_TUBE_HORIZONTAL_DOWN,
4113 EL_TUBE_VERTICAL_LEFT,
4114 EL_TUBE_VERTICAL_RIGHT,
4120 static int ep_acid_pool[] =
4122 EL_ACID_POOL_TOPLEFT,
4123 EL_ACID_POOL_TOPRIGHT,
4124 EL_ACID_POOL_BOTTOMLEFT,
4125 EL_ACID_POOL_BOTTOM,
4126 EL_ACID_POOL_BOTTOMRIGHT,
4131 static int ep_keygate[] =
4141 EL_GATE_1_GRAY_ACTIVE,
4142 EL_GATE_2_GRAY_ACTIVE,
4143 EL_GATE_3_GRAY_ACTIVE,
4144 EL_GATE_4_GRAY_ACTIVE,
4153 EL_EM_GATE_1_GRAY_ACTIVE,
4154 EL_EM_GATE_2_GRAY_ACTIVE,
4155 EL_EM_GATE_3_GRAY_ACTIVE,
4156 EL_EM_GATE_4_GRAY_ACTIVE,
4165 EL_EMC_GATE_5_GRAY_ACTIVE,
4166 EL_EMC_GATE_6_GRAY_ACTIVE,
4167 EL_EMC_GATE_7_GRAY_ACTIVE,
4168 EL_EMC_GATE_8_GRAY_ACTIVE,
4170 EL_DC_GATE_WHITE_GRAY,
4171 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4176 static int ep_amoeboid[] =
4188 static int ep_amoebalive[] =
4199 static int ep_has_editor_content[] =
4205 EL_SOKOBAN_FIELD_PLAYER,
4222 static int ep_can_turn_each_move[] =
4224 /* !!! do something with this one !!! */
4228 static int ep_can_grow[] =
4242 static int ep_active_bomb[] =
4245 EL_EM_DYNAMITE_ACTIVE,
4246 EL_DYNABOMB_PLAYER_1_ACTIVE,
4247 EL_DYNABOMB_PLAYER_2_ACTIVE,
4248 EL_DYNABOMB_PLAYER_3_ACTIVE,
4249 EL_DYNABOMB_PLAYER_4_ACTIVE,
4250 EL_SP_DISK_RED_ACTIVE,
4255 static int ep_inactive[] =
4265 EL_QUICKSAND_FAST_EMPTY,
4288 EL_GATE_1_GRAY_ACTIVE,
4289 EL_GATE_2_GRAY_ACTIVE,
4290 EL_GATE_3_GRAY_ACTIVE,
4291 EL_GATE_4_GRAY_ACTIVE,
4300 EL_EM_GATE_1_GRAY_ACTIVE,
4301 EL_EM_GATE_2_GRAY_ACTIVE,
4302 EL_EM_GATE_3_GRAY_ACTIVE,
4303 EL_EM_GATE_4_GRAY_ACTIVE,
4312 EL_EMC_GATE_5_GRAY_ACTIVE,
4313 EL_EMC_GATE_6_GRAY_ACTIVE,
4314 EL_EMC_GATE_7_GRAY_ACTIVE,
4315 EL_EMC_GATE_8_GRAY_ACTIVE,
4317 EL_DC_GATE_WHITE_GRAY,
4318 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4319 EL_DC_GATE_FAKE_GRAY,
4322 EL_INVISIBLE_STEELWALL,
4330 EL_WALL_EMERALD_YELLOW,
4331 EL_DYNABOMB_INCREASE_NUMBER,
4332 EL_DYNABOMB_INCREASE_SIZE,
4333 EL_DYNABOMB_INCREASE_POWER,
4337 EL_SOKOBAN_FIELD_EMPTY,
4338 EL_SOKOBAN_FIELD_FULL,
4339 EL_WALL_EMERALD_RED,
4340 EL_WALL_EMERALD_PURPLE,
4341 EL_ACID_POOL_TOPLEFT,
4342 EL_ACID_POOL_TOPRIGHT,
4343 EL_ACID_POOL_BOTTOMLEFT,
4344 EL_ACID_POOL_BOTTOM,
4345 EL_ACID_POOL_BOTTOMRIGHT,
4349 EL_BD_MAGIC_WALL_DEAD,
4351 EL_DC_MAGIC_WALL_DEAD,
4352 EL_AMOEBA_TO_DIAMOND,
4360 EL_SP_GRAVITY_PORT_RIGHT,
4361 EL_SP_GRAVITY_PORT_DOWN,
4362 EL_SP_GRAVITY_PORT_LEFT,
4363 EL_SP_GRAVITY_PORT_UP,
4364 EL_SP_PORT_HORIZONTAL,
4365 EL_SP_PORT_VERTICAL,
4376 EL_SP_HARDWARE_GRAY,
4377 EL_SP_HARDWARE_GREEN,
4378 EL_SP_HARDWARE_BLUE,
4380 EL_SP_HARDWARE_YELLOW,
4381 EL_SP_HARDWARE_BASE_1,
4382 EL_SP_HARDWARE_BASE_2,
4383 EL_SP_HARDWARE_BASE_3,
4384 EL_SP_HARDWARE_BASE_4,
4385 EL_SP_HARDWARE_BASE_5,
4386 EL_SP_HARDWARE_BASE_6,
4387 EL_SP_GRAVITY_ON_PORT_LEFT,
4388 EL_SP_GRAVITY_ON_PORT_RIGHT,
4389 EL_SP_GRAVITY_ON_PORT_UP,
4390 EL_SP_GRAVITY_ON_PORT_DOWN,
4391 EL_SP_GRAVITY_OFF_PORT_LEFT,
4392 EL_SP_GRAVITY_OFF_PORT_RIGHT,
4393 EL_SP_GRAVITY_OFF_PORT_UP,
4394 EL_SP_GRAVITY_OFF_PORT_DOWN,
4395 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4396 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4397 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4398 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4399 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4400 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4401 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4402 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4403 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4404 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4405 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4406 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4407 EL_SIGN_EXCLAMATION,
4408 EL_SIGN_RADIOACTIVITY,
4415 EL_SIGN_ENTRY_FORBIDDEN,
4416 EL_SIGN_EMERGENCY_EXIT,
4424 EL_DC_STEELWALL_1_LEFT,
4425 EL_DC_STEELWALL_1_RIGHT,
4426 EL_DC_STEELWALL_1_TOP,
4427 EL_DC_STEELWALL_1_BOTTOM,
4428 EL_DC_STEELWALL_1_HORIZONTAL,
4429 EL_DC_STEELWALL_1_VERTICAL,
4430 EL_DC_STEELWALL_1_TOPLEFT,
4431 EL_DC_STEELWALL_1_TOPRIGHT,
4432 EL_DC_STEELWALL_1_BOTTOMLEFT,
4433 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4434 EL_DC_STEELWALL_1_TOPLEFT_2,
4435 EL_DC_STEELWALL_1_TOPRIGHT_2,
4436 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4437 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4438 EL_DC_STEELWALL_2_LEFT,
4439 EL_DC_STEELWALL_2_RIGHT,
4440 EL_DC_STEELWALL_2_TOP,
4441 EL_DC_STEELWALL_2_BOTTOM,
4442 EL_DC_STEELWALL_2_HORIZONTAL,
4443 EL_DC_STEELWALL_2_VERTICAL,
4444 EL_DC_STEELWALL_2_MIDDLE,
4445 EL_DC_STEELWALL_2_SINGLE,
4446 EL_STEELWALL_SLIPPERY,
4451 EL_EMC_WALL_SLIPPERY_1,
4452 EL_EMC_WALL_SLIPPERY_2,
4453 EL_EMC_WALL_SLIPPERY_3,
4454 EL_EMC_WALL_SLIPPERY_4,
4475 static int ep_em_slippery_wall[] =
4480 static int ep_gfx_crumbled[] =
4491 static int ep_editor_cascade_active[] =
4493 EL_INTERNAL_CASCADE_BD_ACTIVE,
4494 EL_INTERNAL_CASCADE_EM_ACTIVE,
4495 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4496 EL_INTERNAL_CASCADE_RND_ACTIVE,
4497 EL_INTERNAL_CASCADE_SB_ACTIVE,
4498 EL_INTERNAL_CASCADE_SP_ACTIVE,
4499 EL_INTERNAL_CASCADE_DC_ACTIVE,
4500 EL_INTERNAL_CASCADE_DX_ACTIVE,
4501 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4502 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4503 EL_INTERNAL_CASCADE_CE_ACTIVE,
4504 EL_INTERNAL_CASCADE_GE_ACTIVE,
4505 EL_INTERNAL_CASCADE_REF_ACTIVE,
4506 EL_INTERNAL_CASCADE_USER_ACTIVE,
4507 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4512 static int ep_editor_cascade_inactive[] =
4514 EL_INTERNAL_CASCADE_BD,
4515 EL_INTERNAL_CASCADE_EM,
4516 EL_INTERNAL_CASCADE_EMC,
4517 EL_INTERNAL_CASCADE_RND,
4518 EL_INTERNAL_CASCADE_SB,
4519 EL_INTERNAL_CASCADE_SP,
4520 EL_INTERNAL_CASCADE_DC,
4521 EL_INTERNAL_CASCADE_DX,
4522 EL_INTERNAL_CASCADE_CHARS,
4523 EL_INTERNAL_CASCADE_STEEL_CHARS,
4524 EL_INTERNAL_CASCADE_CE,
4525 EL_INTERNAL_CASCADE_GE,
4526 EL_INTERNAL_CASCADE_REF,
4527 EL_INTERNAL_CASCADE_USER,
4528 EL_INTERNAL_CASCADE_DYNAMIC,
4533 static int ep_obsolete[] =
4537 EL_EM_KEY_1_FILE_OBSOLETE,
4538 EL_EM_KEY_2_FILE_OBSOLETE,
4539 EL_EM_KEY_3_FILE_OBSOLETE,
4540 EL_EM_KEY_4_FILE_OBSOLETE,
4541 EL_ENVELOPE_OBSOLETE,
4550 } element_properties[] =
4552 { ep_diggable, EP_DIGGABLE },
4553 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4554 { ep_dont_run_into, EP_DONT_RUN_INTO },
4555 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4556 { ep_dont_touch, EP_DONT_TOUCH },
4557 { ep_indestructible, EP_INDESTRUCTIBLE },
4558 { ep_slippery, EP_SLIPPERY },
4559 { ep_can_change, EP_CAN_CHANGE },
4560 { ep_can_move, EP_CAN_MOVE },
4561 { ep_can_fall, EP_CAN_FALL },
4562 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4563 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4564 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4565 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4566 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4567 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4568 { ep_walkable_over, EP_WALKABLE_OVER },
4569 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4570 { ep_walkable_under, EP_WALKABLE_UNDER },
4571 { ep_passable_over, EP_PASSABLE_OVER },
4572 { ep_passable_inside, EP_PASSABLE_INSIDE },
4573 { ep_passable_under, EP_PASSABLE_UNDER },
4574 { ep_droppable, EP_DROPPABLE },
4575 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4576 { ep_pushable, EP_PUSHABLE },
4577 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4578 { ep_protected, EP_PROTECTED },
4579 { ep_throwable, EP_THROWABLE },
4580 { ep_can_explode, EP_CAN_EXPLODE },
4581 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4583 { ep_player, EP_PLAYER },
4584 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4585 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4586 { ep_switchable, EP_SWITCHABLE },
4587 { ep_bd_element, EP_BD_ELEMENT },
4588 { ep_sp_element, EP_SP_ELEMENT },
4589 { ep_sb_element, EP_SB_ELEMENT },
4591 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4592 { ep_food_penguin, EP_FOOD_PENGUIN },
4593 { ep_food_pig, EP_FOOD_PIG },
4594 { ep_historic_wall, EP_HISTORIC_WALL },
4595 { ep_historic_solid, EP_HISTORIC_SOLID },
4596 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4597 { ep_belt, EP_BELT },
4598 { ep_belt_active, EP_BELT_ACTIVE },
4599 { ep_belt_switch, EP_BELT_SWITCH },
4600 { ep_tube, EP_TUBE },
4601 { ep_acid_pool, EP_ACID_POOL },
4602 { ep_keygate, EP_KEYGATE },
4603 { ep_amoeboid, EP_AMOEBOID },
4604 { ep_amoebalive, EP_AMOEBALIVE },
4605 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4606 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4607 { ep_can_grow, EP_CAN_GROW },
4608 { ep_active_bomb, EP_ACTIVE_BOMB },
4609 { ep_inactive, EP_INACTIVE },
4611 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4613 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4615 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4616 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4618 { ep_obsolete, EP_OBSOLETE },
4625 /* always start with reliable default values (element has no properties) */
4626 /* (but never initialize clipboard elements after the very first time) */
4627 /* (to be able to use clipboard elements between several levels) */
4628 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4629 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4630 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4631 SET_PROPERTY(i, j, FALSE);
4633 /* set all base element properties from above array definitions */
4634 for (i = 0; element_properties[i].elements != NULL; i++)
4635 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4636 SET_PROPERTY((element_properties[i].elements)[j],
4637 element_properties[i].property, TRUE);
4639 /* copy properties to some elements that are only stored in level file */
4640 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4641 for (j = 0; copy_properties[j][0] != -1; j++)
4642 if (HAS_PROPERTY(copy_properties[j][0], i))
4643 for (k = 1; k <= 4; k++)
4644 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4646 /* set static element properties that are not listed in array definitions */
4647 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4648 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4650 clipboard_elements_initialized = TRUE;
4653 void InitElementPropertiesEngine(int engine_version)
4655 static int no_wall_properties[] =
4658 EP_COLLECTIBLE_ONLY,
4660 EP_DONT_COLLIDE_WITH,
4663 EP_CAN_SMASH_PLAYER,
4664 EP_CAN_SMASH_ENEMIES,
4665 EP_CAN_SMASH_EVERYTHING,
4670 EP_FOOD_DARK_YAMYAM,
4686 /* important: after initialization in InitElementPropertiesStatic(), the
4687 elements are not again initialized to a default value; therefore all
4688 changes have to make sure that they leave the element with a defined
4689 property (which means that conditional property changes must be set to
4690 a reliable default value before) */
4692 /* resolve group elements */
4693 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4694 ResolveGroupElement(EL_GROUP_START + i);
4696 /* set all special, combined or engine dependent element properties */
4697 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4699 /* do not change (already initialized) clipboard elements here */
4700 if (IS_CLIPBOARD_ELEMENT(i))
4703 /* ---------- INACTIVE ------------------------------------------------- */
4704 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4705 i <= EL_CHAR_END) ||
4706 (i >= EL_STEEL_CHAR_START &&
4707 i <= EL_STEEL_CHAR_END)));
4709 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4710 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4711 IS_WALKABLE_INSIDE(i) ||
4712 IS_WALKABLE_UNDER(i)));
4714 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4715 IS_PASSABLE_INSIDE(i) ||
4716 IS_PASSABLE_UNDER(i)));
4718 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4719 IS_PASSABLE_OVER(i)));
4721 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4722 IS_PASSABLE_INSIDE(i)));
4724 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4725 IS_PASSABLE_UNDER(i)));
4727 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4730 /* ---------- COLLECTIBLE ---------------------------------------------- */
4731 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4735 /* ---------- SNAPPABLE ------------------------------------------------ */
4736 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4737 IS_COLLECTIBLE(i) ||
4741 /* ---------- WALL ----------------------------------------------------- */
4742 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4744 for (j = 0; no_wall_properties[j] != -1; j++)
4745 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4746 i >= EL_FIRST_RUNTIME_UNREAL)
4747 SET_PROPERTY(i, EP_WALL, FALSE);
4749 if (IS_HISTORIC_WALL(i))
4750 SET_PROPERTY(i, EP_WALL, TRUE);
4752 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4753 if (engine_version < VERSION_IDENT(2,2,0,0))
4754 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4756 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4758 !IS_COLLECTIBLE(i)));
4760 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4761 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4762 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4764 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4765 IS_INDESTRUCTIBLE(i)));
4767 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4769 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4770 else if (engine_version < VERSION_IDENT(2,2,0,0))
4771 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4773 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4777 if (IS_CUSTOM_ELEMENT(i))
4779 /* these are additional properties which are initially false when set */
4781 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4783 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4784 if (DONT_COLLIDE_WITH(i))
4785 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4787 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4788 if (CAN_SMASH_EVERYTHING(i))
4789 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4790 if (CAN_SMASH_ENEMIES(i))
4791 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4794 /* ---------- CAN_SMASH ------------------------------------------------ */
4795 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4796 CAN_SMASH_ENEMIES(i) ||
4797 CAN_SMASH_EVERYTHING(i)));
4799 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4800 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4801 EXPLODES_BY_FIRE(i)));
4803 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4804 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4805 EXPLODES_SMASHED(i)));
4807 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4808 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4809 EXPLODES_IMPACT(i)));
4811 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4812 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4814 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4815 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4816 i == EL_BLACK_ORB));
4818 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4819 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4821 IS_CUSTOM_ELEMENT(i)));
4823 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4824 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4825 i == EL_SP_ELECTRON));
4827 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4828 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4829 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4830 getMoveIntoAcidProperty(&level, i));
4832 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4833 if (MAYBE_DONT_COLLIDE_WITH(i))
4834 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4835 getDontCollideWithProperty(&level, i));
4837 /* ---------- SP_PORT -------------------------------------------------- */
4838 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4839 IS_PASSABLE_INSIDE(i)));
4841 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4842 for (j = 0; j < level.num_android_clone_elements; j++)
4843 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4845 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4847 /* ---------- CAN_CHANGE ----------------------------------------------- */
4848 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4849 for (j = 0; j < element_info[i].num_change_pages; j++)
4850 if (element_info[i].change_page[j].can_change)
4851 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4853 /* ---------- HAS_ACTION ----------------------------------------------- */
4854 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4855 for (j = 0; j < element_info[i].num_change_pages; j++)
4856 if (element_info[i].change_page[j].has_action)
4857 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4859 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4860 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4863 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4865 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4866 element_info[i].crumbled[ACTION_DEFAULT] !=
4867 element_info[i].graphic[ACTION_DEFAULT]);
4869 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
4870 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4871 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
4874 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4875 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4876 IS_EDITOR_CASCADE_INACTIVE(i)));
4879 /* dynamically adjust element properties according to game engine version */
4881 static int ep_em_slippery_wall[] =
4886 EL_EXPANDABLE_WALL_HORIZONTAL,
4887 EL_EXPANDABLE_WALL_VERTICAL,
4888 EL_EXPANDABLE_WALL_ANY,
4889 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4890 EL_EXPANDABLE_STEELWALL_VERTICAL,
4891 EL_EXPANDABLE_STEELWALL_ANY,
4892 EL_EXPANDABLE_STEELWALL_GROWING,
4896 static int ep_em_explodes_by_fire[] =
4899 EL_EM_DYNAMITE_ACTIVE,
4904 /* special EM style gems behaviour */
4905 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4906 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4907 level.em_slippery_gems);
4909 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4910 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4911 (level.em_slippery_gems &&
4912 engine_version > VERSION_IDENT(2,0,1,0)));
4914 /* special EM style explosion behaviour regarding chain reactions */
4915 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4916 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4917 level.em_explodes_by_fire);
4920 /* this is needed because some graphics depend on element properties */
4921 if (game_status == GAME_MODE_PLAYING)
4922 InitElementGraphicInfo();
4925 void InitElementPropertiesAfterLoading(int engine_version)
4929 /* set some other uninitialized values of custom elements in older levels */
4930 if (engine_version < VERSION_IDENT(3,1,0,0))
4932 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4934 int element = EL_CUSTOM_START + i;
4936 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4938 element_info[element].explosion_delay = 17;
4939 element_info[element].ignition_delay = 8;
4944 void InitElementPropertiesGfxElement()
4948 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4950 struct ElementInfo *ei = &element_info[i];
4952 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4956 static void InitGlobal()
4961 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4963 /* check if element_name_info entry defined for each element in "main.h" */
4964 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4965 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4967 element_info[i].token_name = element_name_info[i].token_name;
4968 element_info[i].class_name = element_name_info[i].class_name;
4969 element_info[i].editor_description= element_name_info[i].editor_description;
4972 printf("%04d: %s\n", i, element_name_info[i].token_name);
4976 /* create hash from image config list */
4977 image_config_hash = newSetupFileHash();
4978 for (i = 0; image_config[i].token != NULL; i++)
4979 setHashEntry(image_config_hash,
4980 image_config[i].token,
4981 image_config[i].value);
4983 /* create hash from element token list */
4984 element_token_hash = newSetupFileHash();
4985 for (i = 0; element_name_info[i].token_name != NULL; i++)
4986 setHashEntry(element_token_hash,
4987 element_name_info[i].token_name,
4990 /* create hash from graphic token list */
4991 graphic_token_hash = newSetupFileHash();
4992 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4993 if (strSuffix(image_config[i].value, ".pcx") ||
4994 strSuffix(image_config[i].value, ".wav") ||
4995 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4996 setHashEntry(graphic_token_hash,
4997 image_config[i].token,
4998 int2str(graphic++, 0));
5000 /* create hash from font token list */
5001 font_token_hash = newSetupFileHash();
5002 for (i = 0; font_info[i].token_name != NULL; i++)
5003 setHashEntry(font_token_hash,
5004 font_info[i].token_name,
5007 /* always start with reliable default values (all elements) */
5008 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5009 ActiveElement[i] = i;
5011 /* now add all entries that have an active state (active elements) */
5012 for (i = 0; element_with_active_state[i].element != -1; i++)
5014 int element = element_with_active_state[i].element;
5015 int element_active = element_with_active_state[i].element_active;
5017 ActiveElement[element] = element_active;
5020 /* always start with reliable default values (all buttons) */
5021 for (i = 0; i < NUM_IMAGE_FILES; i++)
5022 ActiveButton[i] = i;
5024 /* now add all entries that have an active state (active buttons) */
5025 for (i = 0; button_with_active_state[i].button != -1; i++)
5027 int button = button_with_active_state[i].button;
5028 int button_active = button_with_active_state[i].button_active;
5030 ActiveButton[button] = button_active;
5033 /* always start with reliable default values (all fonts) */
5034 for (i = 0; i < NUM_FONTS; i++)
5037 /* now add all entries that have an active state (active fonts) */
5038 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
5040 int font = font_with_active_state[i].font_nr;
5041 int font_active = font_with_active_state[i].font_nr_active;
5043 ActiveFont[font] = font_active;
5046 global.autoplay_leveldir = NULL;
5047 global.convert_leveldir = NULL;
5048 global.create_images_dir = NULL;
5050 global.frames_per_second = 0;
5051 global.fps_slowdown = FALSE;
5052 global.fps_slowdown_factor = 1;
5054 global.border_status = GAME_MODE_MAIN;
5056 global.fading_status = GAME_MODE_MAIN;
5057 global.fading_type = TYPE_ENTER_MENU;
5060 global.use_envelope_request = FALSE; /* !!! MOVE TO ARTWORK CONFIG !!! */
5063 void Execute_Command(char *command)
5067 if (strEqual(command, "print graphicsinfo.conf"))
5069 printf("# You can configure additional/alternative image files here.\n");
5070 printf("# (The entries below are default and therefore commented out.)\n");
5072 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
5074 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5077 for (i = 0; image_config[i].token != NULL; i++)
5078 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
5079 image_config[i].value));
5083 else if (strEqual(command, "print soundsinfo.conf"))
5085 printf("# You can configure additional/alternative sound files here.\n");
5086 printf("# (The entries below are default and therefore commented out.)\n");
5088 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
5090 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5093 for (i = 0; sound_config[i].token != NULL; i++)
5094 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
5095 sound_config[i].value));
5099 else if (strEqual(command, "print musicinfo.conf"))
5101 printf("# You can configure additional/alternative music files here.\n");
5102 printf("# (The entries below are default and therefore commented out.)\n");
5104 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
5106 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5109 for (i = 0; music_config[i].token != NULL; i++)
5110 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
5111 music_config[i].value));
5115 else if (strEqual(command, "print editorsetup.conf"))
5117 printf("# You can configure your personal editor element list here.\n");
5118 printf("# (The entries below are default and therefore commented out.)\n");
5121 /* this is needed to be able to check element list for cascade elements */
5122 InitElementPropertiesStatic();
5123 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5125 PrintEditorElementList();
5129 else if (strEqual(command, "print helpanim.conf"))
5131 printf("# You can configure different element help animations here.\n");
5132 printf("# (The entries below are default and therefore commented out.)\n");
5135 for (i = 0; helpanim_config[i].token != NULL; i++)
5137 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
5138 helpanim_config[i].value));
5140 if (strEqual(helpanim_config[i].token, "end"))
5146 else if (strEqual(command, "print helptext.conf"))
5148 printf("# You can configure different element help text here.\n");
5149 printf("# (The entries below are default and therefore commented out.)\n");
5152 for (i = 0; helptext_config[i].token != NULL; i++)
5153 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
5154 helptext_config[i].value));
5158 else if (strPrefix(command, "dump level "))
5160 char *filename = &command[11];
5162 if (!fileExists(filename))
5163 Error(ERR_EXIT, "cannot open file '%s'", filename);
5165 LoadLevelFromFilename(&level, filename);
5170 else if (strPrefix(command, "dump tape "))
5172 char *filename = &command[10];
5174 if (!fileExists(filename))
5175 Error(ERR_EXIT, "cannot open file '%s'", filename);
5177 LoadTapeFromFilename(filename);
5182 else if (strPrefix(command, "autoplay "))
5184 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
5186 while (*str_ptr != '\0') /* continue parsing string */
5188 /* cut leading whitespace from string, replace it by string terminator */
5189 while (*str_ptr == ' ' || *str_ptr == '\t')
5192 if (*str_ptr == '\0') /* end of string reached */
5195 if (global.autoplay_leveldir == NULL) /* read level set string */
5197 global.autoplay_leveldir = str_ptr;
5198 global.autoplay_all = TRUE; /* default: play all tapes */
5200 for (i = 0; i < MAX_TAPES_PER_SET; i++)
5201 global.autoplay_level[i] = FALSE;
5203 else /* read level number string */
5205 int level_nr = atoi(str_ptr); /* get level_nr value */
5207 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5208 global.autoplay_level[level_nr] = TRUE;
5210 global.autoplay_all = FALSE;
5213 /* advance string pointer to the next whitespace (or end of string) */
5214 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5218 else if (strPrefix(command, "convert "))
5220 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
5221 char *str_ptr = strchr(str_copy, ' ');
5223 global.convert_leveldir = str_copy;
5224 global.convert_level_nr = -1;
5226 if (str_ptr != NULL) /* level number follows */
5228 *str_ptr++ = '\0'; /* terminate leveldir string */
5229 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
5232 else if (strPrefix(command, "create images "))
5234 #if defined(TARGET_SDL)
5235 global.create_images_dir = getStringCopy(&command[14]);
5237 if (access(global.create_images_dir, W_OK) != 0)
5238 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
5239 global.create_images_dir);
5241 Error(ERR_EXIT, "command only available for SDL target");
5246 #if defined(TARGET_SDL)
5247 #if !defined(TARGET_SDL2)
5248 else if (strEqual(command, "SDL_ListModes"))
5253 SDL_Init(SDL_INIT_VIDEO);
5255 /* get available fullscreen/hardware modes */
5256 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
5258 /* check if there are any modes available */
5261 printf("No modes available!\n");
5266 /* check if our resolution is restricted */
5267 if (modes == (SDL_Rect **)-1)
5269 printf("All resolutions available.\n");
5273 printf("Available Modes:\n");
5275 for(i = 0; modes[i]; i++)
5276 printf(" %d x %d\n", modes[i]->w, modes[i]->h);
5287 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
5291 static void InitSetup()
5293 LoadSetup(); /* global setup info */
5295 /* set some options from setup file */
5297 if (setup.options.verbose)
5298 options.verbose = TRUE;
5301 static void InitGameInfo()
5303 game.restart_level = FALSE;
5306 static void InitPlayerInfo()
5310 /* choose default local player */
5311 local_player = &stored_player[0];
5313 for (i = 0; i < MAX_PLAYERS; i++)
5314 stored_player[i].connected = FALSE;
5316 local_player->connected = TRUE;
5319 static void InitArtworkInfo()
5324 static char *get_string_in_brackets(char *string)
5326 char *string_in_brackets = checked_malloc(strlen(string) + 3);
5328 sprintf(string_in_brackets, "[%s]", string);
5330 return string_in_brackets;
5333 static char *get_level_id_suffix(int id_nr)
5335 char *id_suffix = checked_malloc(1 + 3 + 1);
5337 if (id_nr < 0 || id_nr > 999)
5340 sprintf(id_suffix, ".%03d", id_nr);
5346 static char *get_element_class_token(int element)
5348 char *element_class_name = element_info[element].class_name;
5349 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
5351 sprintf(element_class_token, "[%s]", element_class_name);
5353 return element_class_token;
5356 static char *get_action_class_token(int action)
5358 char *action_class_name = &element_action_info[action].suffix[1];
5359 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
5361 sprintf(action_class_token, "[%s]", action_class_name);
5363 return action_class_token;
5367 static void InitArtworkConfig()
5369 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
5370 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
5371 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
5372 static char *action_id_suffix[NUM_ACTIONS + 1];
5373 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5374 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5375 static char *level_id_suffix[MAX_LEVELS + 1];
5376 static char *dummy[1] = { NULL };
5377 static char *ignore_generic_tokens[] =
5383 static char **ignore_image_tokens;
5384 static char **ignore_sound_tokens;
5385 static char **ignore_music_tokens;
5386 int num_ignore_generic_tokens;
5387 int num_ignore_image_tokens;
5388 int num_ignore_sound_tokens;
5389 int num_ignore_music_tokens;
5392 /* dynamically determine list of generic tokens to be ignored */
5393 num_ignore_generic_tokens = 0;
5394 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5395 num_ignore_generic_tokens++;
5397 /* dynamically determine list of image tokens to be ignored */
5398 num_ignore_image_tokens = num_ignore_generic_tokens;
5399 for (i = 0; image_config_vars[i].token != NULL; i++)
5400 num_ignore_image_tokens++;
5401 ignore_image_tokens =
5402 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5403 for (i = 0; i < num_ignore_generic_tokens; i++)
5404 ignore_image_tokens[i] = ignore_generic_tokens[i];
5405 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5406 ignore_image_tokens[num_ignore_generic_tokens + i] =
5407 image_config_vars[i].token;
5408 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5410 /* dynamically determine list of sound tokens to be ignored */
5411 num_ignore_sound_tokens = num_ignore_generic_tokens;
5412 ignore_sound_tokens =
5413 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5414 for (i = 0; i < num_ignore_generic_tokens; i++)
5415 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5416 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5418 /* dynamically determine list of music tokens to be ignored */
5419 num_ignore_music_tokens = num_ignore_generic_tokens;
5420 ignore_music_tokens =
5421 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5422 for (i = 0; i < num_ignore_generic_tokens; i++)
5423 ignore_music_tokens[i] = ignore_generic_tokens[i];
5424 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5426 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5427 image_id_prefix[i] = element_info[i].token_name;
5428 for (i = 0; i < NUM_FONTS; i++)
5429 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5430 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
5432 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5433 sound_id_prefix[i] = element_info[i].token_name;
5434 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5435 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5436 get_string_in_brackets(element_info[i].class_name);
5437 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
5439 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5440 music_id_prefix[i] = music_prefix_info[i].prefix;
5441 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
5443 for (i = 0; i < NUM_ACTIONS; i++)
5444 action_id_suffix[i] = element_action_info[i].suffix;
5445 action_id_suffix[NUM_ACTIONS] = NULL;
5447 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5448 direction_id_suffix[i] = element_direction_info[i].suffix;
5449 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5451 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5452 special_id_suffix[i] = special_suffix_info[i].suffix;
5453 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5455 for (i = 0; i < MAX_LEVELS; i++)
5456 level_id_suffix[i] = get_level_id_suffix(i);
5457 level_id_suffix[MAX_LEVELS] = NULL;
5459 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5460 image_id_prefix, action_id_suffix, direction_id_suffix,
5461 special_id_suffix, ignore_image_tokens);
5462 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5463 sound_id_prefix, action_id_suffix, dummy,
5464 special_id_suffix, ignore_sound_tokens);
5465 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5466 music_id_prefix, special_id_suffix, level_id_suffix,
5467 dummy, ignore_music_tokens);
5470 static void InitMixer()
5477 void InitGfxBuffers()
5479 ReCreateBitmap(&bitmap_db_store, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5480 ReCreateBitmap(&bitmap_db_cross, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5481 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE, DEFAULT_DEPTH);
5482 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE, DEFAULT_DEPTH);
5483 ReCreateBitmap(&bitmap_db_door, 3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
5484 ReCreateBitmap(&bitmap_db_toons, FULL_SXSIZE, FULL_SYSIZE, DEFAULT_DEPTH);
5486 /* initialize screen properties */
5487 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5488 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5490 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5491 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5492 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5493 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5494 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5496 InitGfxBuffers_EM();
5497 InitGfxBuffers_SP();
5502 struct GraphicInfo *graphic_info_last = graphic_info;
5503 char *filename_font_initial = NULL;
5504 char *filename_anim_initial = NULL;
5505 Bitmap *bitmap_font_initial = NULL;
5509 /* determine settings for initial font (for displaying startup messages) */
5510 for (i = 0; image_config[i].token != NULL; i++)
5512 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5514 char font_token[128];
5517 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5518 len_font_token = strlen(font_token);
5520 if (strEqual(image_config[i].token, font_token))
5521 filename_font_initial = image_config[i].value;
5522 else if (strlen(image_config[i].token) > len_font_token &&
5523 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5525 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5526 font_initial[j].src_x = atoi(image_config[i].value);
5527 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5528 font_initial[j].src_y = atoi(image_config[i].value);
5529 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5530 font_initial[j].width = atoi(image_config[i].value);
5531 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5532 font_initial[j].height = atoi(image_config[i].value);
5537 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5539 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5540 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5543 if (filename_font_initial == NULL) /* should not happen */
5544 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5549 /* create additional image buffers for double-buffering and cross-fading */
5550 bitmap_db_store = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5551 bitmap_db_cross = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5552 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
5553 bitmap_db_panel = CreateBitmap(DXSIZE, DYSIZE, DEFAULT_DEPTH);
5554 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
5555 bitmap_db_toons = CreateBitmap(FULL_SXSIZE, FULL_SYSIZE, DEFAULT_DEPTH);
5557 /* initialize screen properties */
5558 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5559 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5561 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5562 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5563 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5564 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5567 InitGfxCustomArtworkInfo();
5569 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5571 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5572 font_initial[j].bitmap = bitmap_font_initial;
5574 InitFontGraphicInfo();
5576 font_height = getFontHeight(FC_RED);
5579 DrawInitText(getWindowTitleString(), 20, FC_YELLOW);
5581 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
5583 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
5584 DrawInitText(PROGRAM_WEBSITE_STRING, WIN_YSIZE - 20 - font_height, FC_RED);
5586 DrawInitText("Loading graphics", 120, FC_GREEN);
5590 /* initialize busy animation with default values */
5591 int parameter[NUM_GFX_ARGS];
5592 for (i = 0; i < NUM_GFX_ARGS; i++)
5593 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5594 image_config_suffix[i].token,
5595 image_config_suffix[i].type);
5597 for (i = 0; i < NUM_GFX_ARGS; i++)
5598 printf("::: '%s' => %d\n", image_config_suffix[i].token, parameter[i]);
5602 /* determine settings for busy animation (when displaying startup messages) */
5603 for (i = 0; image_config[i].token != NULL; i++)
5605 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5606 int len_anim_token = strlen(anim_token);
5608 if (strEqual(image_config[i].token, anim_token))
5609 filename_anim_initial = image_config[i].value;
5610 else if (strlen(image_config[i].token) > len_anim_token &&
5611 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5614 for (j = 0; image_config_suffix[j].token != NULL; j++)
5616 if (strEqual(&image_config[i].token[len_anim_token],
5617 image_config_suffix[j].token))
5619 get_graphic_parameter_value(image_config[i].value,
5620 image_config_suffix[j].token,
5621 image_config_suffix[j].type);
5624 if (strEqual(&image_config[i].token[len_anim_token], ".x"))
5625 anim_initial.src_x = atoi(image_config[i].value);
5626 else if (strEqual(&image_config[i].token[len_anim_token], ".y"))
5627 anim_initial.src_y = atoi(image_config[i].value);
5628 else if (strEqual(&image_config[i].token[len_anim_token], ".width"))
5629 anim_initial.width = atoi(image_config[i].value);
5630 else if (strEqual(&image_config[i].token[len_anim_token], ".height"))
5631 anim_initial.height = atoi(image_config[i].value);
5632 else if (strEqual(&image_config[i].token[len_anim_token], ".frames"))
5633 anim_initial.anim_frames = atoi(image_config[i].value);
5634 else if (strEqual(&image_config[i].token[len_anim_token],
5635 ".frames_per_line"))
5636 anim_initial.anim_frames_per_line = atoi(image_config[i].value);
5637 else if (strEqual(&image_config[i].token[len_anim_token], ".delay"))
5638 anim_initial.anim_delay = atoi(image_config[i].value);
5643 #if defined(CREATE_SPECIAL_EDITION_RND_JUE)
5644 filename_anim_initial = "loading.pcx";
5646 parameter[GFX_ARG_X] = 0;
5647 parameter[GFX_ARG_Y] = 0;
5648 parameter[GFX_ARG_WIDTH] = 128;
5649 parameter[GFX_ARG_HEIGHT] = 40;
5650 parameter[GFX_ARG_FRAMES] = 32;
5651 parameter[GFX_ARG_DELAY] = 4;
5652 parameter[GFX_ARG_FRAMES_PER_LINE] = ARG_UNDEFINED_VALUE;
5655 if (filename_anim_initial == NULL) /* should not happen */
5656 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5658 anim_initial.bitmap = LoadCustomImage(filename_anim_initial);
5660 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
5662 set_graphic_parameters_ext(0, parameter, anim_initial.bitmap);
5665 printf("::: INIT_GFX: anim_frames_per_line == %d [%d / %d] [%d, %d]\n",
5666 graphic_info[0].anim_frames_per_line,
5667 get_scaled_graphic_width(0),
5668 graphic_info[0].width,
5669 getOriginalImageWidthFromImageID(0),
5670 graphic_info[0].scale_up_factor);
5673 graphic_info = graphic_info_last;
5675 init.busy.width = anim_initial.width;
5676 init.busy.height = anim_initial.height;
5678 InitMenuDesignSettings_Static();
5679 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5681 /* use copy of busy animation to prevent change while reloading artwork */
5686 void RedrawBackground()
5688 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
5689 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
5691 redraw_mask = REDRAW_ALL;
5694 void InitGfxBackground()
5698 fieldbuffer = bitmap_db_field;
5699 SetDrawtoField(DRAW_BACKBUFFER);
5702 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5706 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
5707 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
5710 for (x = 0; x < MAX_BUF_XSIZE; x++)
5711 for (y = 0; y < MAX_BUF_YSIZE; y++)
5714 redraw_mask = REDRAW_ALL;
5717 static void InitLevelInfo()
5719 LoadLevelInfo(); /* global level info */
5720 LoadLevelSetup_LastSeries(); /* last played series info */
5721 LoadLevelSetup_SeriesInfo(); /* last played level info */
5724 static void InitLevelArtworkInfo()
5726 LoadLevelArtworkInfo();
5729 static void InitImages()
5731 print_timestamp_init("InitImages");
5734 printf("::: leveldir_current->identifier == '%s'\n",
5735 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5736 printf("::: leveldir_current->graphics_path == '%s'\n",
5737 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5738 printf("::: leveldir_current->graphics_set == '%s'\n",
5739 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5740 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5741 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5744 setLevelArtworkDir(artwork.gfx_first);
5747 printf("::: leveldir_current->identifier == '%s'\n",
5748 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5749 printf("::: leveldir_current->graphics_path == '%s'\n",
5750 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5751 printf("::: leveldir_current->graphics_set == '%s'\n",
5752 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5753 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5754 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5758 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5759 leveldir_current->identifier,
5760 artwork.gfx_current_identifier,
5761 artwork.gfx_current->identifier,
5762 leveldir_current->graphics_set,
5763 leveldir_current->graphics_path);
5766 UPDATE_BUSY_STATE();
5768 ReloadCustomImages();
5769 print_timestamp_time("ReloadCustomImages");
5771 UPDATE_BUSY_STATE();
5773 LoadCustomElementDescriptions();
5774 print_timestamp_time("LoadCustomElementDescriptions");
5776 UPDATE_BUSY_STATE();
5778 LoadMenuDesignSettings();
5779 print_timestamp_time("LoadMenuDesignSettings");
5781 UPDATE_BUSY_STATE();
5783 ReinitializeGraphics();
5784 print_timestamp_time("ReinitializeGraphics");
5786 UPDATE_BUSY_STATE();
5788 print_timestamp_done("InitImages");
5791 static void InitSound(char *identifier)
5793 print_timestamp_init("InitSound");
5795 if (identifier == NULL)
5796 identifier = artwork.snd_current->identifier;
5798 /* set artwork path to send it to the sound server process */
5799 setLevelArtworkDir(artwork.snd_first);
5801 InitReloadCustomSounds(identifier);
5802 print_timestamp_time("InitReloadCustomSounds");
5804 ReinitializeSounds();
5805 print_timestamp_time("ReinitializeSounds");
5807 print_timestamp_done("InitSound");
5810 static void InitMusic(char *identifier)
5812 print_timestamp_init("InitMusic");
5814 if (identifier == NULL)
5815 identifier = artwork.mus_current->identifier;
5817 /* set artwork path to send it to the sound server process */
5818 setLevelArtworkDir(artwork.mus_first);
5820 InitReloadCustomMusic(identifier);
5821 print_timestamp_time("InitReloadCustomMusic");
5823 ReinitializeMusic();
5824 print_timestamp_time("ReinitializeMusic");
5826 print_timestamp_done("InitMusic");
5829 void InitNetworkServer()
5831 #if defined(NETWORK_AVALIABLE)
5835 if (!options.network)
5838 #if defined(NETWORK_AVALIABLE)
5839 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5841 if (!ConnectToServer(options.server_host, options.server_port))
5842 Error(ERR_EXIT, "cannot connect to network game server");
5844 SendToServer_PlayerName(setup.player_name);
5845 SendToServer_ProtocolVersion();
5848 SendToServer_NrWanted(nr_wanted);
5852 static boolean CheckArtworkConfigForCustomElements(char *filename)
5854 SetupFileHash *setup_file_hash;
5855 boolean redefined_ce_found = FALSE;
5857 /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */
5859 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5861 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5863 char *token = HASH_ITERATION_TOKEN(itr);
5865 if (strPrefix(token, "custom_"))
5867 redefined_ce_found = TRUE;
5872 END_HASH_ITERATION(setup_file_hash, itr)
5874 freeSetupFileHash(setup_file_hash);
5877 return redefined_ce_found;
5880 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5882 char *filename_base, *filename_local;
5883 boolean redefined_ce_found = FALSE;
5885 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5888 printf("::: leveldir_current->identifier == '%s'\n",
5889 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5890 printf("::: leveldir_current->graphics_path == '%s'\n",
5891 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5892 printf("::: leveldir_current->graphics_set == '%s'\n",
5893 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5894 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5895 leveldir_current == NULL ? "[NULL]" :
5896 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5899 /* first look for special artwork configured in level series config */
5900 filename_base = getCustomArtworkLevelConfigFilename(type);
5903 printf("::: filename_base == '%s'\n", filename_base);
5906 if (fileExists(filename_base))
5907 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5909 filename_local = getCustomArtworkConfigFilename(type);
5912 printf("::: filename_local == '%s'\n", filename_local);
5915 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5916 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5919 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5922 return redefined_ce_found;
5925 static void InitOverrideArtwork()
5927 boolean redefined_ce_found = FALSE;
5929 /* to check if this level set redefines any CEs, do not use overriding */
5930 gfx.override_level_graphics = FALSE;
5931 gfx.override_level_sounds = FALSE;
5932 gfx.override_level_music = FALSE;
5934 /* now check if this level set has definitions for custom elements */
5935 if (setup.override_level_graphics == AUTO ||
5936 setup.override_level_sounds == AUTO ||
5937 setup.override_level_music == AUTO)
5938 redefined_ce_found =
5939 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5940 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5941 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5944 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5947 if (redefined_ce_found)
5949 /* this level set has CE definitions: change "AUTO" to "FALSE" */
5950 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5951 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
5952 gfx.override_level_music = (setup.override_level_music == TRUE);
5956 /* this level set has no CE definitions: change "AUTO" to "TRUE" */
5957 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5958 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
5959 gfx.override_level_music = (setup.override_level_music != FALSE);
5963 printf("::: => %d, %d, %d\n",
5964 gfx.override_level_graphics,
5965 gfx.override_level_sounds,
5966 gfx.override_level_music);
5970 static char *getNewArtworkIdentifier(int type)
5972 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5973 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5974 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5975 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5976 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5978 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5980 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
5982 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5983 char *leveldir_identifier = leveldir_current->identifier;
5985 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
5986 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5988 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
5990 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5991 char *artwork_current_identifier;
5992 char *artwork_new_identifier = NULL; /* default: nothing has changed */
5994 /* leveldir_current may be invalid (level group, parent link) */
5995 if (!validLevelSeries(leveldir_current))
5998 /* 1st step: determine artwork set to be activated in descending order:
5999 --------------------------------------------------------------------
6000 1. setup artwork (when configured to override everything else)
6001 2. artwork set configured in "levelinfo.conf" of current level set
6002 (artwork in level directory will have priority when loading later)
6003 3. artwork in level directory (stored in artwork sub-directory)
6004 4. setup artwork (currently configured in setup menu) */
6006 if (setup_override_artwork)
6007 artwork_current_identifier = setup_artwork_set;
6008 else if (leveldir_artwork_set != NULL)
6009 artwork_current_identifier = leveldir_artwork_set;
6010 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
6011 artwork_current_identifier = leveldir_identifier;
6013 artwork_current_identifier = setup_artwork_set;
6016 /* 2nd step: check if it is really needed to reload artwork set
6017 ------------------------------------------------------------ */
6020 if (type == ARTWORK_TYPE_GRAPHICS)
6021 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
6022 artwork_new_identifier,
6023 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
6024 artwork_current_identifier,
6025 leveldir_current->graphics_set,
6026 leveldir_current->identifier);
6029 /* ---------- reload if level set and also artwork set has changed ------- */
6030 if (leveldir_current_identifier[type] != leveldir_identifier &&
6031 (last_has_level_artwork_set[type] || has_level_artwork_set))
6032 artwork_new_identifier = artwork_current_identifier;
6034 leveldir_current_identifier[type] = leveldir_identifier;
6035 last_has_level_artwork_set[type] = has_level_artwork_set;
6038 if (type == ARTWORK_TYPE_GRAPHICS)
6039 printf("::: 1: '%s'\n", artwork_new_identifier);
6042 /* ---------- reload if "override artwork" setting has changed ----------- */
6043 if (last_override_level_artwork[type] != setup_override_artwork)
6044 artwork_new_identifier = artwork_current_identifier;
6046 last_override_level_artwork[type] = setup_override_artwork;
6049 if (type == ARTWORK_TYPE_GRAPHICS)
6050 printf("::: 2: '%s'\n", artwork_new_identifier);
6053 /* ---------- reload if current artwork identifier has changed ----------- */
6054 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
6055 artwork_current_identifier))
6056 artwork_new_identifier = artwork_current_identifier;
6058 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
6061 if (type == ARTWORK_TYPE_GRAPHICS)
6062 printf("::: 3: '%s'\n", artwork_new_identifier);
6065 /* ---------- do not reload directly after starting ---------------------- */
6066 if (!initialized[type])
6067 artwork_new_identifier = NULL;
6069 initialized[type] = TRUE;
6072 if (type == ARTWORK_TYPE_GRAPHICS)
6073 printf("::: 4: '%s'\n", artwork_new_identifier);
6077 if (type == ARTWORK_TYPE_GRAPHICS)
6078 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
6079 artwork.gfx_current_identifier, artwork_current_identifier,
6080 artwork.gfx_current->identifier, leveldir_current->graphics_set,
6081 artwork_new_identifier);
6084 return artwork_new_identifier;
6087 void ReloadCustomArtwork(int force_reload)
6089 int last_game_status = game_status; /* save current game status */
6090 char *gfx_new_identifier;
6091 char *snd_new_identifier;
6092 char *mus_new_identifier;
6093 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
6094 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
6095 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
6096 boolean reload_needed;
6098 InitOverrideArtwork();
6100 force_reload_gfx |= AdjustGraphicsForEMC();
6102 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
6103 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
6104 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
6106 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
6107 snd_new_identifier != NULL || force_reload_snd ||
6108 mus_new_identifier != NULL || force_reload_mus);
6113 print_timestamp_init("ReloadCustomArtwork");
6115 game_status = GAME_MODE_LOADING;
6117 FadeOut(REDRAW_ALL);
6120 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6122 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
6124 print_timestamp_time("ClearRectangle");
6127 printf("::: fading in ... %d\n", fading.fade_mode);
6131 printf("::: done\n");
6134 if (gfx_new_identifier != NULL || force_reload_gfx)
6137 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
6138 artwork.gfx_current_identifier,
6140 artwork.gfx_current->identifier,
6141 leveldir_current->graphics_set);
6145 print_timestamp_time("InitImages");
6148 if (snd_new_identifier != NULL || force_reload_snd)
6150 InitSound(snd_new_identifier);
6151 print_timestamp_time("InitSound");
6154 if (mus_new_identifier != NULL || force_reload_mus)
6156 InitMusic(mus_new_identifier);
6157 print_timestamp_time("InitMusic");
6160 game_status = last_game_status; /* restore current game status */
6162 init_last = init; /* switch to new busy animation */
6165 printf("::: ----------------DELAY 1 ...\n");
6170 printf("::: FadeOut @ ReloadCustomArtwork ...\n");
6172 FadeOut(REDRAW_ALL);
6174 printf("::: FadeOut @ ReloadCustomArtwork done\n");
6179 /* force redraw of (open or closed) door graphics */
6180 SetDoorState(DOOR_OPEN_ALL);
6181 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
6186 FadeSetEnterScreen();
6187 FadeSkipNextFadeOut();
6188 // FadeSetDisabled();
6193 fading = fading_none;
6198 redraw_mask = REDRAW_ALL;
6201 print_timestamp_done("ReloadCustomArtwork");
6204 void KeyboardAutoRepeatOffUnlessAutoplay()
6206 if (global.autoplay_leveldir == NULL)
6207 KeyboardAutoRepeatOff();
6210 void DisplayExitMessage(char *format, va_list ap)
6212 // check if draw buffer and fonts for exit message are already available
6213 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
6216 int font_1 = FC_RED;
6217 int font_2 = FC_YELLOW;
6218 int font_3 = FC_BLUE;
6219 int font_width = getFontWidth(font_2);
6220 int font_height = getFontHeight(font_2);
6223 int sxsize = WIN_XSIZE - 2 * sx;
6224 int sysize = WIN_YSIZE - 2 * sy;
6225 int line_length = sxsize / font_width;
6226 int max_lines = sysize / font_height;
6227 int num_lines_printed;
6231 gfx.sxsize = sxsize;
6232 gfx.sysize = sysize;
6236 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6238 DrawTextSCentered(sy, font_1, "Fatal error:");
6239 sy += 3 * font_height;;
6242 DrawTextBufferVA(sx, sy, format, ap, font_2,
6243 line_length, line_length, max_lines,
6244 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6245 sy += (num_lines_printed + 3) * font_height;
6247 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
6248 sy += 3 * font_height;
6251 DrawTextBuffer(sx, sy, program.error_filename, font_2,
6252 line_length, line_length, max_lines,
6253 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6255 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
6257 redraw_mask = REDRAW_ALL;
6261 /* deactivate toons on error message screen */
6262 setup.toons = FALSE;
6264 WaitForEventToContinue();
6268 /* ========================================================================= */
6270 /* ========================================================================= */
6274 print_timestamp_init("OpenAll");
6276 game_status = GAME_MODE_LOADING;
6282 InitGlobal(); /* initialize some global variables */
6284 print_timestamp_time("[init global stuff]");
6286 if (options.execute_command)
6287 Execute_Command(options.execute_command);
6289 if (options.serveronly)
6291 #if defined(PLATFORM_UNIX)
6292 NetworkServer(options.server_port, options.serveronly);
6294 Error(ERR_WARN, "networking only supported in Unix version");
6297 exit(0); /* never reached, server loops forever */
6302 print_timestamp_time("[init setup/config stuff (1)]");
6305 print_timestamp_time("[init setup/config stuff (2)]");
6307 print_timestamp_time("[init setup/config stuff (3)]");
6308 InitArtworkInfo(); /* needed before loading gfx, sound & music */
6309 print_timestamp_time("[init setup/config stuff (4)]");
6310 InitArtworkConfig(); /* needed before forking sound child process */
6311 print_timestamp_time("[init setup/config stuff (5)]");
6313 print_timestamp_time("[init setup/config stuff (6)]");
6319 InitRND(NEW_RANDOMIZE);
6320 InitSimpleRandom(NEW_RANDOMIZE);
6324 print_timestamp_time("[init setup/config stuff]");
6327 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
6329 InitEventFilter(FilterEvents);
6331 print_timestamp_time("[init video stuff]");
6333 InitElementPropertiesStatic();
6334 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
6335 InitElementPropertiesGfxElement();
6337 print_timestamp_time("[init element properties stuff]");
6341 print_timestamp_time("InitGfx");
6344 print_timestamp_time("InitLevelInfo");
6346 InitLevelArtworkInfo();
6347 print_timestamp_time("InitLevelArtworkInfo");
6349 InitOverrideArtwork(); /* needs to know current level directory */
6350 print_timestamp_time("InitOverrideArtwork");
6352 InitImages(); /* needs to know current level directory */
6353 print_timestamp_time("InitImages");
6355 InitSound(NULL); /* needs to know current level directory */
6356 print_timestamp_time("InitSound");
6358 InitMusic(NULL); /* needs to know current level directory */
6359 print_timestamp_time("InitMusic");
6361 InitGfxBackground();
6371 if (global.autoplay_leveldir)
6376 else if (global.convert_leveldir)
6381 else if (global.create_images_dir)
6383 CreateLevelSketchImages();
6387 game_status = GAME_MODE_MAIN;
6390 FadeSetEnterScreen();
6391 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
6392 FadeSkipNextFadeOut();
6393 // FadeSetDisabled();
6395 fading = fading_none;
6398 print_timestamp_time("[post-artwork]");
6400 print_timestamp_done("OpenAll");
6404 InitNetworkServer();
6407 void CloseAllAndExit(int exit_value)
6412 CloseAudio(); /* called after freeing sounds (needed for SDL) */
6424 #if defined(TARGET_SDL)
6425 #if defined(TARGET_SDL2)
6427 // set a flag to tell the network server thread to quit and wait for it
6428 // using SDL_WaitThread()
6430 if (network_server) /* terminate network server */
6431 SDL_KillThread(server_thread);
6435 CloseVideoDisplay();
6436 ClosePlatformDependentStuff();
6438 if (exit_value != 0)
6440 /* fall back to default level set (current set may have caused an error) */
6441 SaveLevelSetup_LastSeries_Deactivate();
6443 /* tell user where to find error log file which may contain more details */
6444 // (error notification now directly displayed on screen inside R'n'D
6445 // NotifyUserAboutErrorFile(); /* currently only works for Windows */