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,
200 graphic_info[graphic].tile_size);
203 void InitElementSmallImages()
205 print_timestamp_init("InitElementSmallImages");
207 static int special_graphics[] =
209 IMG_EDITOR_ELEMENT_BORDER,
210 IMG_EDITOR_ELEMENT_BORDER_INPUT,
211 IMG_EDITOR_CASCADE_LIST,
212 IMG_EDITOR_CASCADE_LIST_ACTIVE,
215 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
216 int num_property_mappings = getImageListPropertyMappingSize();
219 print_timestamp_time("getImageListPropertyMapping/Size");
221 print_timestamp_init("InitElementSmallImagesScaledUp (1)");
222 /* initialize normal images from static configuration */
223 for (i = 0; element_to_graphic[i].element > -1; i++)
224 InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
225 print_timestamp_done("InitElementSmallImagesScaledUp (1)");
227 /* initialize special images from static configuration */
228 for (i = 0; element_to_special_graphic[i].element > -1; i++)
229 InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
230 print_timestamp_time("InitElementSmallImagesScaledUp (2)");
232 /* initialize images from dynamic configuration (may be elements or other) */
233 for (i = 0; i < num_property_mappings; i++)
234 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
235 print_timestamp_time("InitElementSmallImagesScaledUp (3)");
237 /* initialize special images from above list (non-element images) */
238 for (i = 0; special_graphics[i] > -1; i++)
239 InitElementSmallImagesScaledUp(special_graphics[i]);
240 print_timestamp_time("InitElementSmallImagesScaledUp (4)");
242 print_timestamp_done("InitElementSmallImages");
245 void InitScaledImages()
249 /* scale normal images from static configuration, if not already scaled */
250 for (i = 0; i < NUM_IMAGE_FILES; i++)
251 ScaleImage(i, graphic_info[i].scale_up_factor);
255 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
256 void SetBitmaps_EM(Bitmap **em_bitmap)
258 em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
259 em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].bitmap;
264 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
265 void SetBitmaps_SP(Bitmap **sp_bitmap)
267 *sp_bitmap = graphic_info[IMG_SP_OBJECTS].bitmap;
271 static int getFontBitmapID(int font_nr)
275 /* (special case: do not use special font for GAME_MODE_LOADING) */
276 if (game_status >= GAME_MODE_TITLE_INITIAL &&
277 game_status <= GAME_MODE_PSEUDO_PREVIEW)
278 special = game_status;
279 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
280 special = GFX_SPECIAL_ARG_MAIN;
282 else if (game_status == GAME_MODE_PLAYING)
283 special = GFX_SPECIAL_ARG_DOOR;
290 font_info[font_nr].token_name,
291 special_suffix_info[special].suffix);
296 return font_info[font_nr].special_bitmap_id[special];
301 static int getFontFromToken(char *token)
304 char *value = getHashEntry(font_token_hash, token);
311 /* !!! OPTIMIZE THIS BY USING HASH !!! */
312 for (i = 0; i < NUM_FONTS; i++)
313 if (strEqual(token, font_info[i].token_name))
317 /* if font not found, use reliable default value */
318 return FONT_INITIAL_1;
321 void InitFontGraphicInfo()
323 static struct FontBitmapInfo *font_bitmap_info = NULL;
324 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
325 int num_property_mappings = getImageListPropertyMappingSize();
326 int num_font_bitmaps = NUM_FONTS;
329 if (graphic_info == NULL) /* still at startup phase */
331 InitFontInfo(font_initial, NUM_INITIAL_FONTS,
332 getFontBitmapID, getFontFromToken);
337 /* ---------- initialize font graphic definitions ---------- */
339 /* always start with reliable default values (normal font graphics) */
340 for (i = 0; i < NUM_FONTS; i++)
341 font_info[i].graphic = IMG_FONT_INITIAL_1;
343 /* initialize normal font/graphic mapping from static configuration */
344 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
346 int font_nr = font_to_graphic[i].font_nr;
347 int special = font_to_graphic[i].special;
348 int graphic = font_to_graphic[i].graphic;
353 font_info[font_nr].graphic = graphic;
356 /* always start with reliable default values (special font graphics) */
357 for (i = 0; i < NUM_FONTS; i++)
359 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
361 font_info[i].special_graphic[j] = font_info[i].graphic;
362 font_info[i].special_bitmap_id[j] = i;
366 /* initialize special font/graphic mapping from static configuration */
367 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
369 int font_nr = font_to_graphic[i].font_nr;
370 int special = font_to_graphic[i].special;
371 int graphic = font_to_graphic[i].graphic;
372 int base_graphic = font2baseimg(font_nr);
374 if (IS_SPECIAL_GFX_ARG(special))
376 boolean base_redefined =
377 getImageListEntryFromImageID(base_graphic)->redefined;
378 boolean special_redefined =
379 getImageListEntryFromImageID(graphic)->redefined;
380 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
382 /* if the base font ("font.title_1", for example) has been redefined,
383 but not the special font ("font.title_1.LEVELS", for example), do not
384 use an existing (in this case considered obsolete) special font
385 anymore, but use the automatically determined default font */
386 /* special case: cloned special fonts must be explicitly redefined,
387 but are not automatically redefined by redefining base font */
388 if (base_redefined && !special_redefined && !special_cloned)
391 font_info[font_nr].special_graphic[special] = graphic;
392 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
397 /* initialize special font/graphic mapping from dynamic configuration */
398 for (i = 0; i < num_property_mappings; i++)
400 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
401 int special = property_mapping[i].ext3_index;
402 int graphic = property_mapping[i].artwork_index;
407 if (IS_SPECIAL_GFX_ARG(special))
409 font_info[font_nr].special_graphic[special] = graphic;
410 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
415 /* correct special font/graphic mapping for cloned fonts for downwards
416 compatibility of PREVIEW fonts -- this is only needed for implicit
417 redefinition of special font by redefined base font, and only if other
418 fonts are cloned from this special font (like in the "Zelda" level set) */
419 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
421 int font_nr = font_to_graphic[i].font_nr;
422 int special = font_to_graphic[i].special;
423 int graphic = font_to_graphic[i].graphic;
425 if (IS_SPECIAL_GFX_ARG(special))
427 boolean special_redefined =
428 getImageListEntryFromImageID(graphic)->redefined;
429 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
431 if (special_cloned && !special_redefined)
435 for (j = 0; font_to_graphic[j].font_nr > -1; j++)
437 int font_nr2 = font_to_graphic[j].font_nr;
438 int special2 = font_to_graphic[j].special;
439 int graphic2 = font_to_graphic[j].graphic;
441 if (IS_SPECIAL_GFX_ARG(special2) &&
442 graphic2 == graphic_info[graphic].clone_from)
444 font_info[font_nr].special_graphic[special] =
445 font_info[font_nr2].special_graphic[special2];
446 font_info[font_nr].special_bitmap_id[special] =
447 font_info[font_nr2].special_bitmap_id[special2];
454 /* reset non-redefined ".active" font graphics if normal font is redefined */
455 /* (this different treatment is needed because normal and active fonts are
456 independently defined ("active" is not a property of font definitions!) */
457 for (i = 0; i < NUM_FONTS; i++)
459 int font_nr_base = i;
460 int font_nr_active = FONT_ACTIVE(font_nr_base);
462 /* check only those fonts with exist as normal and ".active" variant */
463 if (font_nr_base != font_nr_active)
465 int base_graphic = font_info[font_nr_base].graphic;
466 int active_graphic = font_info[font_nr_active].graphic;
467 boolean base_redefined =
468 getImageListEntryFromImageID(base_graphic)->redefined;
469 boolean active_redefined =
470 getImageListEntryFromImageID(active_graphic)->redefined;
472 /* if the base font ("font.menu_1", for example) has been redefined,
473 but not the active font ("font.menu_1.active", for example), do not
474 use an existing (in this case considered obsolete) active font
475 anymore, but use the automatically determined default font */
476 if (base_redefined && !active_redefined)
477 font_info[font_nr_active].graphic = base_graphic;
479 /* now also check each "special" font (which may be the same as above) */
480 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
482 int base_graphic = font_info[font_nr_base].special_graphic[j];
483 int active_graphic = font_info[font_nr_active].special_graphic[j];
484 boolean base_redefined =
485 getImageListEntryFromImageID(base_graphic)->redefined;
486 boolean active_redefined =
487 getImageListEntryFromImageID(active_graphic)->redefined;
489 /* same as above, but check special graphic definitions, for example:
490 redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN" */
491 if (base_redefined && !active_redefined)
493 font_info[font_nr_active].special_graphic[j] =
494 font_info[font_nr_base].special_graphic[j];
495 font_info[font_nr_active].special_bitmap_id[j] =
496 font_info[font_nr_base].special_bitmap_id[j];
502 /* ---------- initialize font bitmap array ---------- */
504 if (font_bitmap_info != NULL)
505 FreeFontInfo(font_bitmap_info);
508 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
510 /* ---------- initialize font bitmap definitions ---------- */
512 for (i = 0; i < NUM_FONTS; i++)
514 if (i < NUM_INITIAL_FONTS)
516 font_bitmap_info[i] = font_initial[i];
520 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
522 int font_bitmap_id = font_info[i].special_bitmap_id[j];
523 int graphic = font_info[i].special_graphic[j];
525 /* set 'graphic_info' for font entries, if uninitialized (guessed) */
526 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
528 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
529 graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
532 /* copy font relevant information from graphics information */
533 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
534 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
535 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
536 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
537 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
539 font_bitmap_info[font_bitmap_id].draw_xoffset =
540 graphic_info[graphic].draw_xoffset;
541 font_bitmap_info[font_bitmap_id].draw_yoffset =
542 graphic_info[graphic].draw_yoffset;
544 font_bitmap_info[font_bitmap_id].num_chars =
545 graphic_info[graphic].anim_frames;
546 font_bitmap_info[font_bitmap_id].num_chars_per_line =
547 graphic_info[graphic].anim_frames_per_line;
551 InitFontInfo(font_bitmap_info, num_font_bitmaps,
552 getFontBitmapID, getFontFromToken);
555 void InitElementGraphicInfo()
557 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
558 int num_property_mappings = getImageListPropertyMappingSize();
561 if (graphic_info == NULL) /* still at startup phase */
564 /* set values to -1 to identify later as "uninitialized" values */
565 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
567 for (act = 0; act < NUM_ACTIONS; act++)
569 element_info[i].graphic[act] = -1;
570 element_info[i].crumbled[act] = -1;
572 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
574 element_info[i].direction_graphic[act][dir] = -1;
575 element_info[i].direction_crumbled[act][dir] = -1;
582 /* initialize normal element/graphic mapping from static configuration */
583 for (i = 0; element_to_graphic[i].element > -1; i++)
585 int element = element_to_graphic[i].element;
586 int action = element_to_graphic[i].action;
587 int direction = element_to_graphic[i].direction;
588 boolean crumbled = element_to_graphic[i].crumbled;
589 int graphic = element_to_graphic[i].graphic;
590 int base_graphic = el2baseimg(element);
592 if (graphic_info[graphic].bitmap == NULL)
595 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
598 boolean base_redefined =
599 getImageListEntryFromImageID(base_graphic)->redefined;
600 boolean act_dir_redefined =
601 getImageListEntryFromImageID(graphic)->redefined;
603 /* if the base graphic ("emerald", for example) has been redefined,
604 but not the action graphic ("emerald.falling", for example), do not
605 use an existing (in this case considered obsolete) action graphic
606 anymore, but use the automatically determined default graphic */
607 if (base_redefined && !act_dir_redefined)
612 action = ACTION_DEFAULT;
617 element_info[element].direction_crumbled[action][direction] = graphic;
619 element_info[element].crumbled[action] = graphic;
624 element_info[element].direction_graphic[action][direction] = graphic;
626 element_info[element].graphic[action] = graphic;
630 /* initialize normal element/graphic mapping from dynamic configuration */
631 for (i = 0; i < num_property_mappings; i++)
633 int element = property_mapping[i].base_index;
634 int action = property_mapping[i].ext1_index;
635 int direction = property_mapping[i].ext2_index;
636 int special = property_mapping[i].ext3_index;
637 int graphic = property_mapping[i].artwork_index;
638 boolean crumbled = FALSE;
641 if ((element == EL_EM_DYNAMITE ||
642 element == EL_EM_DYNAMITE_ACTIVE) &&
643 action == ACTION_ACTIVE &&
644 (special == GFX_SPECIAL_ARG_EDITOR ||
645 special == GFX_SPECIAL_ARG_PANEL))
646 printf("::: DYNAMIC: %d, %d, %d -> %d\n",
647 element, action, special, graphic);
650 if (special == GFX_SPECIAL_ARG_CRUMBLED)
656 if (graphic_info[graphic].bitmap == NULL)
659 if (element >= MAX_NUM_ELEMENTS || special != -1)
663 action = ACTION_DEFAULT;
668 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
669 element_info[element].direction_crumbled[action][dir] = -1;
672 element_info[element].direction_crumbled[action][direction] = graphic;
674 element_info[element].crumbled[action] = graphic;
679 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
680 element_info[element].direction_graphic[action][dir] = -1;
683 element_info[element].direction_graphic[action][direction] = graphic;
685 element_info[element].graphic[action] = graphic;
689 /* now copy all graphics that are defined to be cloned from other graphics */
690 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
692 int graphic = element_info[i].graphic[ACTION_DEFAULT];
693 int crumbled_like, diggable_like;
698 crumbled_like = graphic_info[graphic].crumbled_like;
699 diggable_like = graphic_info[graphic].diggable_like;
701 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
703 for (act = 0; act < NUM_ACTIONS; act++)
704 element_info[i].crumbled[act] =
705 element_info[crumbled_like].crumbled[act];
706 for (act = 0; act < NUM_ACTIONS; act++)
707 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
708 element_info[i].direction_crumbled[act][dir] =
709 element_info[crumbled_like].direction_crumbled[act][dir];
712 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
714 element_info[i].graphic[ACTION_DIGGING] =
715 element_info[diggable_like].graphic[ACTION_DIGGING];
716 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
717 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
718 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
723 /* set hardcoded definitions for some runtime elements without graphic */
724 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
728 /* set hardcoded definitions for some internal elements without graphic */
729 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
731 if (IS_EDITOR_CASCADE_INACTIVE(i))
732 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
733 else if (IS_EDITOR_CASCADE_ACTIVE(i))
734 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
738 /* now set all undefined/invalid graphics to -1 to set to default after it */
739 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
741 for (act = 0; act < NUM_ACTIONS; act++)
745 graphic = element_info[i].graphic[act];
746 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
747 element_info[i].graphic[act] = -1;
749 graphic = element_info[i].crumbled[act];
750 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
751 element_info[i].crumbled[act] = -1;
753 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
755 graphic = element_info[i].direction_graphic[act][dir];
756 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
757 element_info[i].direction_graphic[act][dir] = -1;
759 graphic = element_info[i].direction_crumbled[act][dir];
760 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
761 element_info[i].direction_crumbled[act][dir] = -1;
768 /* adjust graphics with 2nd tile for movement according to direction
769 (do this before correcting '-1' values to minimize calculations) */
770 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
772 for (act = 0; act < NUM_ACTIONS; act++)
774 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
776 int graphic = element_info[i].direction_graphic[act][dir];
777 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
779 if (act == ACTION_FALLING) /* special case */
780 graphic = element_info[i].graphic[act];
783 graphic_info[graphic].double_movement &&
784 graphic_info[graphic].swap_double_tiles != 0)
786 struct GraphicInfo *g = &graphic_info[graphic];
787 int src_x_front = g->src_x;
788 int src_y_front = g->src_y;
789 int src_x_back = g->src_x + g->offset2_x;
790 int src_y_back = g->src_y + g->offset2_y;
791 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
793 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
794 src_y_front < src_y_back);
795 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
796 boolean swap_movement_tiles_autodetected =
797 (!frames_are_ordered_diagonally &&
798 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
799 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
800 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
801 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
804 /* swap frontside and backside graphic tile coordinates, if needed */
805 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
807 /* get current (wrong) backside tile coordinates */
808 getFixedGraphicSourceExt(graphic, 0, &dummy,
809 &src_x_back, &src_y_back, TRUE);
811 /* set frontside tile coordinates to backside tile coordinates */
812 g->src_x = src_x_back;
813 g->src_y = src_y_back;
815 /* invert tile offset to point to new backside tile coordinates */
819 /* do not swap front and backside tiles again after correction */
820 g->swap_double_tiles = 0;
829 /* now set all '-1' values to element specific default values */
830 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
832 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
833 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
834 int default_direction_graphic[NUM_DIRECTIONS_FULL];
835 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
837 if (default_graphic == -1)
838 default_graphic = IMG_UNKNOWN;
840 if (default_crumbled == -1)
841 default_crumbled = default_graphic;
843 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
844 if (default_crumbled == -1)
845 default_crumbled = IMG_EMPTY;
848 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
850 default_direction_graphic[dir] =
851 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
852 default_direction_crumbled[dir] =
853 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
855 if (default_direction_graphic[dir] == -1)
856 default_direction_graphic[dir] = default_graphic;
858 if (default_direction_crumbled[dir] == -1)
859 default_direction_crumbled[dir] = default_direction_graphic[dir];
861 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
862 if (default_direction_crumbled[dir] == -1)
863 default_direction_crumbled[dir] = default_crumbled;
867 for (act = 0; act < NUM_ACTIONS; act++)
869 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
870 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
871 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
872 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
873 act == ACTION_TURNING_FROM_RIGHT ||
874 act == ACTION_TURNING_FROM_UP ||
875 act == ACTION_TURNING_FROM_DOWN);
877 /* generic default action graphic (defined by "[default]" directive) */
878 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
879 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
880 int default_remove_graphic = IMG_EMPTY;
882 if (act_remove && default_action_graphic != -1)
883 default_remove_graphic = default_action_graphic;
885 /* look for special default action graphic (classic game specific) */
886 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
887 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
888 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
889 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
890 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
891 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
893 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
894 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
895 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
896 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
897 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
898 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
901 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
902 /* !!! make this better !!! */
903 if (i == EL_EMPTY_SPACE)
905 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
906 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
910 if (default_action_graphic == -1)
911 default_action_graphic = default_graphic;
913 if (default_action_crumbled == -1)
914 default_action_crumbled = default_action_graphic;
916 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
917 if (default_action_crumbled == -1)
918 default_action_crumbled = default_crumbled;
921 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
923 /* use action graphic as the default direction graphic, if undefined */
924 int default_action_direction_graphic = element_info[i].graphic[act];
925 int default_action_direction_crumbled = element_info[i].crumbled[act];
927 /* no graphic for current action -- use default direction graphic */
928 if (default_action_direction_graphic == -1)
929 default_action_direction_graphic =
930 (act_remove ? default_remove_graphic :
932 element_info[i].direction_graphic[ACTION_TURNING][dir] :
933 default_action_graphic != default_graphic ?
934 default_action_graphic :
935 default_direction_graphic[dir]);
937 if (element_info[i].direction_graphic[act][dir] == -1)
938 element_info[i].direction_graphic[act][dir] =
939 default_action_direction_graphic;
942 if (default_action_direction_crumbled == -1)
943 default_action_direction_crumbled =
944 element_info[i].direction_graphic[act][dir];
946 if (default_action_direction_crumbled == -1)
947 default_action_direction_crumbled =
948 (act_remove ? default_remove_graphic :
950 element_info[i].direction_crumbled[ACTION_TURNING][dir] :
951 default_action_crumbled != default_crumbled ?
952 default_action_crumbled :
953 default_direction_crumbled[dir]);
956 if (element_info[i].direction_crumbled[act][dir] == -1)
957 element_info[i].direction_crumbled[act][dir] =
958 default_action_direction_crumbled;
961 /* no graphic for this specific action -- use default action graphic */
962 if (element_info[i].graphic[act] == -1)
963 element_info[i].graphic[act] =
964 (act_remove ? default_remove_graphic :
965 act_turning ? element_info[i].graphic[ACTION_TURNING] :
966 default_action_graphic);
968 if (element_info[i].crumbled[act] == -1)
969 element_info[i].crumbled[act] = element_info[i].graphic[act];
971 if (element_info[i].crumbled[act] == -1)
972 element_info[i].crumbled[act] =
973 (act_remove ? default_remove_graphic :
974 act_turning ? element_info[i].crumbled[ACTION_TURNING] :
975 default_action_crumbled);
983 /* !!! THIS ALSO CLEARS SPECIAL FLAGS (AND IS NOT NEEDED ANYWAY) !!! */
984 /* set animation mode to "none" for each graphic with only 1 frame */
985 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
987 for (act = 0; act < NUM_ACTIONS; act++)
989 int graphic = element_info[i].graphic[act];
990 int crumbled = element_info[i].crumbled[act];
992 if (graphic_info[graphic].anim_frames == 1)
993 graphic_info[graphic].anim_mode = ANIM_NONE;
994 if (graphic_info[crumbled].anim_frames == 1)
995 graphic_info[crumbled].anim_mode = ANIM_NONE;
997 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
999 graphic = element_info[i].direction_graphic[act][dir];
1000 crumbled = element_info[i].direction_crumbled[act][dir];
1002 if (graphic_info[graphic].anim_frames == 1)
1003 graphic_info[graphic].anim_mode = ANIM_NONE;
1004 if (graphic_info[crumbled].anim_frames == 1)
1005 graphic_info[crumbled].anim_mode = ANIM_NONE;
1013 if (options.verbose)
1015 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1016 if (element_info[i].graphic[ACTION_DEFAULT] == IMG_UNKNOWN &&
1018 Error(ERR_INFO, "warning: no graphic for element '%s' (%d)",
1019 element_info[i].token_name, i);
1025 void InitElementSpecialGraphicInfo()
1027 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
1028 int num_property_mappings = getImageListPropertyMappingSize();
1031 /* always start with reliable default values */
1032 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1033 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1034 element_info[i].special_graphic[j] =
1035 element_info[i].graphic[ACTION_DEFAULT];
1037 /* initialize special element/graphic mapping from static configuration */
1038 for (i = 0; element_to_special_graphic[i].element > -1; i++)
1040 int element = element_to_special_graphic[i].element;
1041 int special = element_to_special_graphic[i].special;
1042 int graphic = element_to_special_graphic[i].graphic;
1043 int base_graphic = el2baseimg(element);
1044 boolean base_redefined =
1045 getImageListEntryFromImageID(base_graphic)->redefined;
1046 boolean special_redefined =
1047 getImageListEntryFromImageID(graphic)->redefined;
1050 if ((element == EL_EM_DYNAMITE ||
1051 element == EL_EM_DYNAMITE_ACTIVE) &&
1052 (special == GFX_SPECIAL_ARG_EDITOR ||
1053 special == GFX_SPECIAL_ARG_PANEL))
1054 printf("::: SPECIAL STATIC: %d, %d -> %d\n",
1055 element, special, graphic);
1058 /* if the base graphic ("emerald", for example) has been redefined,
1059 but not the special graphic ("emerald.EDITOR", for example), do not
1060 use an existing (in this case considered obsolete) special graphic
1061 anymore, but use the automatically created (down-scaled) graphic */
1062 if (base_redefined && !special_redefined)
1065 element_info[element].special_graphic[special] = graphic;
1068 /* initialize special element/graphic mapping from dynamic configuration */
1069 for (i = 0; i < num_property_mappings; i++)
1071 int element = property_mapping[i].base_index;
1072 int action = property_mapping[i].ext1_index;
1073 int direction = property_mapping[i].ext2_index;
1074 int special = property_mapping[i].ext3_index;
1075 int graphic = property_mapping[i].artwork_index;
1078 if ((element == EL_EM_DYNAMITE ||
1079 element == EL_EM_DYNAMITE_ACTIVE ||
1080 element == EL_CONVEYOR_BELT_1_MIDDLE ||
1081 element == EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE) &&
1082 (special == GFX_SPECIAL_ARG_EDITOR ||
1083 special == GFX_SPECIAL_ARG_PANEL))
1084 printf("::: SPECIAL DYNAMIC: %d, %d -> %d [%d]\n",
1085 element, special, graphic, property_mapping[i].ext1_index);
1089 if (element == EL_CONVEYOR_BELT_1_MIDDLE &&
1090 action == ACTION_ACTIVE)
1092 element = EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE;
1098 if (element == EL_MAGIC_WALL &&
1099 action == ACTION_ACTIVE)
1101 element = EL_MAGIC_WALL_ACTIVE;
1107 /* for action ".active", replace element with active element, if exists */
1108 if (action == ACTION_ACTIVE && element != ELEMENT_ACTIVE(element))
1110 element = ELEMENT_ACTIVE(element);
1115 if (element >= MAX_NUM_ELEMENTS)
1118 /* do not change special graphic if action or direction was specified */
1119 if (action != -1 || direction != -1)
1122 if (IS_SPECIAL_GFX_ARG(special))
1123 element_info[element].special_graphic[special] = graphic;
1126 /* now set all undefined/invalid graphics to default */
1127 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1128 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1129 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
1130 element_info[i].special_graphic[j] =
1131 element_info[i].graphic[ACTION_DEFAULT];
1134 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
1136 if (type != TYPE_ELEMENT && type != TYPE_GRAPHIC)
1137 return get_parameter_value(value_raw, suffix, type);
1139 if (strEqual(value_raw, ARG_UNDEFINED))
1140 return ARG_UNDEFINED_VALUE;
1142 if (type == TYPE_ELEMENT)
1144 char *value = getHashEntry(element_token_hash, value_raw);
1146 return (value != NULL ? atoi(value) : EL_UNDEFINED);
1148 else if (type == TYPE_GRAPHIC)
1150 char *value = getHashEntry(graphic_token_hash, value_raw);
1152 return (value != NULL ? atoi(value) : IMG_UNDEFINED);
1158 static int get_scaled_graphic_width(int graphic)
1160 int original_width = getOriginalImageWidthFromImageID(graphic);
1161 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1163 return original_width * scale_up_factor;
1166 static int get_scaled_graphic_height(int graphic)
1168 int original_height = getOriginalImageHeightFromImageID(graphic);
1169 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1171 return original_height * scale_up_factor;
1174 static void set_graphic_parameters_ext(int graphic, int *parameter,
1177 struct GraphicInfo *g = &graphic_info[graphic];
1178 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1179 int anim_frames_per_line = 1;
1181 /* always start with reliable default values */
1182 g->src_image_width = 0;
1183 g->src_image_height = 0;
1186 g->width = TILEX; /* default for element graphics */
1187 g->height = TILEY; /* default for element graphics */
1188 g->offset_x = 0; /* one or both of these values ... */
1189 g->offset_y = 0; /* ... will be corrected later */
1190 g->offset2_x = 0; /* one or both of these values ... */
1191 g->offset2_y = 0; /* ... will be corrected later */
1192 g->swap_double_tiles = -1; /* auto-detect tile swapping */
1193 g->crumbled_like = -1; /* do not use clone element */
1194 g->diggable_like = -1; /* do not use clone element */
1195 g->border_size = TILEX / 8; /* "CRUMBLED" border size */
1196 g->scale_up_factor = 1; /* default: no scaling up */
1197 g->tile_size = TILESIZE; /* default: standard tile size */
1198 g->clone_from = -1; /* do not use clone graphic */
1199 g->anim_delay_fixed = 0;
1200 g->anim_delay_random = 0;
1201 g->post_delay_fixed = 0;
1202 g->post_delay_random = 0;
1203 g->fade_mode = FADE_MODE_DEFAULT;
1207 g->align = ALIGN_CENTER; /* default for title screens */
1208 g->valign = VALIGN_MIDDLE; /* default for title screens */
1209 g->sort_priority = 0; /* default for title screens */
1211 g->style = STYLE_DEFAULT;
1213 g->bitmap = src_bitmap;
1216 /* optional zoom factor for scaling up the image to a larger size */
1217 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1218 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1219 if (g->scale_up_factor < 1)
1220 g->scale_up_factor = 1; /* no scaling */
1224 /* optional tile size for using non-standard image size */
1225 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1226 g->tile_size = parameter[GFX_ARG_TILE_SIZE];
1227 if (g->tile_size < TILESIZE)
1228 g->tile_size = TILESIZE; /* standard tile size */
1232 if (g->use_image_size)
1234 /* set new default bitmap size (with scaling, but without small images) */
1235 g->width = get_scaled_graphic_width(graphic);
1236 g->height = get_scaled_graphic_height(graphic);
1240 /* optional x and y tile position of animation frame sequence */
1241 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1242 g->src_x = parameter[GFX_ARG_XPOS] * TILEX;
1243 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1244 g->src_y = parameter[GFX_ARG_YPOS] * TILEY;
1246 /* optional x and y pixel position of animation frame sequence */
1247 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1248 g->src_x = parameter[GFX_ARG_X];
1249 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1250 g->src_y = parameter[GFX_ARG_Y];
1252 /* optional width and height of each animation frame */
1253 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1254 g->width = parameter[GFX_ARG_WIDTH];
1255 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1256 g->height = parameter[GFX_ARG_HEIGHT];
1262 Error(ERR_INFO_LINE, "-");
1263 Error(ERR_WARN, "invalid value %d for '%s.width' (fallback done to %d)",
1264 g->width, getTokenFromImageID(graphic), TILEX);
1265 Error(ERR_INFO_LINE, "-");
1267 g->width = TILEX; /* will be checked to be inside bitmap later */
1272 Error(ERR_INFO_LINE, "-");
1273 Error(ERR_WARN, "invalid value %d for '%s.height' (fallback done to %d)",
1274 g->height, getTokenFromImageID(graphic), TILEY);
1275 Error(ERR_INFO_LINE, "-");
1277 g->height = TILEY; /* will be checked to be inside bitmap later */
1282 /* optional zoom factor for scaling up the image to a larger size */
1283 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1284 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1285 if (g->scale_up_factor < 1)
1286 g->scale_up_factor = 1; /* no scaling */
1291 /* get final bitmap size (with scaling, but without small images) */
1292 int src_image_width = get_scaled_graphic_width(graphic);
1293 int src_image_height = get_scaled_graphic_height(graphic);
1295 if (src_image_width == 0 || src_image_height == 0)
1297 /* only happens when loaded outside artwork system (like "global.busy") */
1298 src_image_width = src_bitmap->width;
1299 src_image_height = src_bitmap->height;
1302 anim_frames_per_row = src_image_width / g->width;
1303 anim_frames_per_col = src_image_height / g->height;
1305 g->src_image_width = src_image_width;
1306 g->src_image_height = src_image_height;
1309 /* correct x or y offset dependent of vertical or horizontal frame order */
1310 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1312 g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1313 parameter[GFX_ARG_OFFSET] : g->height);
1314 anim_frames_per_line = anim_frames_per_col;
1316 else /* frames are ordered horizontally */
1318 g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1319 parameter[GFX_ARG_OFFSET] : g->width);
1320 anim_frames_per_line = anim_frames_per_row;
1323 /* optionally, the x and y offset of frames can be specified directly */
1324 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1325 g->offset_x = parameter[GFX_ARG_XOFFSET];
1326 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1327 g->offset_y = parameter[GFX_ARG_YOFFSET];
1329 /* optionally, moving animations may have separate start and end graphics */
1330 g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1332 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1333 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1335 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1336 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1337 g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1338 parameter[GFX_ARG_2ND_OFFSET] : g->height);
1339 else /* frames are ordered horizontally */
1340 g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1341 parameter[GFX_ARG_2ND_OFFSET] : g->width);
1343 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1344 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1345 g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1346 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1347 g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1349 /* optionally, the second movement tile can be specified as start tile */
1350 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1351 g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1353 /* automatically determine correct number of frames, if not defined */
1354 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1355 g->anim_frames = parameter[GFX_ARG_FRAMES];
1356 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1357 g->anim_frames = anim_frames_per_row;
1358 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1359 g->anim_frames = anim_frames_per_col;
1363 if (g->anim_frames == 0) /* frames must be at least 1 */
1366 g->anim_frames_per_line =
1367 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1368 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1370 g->anim_delay = parameter[GFX_ARG_DELAY];
1371 if (g->anim_delay == 0) /* delay must be at least 1 */
1374 g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1376 if (g->anim_frames == 1)
1377 g->anim_mode = ANIM_NONE;
1380 /* automatically determine correct start frame, if not defined */
1381 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1382 g->anim_start_frame = 0;
1383 else if (g->anim_mode & ANIM_REVERSE)
1384 g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1386 g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1388 /* animation synchronized with global frame counter, not move position */
1389 g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1391 /* optional element for cloning crumble graphics */
1392 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1393 g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1395 /* optional element for cloning digging graphics */
1396 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1397 g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1399 /* optional border size for "crumbling" diggable graphics */
1400 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1401 g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1403 /* this is only used for player "boring" and "sleeping" actions */
1404 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1405 g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1406 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1407 g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1408 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1409 g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1410 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1411 g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1413 /* this is only used for toon animations */
1414 g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1415 g->step_delay = parameter[GFX_ARG_STEP_DELAY];
1417 /* this is only used for drawing font characters */
1418 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1419 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1421 /* this is only used for drawing envelope graphics */
1422 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1424 /* optional graphic for cloning all graphics settings */
1425 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1426 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1428 /* optional settings for drawing title screens and title messages */
1429 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1430 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1431 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1432 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1433 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1434 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1435 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1436 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1437 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1438 g->align = parameter[GFX_ARG_ALIGN];
1439 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1440 g->valign = parameter[GFX_ARG_VALIGN];
1441 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1442 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1444 if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
1445 g->class = parameter[GFX_ARG_CLASS];
1446 if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
1447 g->style = parameter[GFX_ARG_STYLE];
1449 /* this is only used for drawing menu buttons and text */
1450 g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
1451 g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
1452 g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
1453 g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
1456 static void set_graphic_parameters(int graphic)
1459 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1460 char **parameter_raw = image->parameter;
1461 Bitmap *src_bitmap = getBitmapFromImageID(graphic);
1462 int parameter[NUM_GFX_ARGS];
1465 /* if fallback to default artwork is done, also use the default parameters */
1466 if (image->fallback_to_default)
1467 parameter_raw = image->default_parameter;
1469 /* get integer values from string parameters */
1470 for (i = 0; i < NUM_GFX_ARGS; i++)
1471 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1472 image_config_suffix[i].token,
1473 image_config_suffix[i].type);
1475 set_graphic_parameters_ext(graphic, parameter, src_bitmap);
1479 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1480 char **parameter_raw = image->parameter;
1481 Bitmap *src_bitmap = getBitmapFromImageID(graphic);
1482 int parameter[NUM_GFX_ARGS];
1483 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1484 int anim_frames_per_line = 1;
1487 /* if fallback to default artwork is done, also use the default parameters */
1488 if (image->fallback_to_default)
1489 parameter_raw = image->default_parameter;
1491 /* get integer values from string parameters */
1492 for (i = 0; i < NUM_GFX_ARGS; i++)
1493 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1494 image_config_suffix[i].token,
1495 image_config_suffix[i].type);
1497 graphic_info[graphic].bitmap = src_bitmap;
1499 /* always start with reliable default values */
1500 graphic_info[graphic].src_image_width = 0;
1501 graphic_info[graphic].src_image_height = 0;
1502 graphic_info[graphic].src_x = 0;
1503 graphic_info[graphic].src_y = 0;
1504 graphic_info[graphic].width = TILEX; /* default for element graphics */
1505 graphic_info[graphic].height = TILEY; /* default for element graphics */
1506 graphic_info[graphic].offset_x = 0; /* one or both of these values ... */
1507 graphic_info[graphic].offset_y = 0; /* ... will be corrected later */
1508 graphic_info[graphic].offset2_x = 0; /* one or both of these values ... */
1509 graphic_info[graphic].offset2_y = 0; /* ... will be corrected later */
1510 graphic_info[graphic].swap_double_tiles = -1; /* auto-detect tile swapping */
1511 graphic_info[graphic].crumbled_like = -1; /* do not use clone element */
1512 graphic_info[graphic].diggable_like = -1; /* do not use clone element */
1513 graphic_info[graphic].border_size = TILEX / 8; /* "CRUMBLED" border size */
1514 graphic_info[graphic].scale_up_factor = 1; /* default: no scaling up */
1515 graphic_info[graphic].clone_from = -1; /* do not use clone graphic */
1516 graphic_info[graphic].anim_delay_fixed = 0;
1517 graphic_info[graphic].anim_delay_random = 0;
1518 graphic_info[graphic].post_delay_fixed = 0;
1519 graphic_info[graphic].post_delay_random = 0;
1520 graphic_info[graphic].fade_mode = FADE_MODE_DEFAULT;
1521 graphic_info[graphic].fade_delay = -1;
1522 graphic_info[graphic].post_delay = -1;
1523 graphic_info[graphic].auto_delay = -1;
1524 graphic_info[graphic].align = ALIGN_CENTER; /* default for title screens */
1525 graphic_info[graphic].valign = VALIGN_MIDDLE; /* default for title screens */
1526 graphic_info[graphic].sort_priority = 0; /* default for title screens */
1529 /* optional zoom factor for scaling up the image to a larger size */
1530 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1531 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1532 if (graphic_info[graphic].scale_up_factor < 1)
1533 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
1537 if (graphic_info[graphic].use_image_size)
1539 /* set new default bitmap size (with scaling, but without small images) */
1540 graphic_info[graphic].width = get_scaled_graphic_width(graphic);
1541 graphic_info[graphic].height = get_scaled_graphic_height(graphic);
1545 /* optional x and y tile position of animation frame sequence */
1546 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1547 graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
1548 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1549 graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
1551 /* optional x and y pixel position of animation frame sequence */
1552 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1553 graphic_info[graphic].src_x = parameter[GFX_ARG_X];
1554 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1555 graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
1557 /* optional width and height of each animation frame */
1558 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1559 graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
1560 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1561 graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
1564 /* optional zoom factor for scaling up the image to a larger size */
1565 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1566 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1567 if (graphic_info[graphic].scale_up_factor < 1)
1568 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
1573 /* get final bitmap size (with scaling, but without small images) */
1574 int src_image_width = get_scaled_graphic_width(graphic);
1575 int src_image_height = get_scaled_graphic_height(graphic);
1577 anim_frames_per_row = src_image_width / graphic_info[graphic].width;
1578 anim_frames_per_col = src_image_height / graphic_info[graphic].height;
1580 graphic_info[graphic].src_image_width = src_image_width;
1581 graphic_info[graphic].src_image_height = src_image_height;
1584 /* correct x or y offset dependent of vertical or horizontal frame order */
1585 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1587 graphic_info[graphic].offset_y =
1588 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1589 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
1590 anim_frames_per_line = anim_frames_per_col;
1592 else /* frames are ordered horizontally */
1594 graphic_info[graphic].offset_x =
1595 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1596 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
1597 anim_frames_per_line = anim_frames_per_row;
1600 /* optionally, the x and y offset of frames can be specified directly */
1601 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1602 graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
1603 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1604 graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
1606 /* optionally, moving animations may have separate start and end graphics */
1607 graphic_info[graphic].double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1609 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1610 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1612 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1613 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1614 graphic_info[graphic].offset2_y =
1615 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1616 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].height);
1617 else /* frames are ordered horizontally */
1618 graphic_info[graphic].offset2_x =
1619 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1620 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].width);
1622 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1623 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1624 graphic_info[graphic].offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1625 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1626 graphic_info[graphic].offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1628 /* optionally, the second movement tile can be specified as start tile */
1629 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1630 graphic_info[graphic].swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1632 /* automatically determine correct number of frames, if not defined */
1633 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1634 graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
1635 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1636 graphic_info[graphic].anim_frames = anim_frames_per_row;
1637 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1638 graphic_info[graphic].anim_frames = anim_frames_per_col;
1640 graphic_info[graphic].anim_frames = 1;
1642 if (graphic_info[graphic].anim_frames == 0) /* frames must be at least 1 */
1643 graphic_info[graphic].anim_frames = 1;
1645 graphic_info[graphic].anim_frames_per_line =
1646 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1647 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1649 graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
1650 if (graphic_info[graphic].anim_delay == 0) /* delay must be at least 1 */
1651 graphic_info[graphic].anim_delay = 1;
1653 graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
1655 if (graphic_info[graphic].anim_frames == 1)
1656 graphic_info[graphic].anim_mode = ANIM_NONE;
1659 /* automatically determine correct start frame, if not defined */
1660 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1661 graphic_info[graphic].anim_start_frame = 0;
1662 else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
1663 graphic_info[graphic].anim_start_frame =
1664 graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1666 graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
1668 /* animation synchronized with global frame counter, not move position */
1669 graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1671 /* optional element for cloning crumble graphics */
1672 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1673 graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1675 /* optional element for cloning digging graphics */
1676 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1677 graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1679 /* optional border size for "crumbling" diggable graphics */
1680 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1681 graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
1683 /* this is only used for player "boring" and "sleeping" actions */
1684 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1685 graphic_info[graphic].anim_delay_fixed =
1686 parameter[GFX_ARG_ANIM_DELAY_FIXED];
1687 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1688 graphic_info[graphic].anim_delay_random =
1689 parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1690 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1691 graphic_info[graphic].post_delay_fixed =
1692 parameter[GFX_ARG_POST_DELAY_FIXED];
1693 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1694 graphic_info[graphic].post_delay_random =
1695 parameter[GFX_ARG_POST_DELAY_RANDOM];
1697 /* this is only used for toon animations */
1698 graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
1699 graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY];
1701 /* this is only used for drawing font characters */
1702 graphic_info[graphic].draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1703 graphic_info[graphic].draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1705 /* this is only used for drawing envelope graphics */
1706 graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1708 /* optional graphic for cloning all graphics settings */
1709 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1710 graphic_info[graphic].clone_from = parameter[GFX_ARG_CLONE_FROM];
1712 /* optional settings for drawing title screens and title messages */
1713 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1714 graphic_info[graphic].fade_mode = parameter[GFX_ARG_FADE_MODE];
1715 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1716 graphic_info[graphic].fade_delay = parameter[GFX_ARG_FADE_DELAY];
1717 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1718 graphic_info[graphic].post_delay = parameter[GFX_ARG_POST_DELAY];
1719 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1720 graphic_info[graphic].auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1721 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1722 graphic_info[graphic].align = parameter[GFX_ARG_ALIGN];
1723 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1724 graphic_info[graphic].valign = parameter[GFX_ARG_VALIGN];
1725 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1726 graphic_info[graphic].sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1729 UPDATE_BUSY_STATE();
1732 static void set_cloned_graphic_parameters(int graphic)
1734 int fallback_graphic = IMG_CHAR_EXCLAM;
1735 int max_num_images = getImageListSize();
1736 int clone_graphic = graphic_info[graphic].clone_from;
1737 int num_references_followed = 1;
1739 while (graphic_info[clone_graphic].clone_from != -1 &&
1740 num_references_followed < max_num_images)
1742 clone_graphic = graphic_info[clone_graphic].clone_from;
1744 num_references_followed++;
1747 if (num_references_followed >= max_num_images)
1749 Error(ERR_INFO_LINE, "-");
1750 Error(ERR_INFO, "warning: error found in config file:");
1751 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1752 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1753 Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1754 Error(ERR_INFO, "custom graphic rejected for this element/action");
1756 if (graphic == fallback_graphic)
1757 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1759 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1760 Error(ERR_INFO_LINE, "-");
1762 graphic_info[graphic] = graphic_info[fallback_graphic];
1766 graphic_info[graphic] = graphic_info[clone_graphic];
1767 graphic_info[graphic].clone_from = clone_graphic;
1771 static void InitGraphicInfo()
1773 int fallback_graphic = IMG_CHAR_EXCLAM;
1774 int num_images = getImageListSize();
1777 /* use image size as default values for width and height for these images */
1778 static int full_size_graphics[] =
1783 IMG_BACKGROUND_ENVELOPE_1,
1784 IMG_BACKGROUND_ENVELOPE_2,
1785 IMG_BACKGROUND_ENVELOPE_3,
1786 IMG_BACKGROUND_ENVELOPE_4,
1787 IMG_BACKGROUND_REQUEST,
1790 IMG_BACKGROUND_TITLE_INITIAL,
1791 IMG_BACKGROUND_TITLE,
1792 IMG_BACKGROUND_MAIN,
1793 IMG_BACKGROUND_LEVELS,
1794 IMG_BACKGROUND_LEVELNR,
1795 IMG_BACKGROUND_SCORES,
1796 IMG_BACKGROUND_EDITOR,
1797 IMG_BACKGROUND_INFO,
1798 IMG_BACKGROUND_INFO_ELEMENTS,
1799 IMG_BACKGROUND_INFO_MUSIC,
1800 IMG_BACKGROUND_INFO_CREDITS,
1801 IMG_BACKGROUND_INFO_PROGRAM,
1802 IMG_BACKGROUND_INFO_VERSION,
1803 IMG_BACKGROUND_INFO_LEVELSET,
1804 IMG_BACKGROUND_SETUP,
1805 IMG_BACKGROUND_PLAYING,
1806 IMG_BACKGROUND_DOOR,
1807 IMG_BACKGROUND_TAPE,
1808 IMG_BACKGROUND_PANEL,
1809 IMG_BACKGROUND_PALETTE,
1810 IMG_BACKGROUND_TOOLBOX,
1812 IMG_TITLESCREEN_INITIAL_1,
1813 IMG_TITLESCREEN_INITIAL_2,
1814 IMG_TITLESCREEN_INITIAL_3,
1815 IMG_TITLESCREEN_INITIAL_4,
1816 IMG_TITLESCREEN_INITIAL_5,
1823 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1,
1824 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2,
1825 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3,
1826 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4,
1827 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5,
1828 IMG_BACKGROUND_TITLEMESSAGE_1,
1829 IMG_BACKGROUND_TITLEMESSAGE_2,
1830 IMG_BACKGROUND_TITLEMESSAGE_3,
1831 IMG_BACKGROUND_TITLEMESSAGE_4,
1832 IMG_BACKGROUND_TITLEMESSAGE_5,
1837 checked_free(graphic_info);
1839 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1842 /* initialize "use_image_size" flag with default value */
1843 for (i = 0; i < num_images; i++)
1844 graphic_info[i].use_image_size = FALSE;
1846 /* initialize "use_image_size" flag from static configuration above */
1847 for (i = 0; full_size_graphics[i] != -1; i++)
1848 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1851 /* first set all graphic paramaters ... */
1852 for (i = 0; i < num_images; i++)
1853 set_graphic_parameters(i);
1855 /* ... then copy these parameters for cloned graphics */
1856 for (i = 0; i < num_images; i++)
1857 if (graphic_info[i].clone_from != -1)
1858 set_cloned_graphic_parameters(i);
1860 for (i = 0; i < num_images; i++)
1865 int first_frame, last_frame;
1866 int src_bitmap_width, src_bitmap_height;
1868 /* now check if no animation frames are outside of the loaded image */
1870 if (graphic_info[i].bitmap == NULL)
1871 continue; /* skip check for optional images that are undefined */
1873 /* get image size (this can differ from the standard element tile size!) */
1874 width = graphic_info[i].width;
1875 height = graphic_info[i].height;
1877 /* get final bitmap size (with scaling, but without small images) */
1878 src_bitmap_width = graphic_info[i].src_image_width;
1879 src_bitmap_height = graphic_info[i].src_image_height;
1881 /* check if first animation frame is inside specified bitmap */
1884 getFixedGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1887 /* this avoids calculating wrong start position for out-of-bounds frame */
1888 src_x = graphic_info[i].src_x;
1889 src_y = graphic_info[i].src_y;
1892 if (src_x < 0 || src_y < 0 ||
1893 src_x + width > src_bitmap_width ||
1894 src_y + height > src_bitmap_height)
1896 Error(ERR_INFO_LINE, "-");
1897 Error(ERR_INFO, "warning: error found in config file:");
1898 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1899 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1900 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1902 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1903 src_x, src_y, src_bitmap_width, src_bitmap_height);
1904 Error(ERR_INFO, "custom graphic rejected for this element/action");
1906 if (i == fallback_graphic)
1907 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1909 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1910 Error(ERR_INFO_LINE, "-");
1912 graphic_info[i] = graphic_info[fallback_graphic];
1915 /* check if last animation frame is inside specified bitmap */
1917 last_frame = graphic_info[i].anim_frames - 1;
1918 getFixedGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1920 if (src_x < 0 || src_y < 0 ||
1921 src_x + width > src_bitmap_width ||
1922 src_y + height > src_bitmap_height)
1924 Error(ERR_INFO_LINE, "-");
1925 Error(ERR_INFO, "warning: error found in config file:");
1926 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1927 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1928 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1930 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1931 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1932 Error(ERR_INFO, "::: %d, %d", width, height);
1933 Error(ERR_INFO, "custom graphic rejected for this element/action");
1935 if (i == fallback_graphic)
1936 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1938 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1939 Error(ERR_INFO_LINE, "-");
1941 graphic_info[i] = graphic_info[fallback_graphic];
1946 static void InitGraphicCompatibilityInfo()
1948 struct FileInfo *fi_global_door =
1949 getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1950 int num_images = getImageListSize();
1953 /* the following compatibility handling is needed for the following case:
1954 versions up to 3.3.0.0 used one large bitmap "global.door" for various
1955 graphics mainly used for door and panel graphics, like editor, tape and
1956 in-game buttons with hard-coded bitmap positions and button sizes; as
1957 these graphics now have individual definitions, redefining "global.door"
1958 to change all these graphics at once like before does not work anymore
1959 (because all those individual definitions still have their default values);
1960 to solve this, remap all those individual definitions that are not
1961 redefined to the new bitmap of "global.door" if it was redefined */
1963 /* special compatibility handling if image "global.door" was redefined */
1964 if (fi_global_door->redefined)
1966 for (i = 0; i < num_images; i++)
1968 struct FileInfo *fi = getImageListEntryFromImageID(i);
1970 /* process only those images that still use the default settings */
1973 /* process all images which default to same image as "global.door" */
1974 if (strEqual(fi->default_filename, fi_global_door->default_filename))
1976 // printf("::: special treatment needed for token '%s'\n", fi->token);
1978 graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
1985 InitGraphicCompatibilityInfo_Doors();
1992 int *width, *height;
1997 { IMG_DOOR_1_WING_LEFT, &door_1.width, &door_1.height, FALSE },
1998 { IMG_DOOR_1_WING_RIGHT, &door_1.width, &door_1.height, TRUE },
1999 { IMG_DOOR_2_WING_LEFT, &door_2.width, &door_2.height, FALSE },
2000 { IMG_DOOR_2_WING_RIGHT, &door_2.width, &door_2.height, TRUE },
2002 { 0, NULL, NULL, FALSE }
2005 for (i = 0; doors[i].graphic != 0; i++)
2007 int graphic = doors[i].graphic;
2008 int *width = doors[i].width;
2009 int *height = doors[i].height;
2010 boolean right_wing = doors[i].right_wing;
2012 struct FileInfo *fi = getImageListEntryFromImageID(graphic);
2013 struct GraphicInfo *g = &graphic_info[graphic];
2019 // correct start position for right wing of "standard" door graphic
2021 g->src_x += g->width - *width;
2027 g->height = *height;
2033 for (i = 0; i < num_images; i++)
2035 struct FileInfo *fi = getImageListEntryFromImageID(i);
2037 if (i == IMG_GLOBAL_DOOR)
2039 printf("::: %s, %s, %d\n",
2040 fi->default_filename,
2048 static void InitElementSoundInfo()
2050 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
2051 int num_property_mappings = getSoundListPropertyMappingSize();
2054 /* set values to -1 to identify later as "uninitialized" values */
2055 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2056 for (act = 0; act < NUM_ACTIONS; act++)
2057 element_info[i].sound[act] = -1;
2059 /* initialize element/sound mapping from static configuration */
2060 for (i = 0; element_to_sound[i].element > -1; i++)
2062 int element = element_to_sound[i].element;
2063 int action = element_to_sound[i].action;
2064 int sound = element_to_sound[i].sound;
2065 boolean is_class = element_to_sound[i].is_class;
2068 action = ACTION_DEFAULT;
2071 element_info[element].sound[action] = sound;
2073 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2074 if (strEqual(element_info[j].class_name,
2075 element_info[element].class_name))
2076 element_info[j].sound[action] = sound;
2079 /* initialize element class/sound mapping from dynamic configuration */
2080 for (i = 0; i < num_property_mappings; i++)
2082 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
2083 int action = property_mapping[i].ext1_index;
2084 int sound = property_mapping[i].artwork_index;
2086 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
2090 action = ACTION_DEFAULT;
2092 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2093 if (strEqual(element_info[j].class_name,
2094 element_info[element_class].class_name))
2095 element_info[j].sound[action] = sound;
2098 /* initialize element/sound mapping from dynamic configuration */
2099 for (i = 0; i < num_property_mappings; i++)
2101 int element = property_mapping[i].base_index;
2102 int action = property_mapping[i].ext1_index;
2103 int sound = property_mapping[i].artwork_index;
2105 if (element >= MAX_NUM_ELEMENTS)
2109 action = ACTION_DEFAULT;
2111 element_info[element].sound[action] = sound;
2114 /* now set all '-1' values to element specific default values */
2115 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2117 for (act = 0; act < NUM_ACTIONS; act++)
2119 /* generic default action sound (defined by "[default]" directive) */
2120 int default_action_sound = element_info[EL_DEFAULT].sound[act];
2122 /* look for special default action sound (classic game specific) */
2123 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
2124 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
2125 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
2126 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
2127 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
2128 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
2130 /* !!! there's no such thing as a "default action sound" !!! */
2132 /* look for element specific default sound (independent from action) */
2133 if (element_info[i].sound[ACTION_DEFAULT] != -1)
2134 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
2138 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
2139 /* !!! make this better !!! */
2140 if (i == EL_EMPTY_SPACE)
2141 default_action_sound = element_info[EL_DEFAULT].sound[act];
2144 /* no sound for this specific action -- use default action sound */
2145 if (element_info[i].sound[act] == -1)
2146 element_info[i].sound[act] = default_action_sound;
2150 /* copy sound settings to some elements that are only stored in level file
2151 in native R'n'D levels, but are used by game engine in native EM levels */
2152 for (i = 0; copy_properties[i][0] != -1; i++)
2153 for (j = 1; j <= 4; j++)
2154 for (act = 0; act < NUM_ACTIONS; act++)
2155 element_info[copy_properties[i][j]].sound[act] =
2156 element_info[copy_properties[i][0]].sound[act];
2159 static void InitGameModeSoundInfo()
2163 /* set values to -1 to identify later as "uninitialized" values */
2164 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2167 /* initialize gamemode/sound mapping from static configuration */
2168 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
2170 int gamemode = gamemode_to_sound[i].gamemode;
2171 int sound = gamemode_to_sound[i].sound;
2174 gamemode = GAME_MODE_DEFAULT;
2176 menu.sound[gamemode] = sound;
2179 /* now set all '-1' values to levelset specific default values */
2180 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2181 if (menu.sound[i] == -1)
2182 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
2185 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2186 if (menu.sound[i] != -1)
2187 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
2191 static void set_sound_parameters(int sound, char **parameter_raw)
2193 int parameter[NUM_SND_ARGS];
2196 /* get integer values from string parameters */
2197 for (i = 0; i < NUM_SND_ARGS; i++)
2199 get_parameter_value(parameter_raw[i],
2200 sound_config_suffix[i].token,
2201 sound_config_suffix[i].type);
2203 /* explicit loop mode setting in configuration overrides default value */
2204 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2205 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
2207 /* sound volume to change the original volume when loading the sound file */
2208 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
2210 /* sound priority to give certain sounds a higher or lower priority */
2211 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
2214 static void InitSoundInfo()
2216 int *sound_effect_properties;
2217 int num_sounds = getSoundListSize();
2220 checked_free(sound_info);
2222 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
2223 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
2225 /* initialize sound effect for all elements to "no sound" */
2226 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2227 for (j = 0; j < NUM_ACTIONS; j++)
2228 element_info[i].sound[j] = SND_UNDEFINED;
2230 for (i = 0; i < num_sounds; i++)
2232 struct FileInfo *sound = getSoundListEntry(i);
2233 int len_effect_text = strlen(sound->token);
2235 sound_effect_properties[i] = ACTION_OTHER;
2236 sound_info[i].loop = FALSE; /* default: play sound only once */
2239 printf("::: sound %d: '%s'\n", i, sound->token);
2242 /* determine all loop sounds and identify certain sound classes */
2244 for (j = 0; element_action_info[j].suffix; j++)
2246 int len_action_text = strlen(element_action_info[j].suffix);
2248 if (len_action_text < len_effect_text &&
2249 strEqual(&sound->token[len_effect_text - len_action_text],
2250 element_action_info[j].suffix))
2252 sound_effect_properties[i] = element_action_info[j].value;
2253 sound_info[i].loop = element_action_info[j].is_loop_sound;
2259 /* associate elements and some selected sound actions */
2261 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2263 if (element_info[j].class_name)
2265 int len_class_text = strlen(element_info[j].class_name);
2267 if (len_class_text + 1 < len_effect_text &&
2268 strncmp(sound->token,
2269 element_info[j].class_name, len_class_text) == 0 &&
2270 sound->token[len_class_text] == '.')
2272 int sound_action_value = sound_effect_properties[i];
2274 element_info[j].sound[sound_action_value] = i;
2279 set_sound_parameters(i, sound->parameter);
2282 free(sound_effect_properties);
2285 static void InitGameModeMusicInfo()
2287 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
2288 int num_property_mappings = getMusicListPropertyMappingSize();
2289 int default_levelset_music = -1;
2292 /* set values to -1 to identify later as "uninitialized" values */
2293 for (i = 0; i < MAX_LEVELS; i++)
2294 levelset.music[i] = -1;
2295 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2298 /* initialize gamemode/music mapping from static configuration */
2299 for (i = 0; gamemode_to_music[i].music > -1; i++)
2301 int gamemode = gamemode_to_music[i].gamemode;
2302 int music = gamemode_to_music[i].music;
2305 printf("::: gamemode == %d, music == %d\n", gamemode, music);
2309 gamemode = GAME_MODE_DEFAULT;
2311 menu.music[gamemode] = music;
2314 /* initialize gamemode/music mapping from dynamic configuration */
2315 for (i = 0; i < num_property_mappings; i++)
2317 int prefix = property_mapping[i].base_index;
2318 int gamemode = property_mapping[i].ext1_index;
2319 int level = property_mapping[i].ext2_index;
2320 int music = property_mapping[i].artwork_index;
2323 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
2324 prefix, gamemode, level, music);
2327 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
2331 gamemode = GAME_MODE_DEFAULT;
2333 /* level specific music only allowed for in-game music */
2334 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
2335 gamemode = GAME_MODE_PLAYING;
2340 default_levelset_music = music;
2343 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
2344 levelset.music[level] = music;
2345 if (gamemode != GAME_MODE_PLAYING)
2346 menu.music[gamemode] = music;
2349 /* now set all '-1' values to menu specific default values */
2350 /* (undefined values of "levelset.music[]" might stay at "-1" to
2351 allow dynamic selection of music files from music directory!) */
2352 for (i = 0; i < MAX_LEVELS; i++)
2353 if (levelset.music[i] == -1)
2354 levelset.music[i] = default_levelset_music;
2355 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2356 if (menu.music[i] == -1)
2357 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
2360 for (i = 0; i < MAX_LEVELS; i++)
2361 if (levelset.music[i] != -1)
2362 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
2363 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2364 if (menu.music[i] != -1)
2365 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
2369 static void set_music_parameters(int music, char **parameter_raw)
2371 int parameter[NUM_MUS_ARGS];
2374 /* get integer values from string parameters */
2375 for (i = 0; i < NUM_MUS_ARGS; i++)
2377 get_parameter_value(parameter_raw[i],
2378 music_config_suffix[i].token,
2379 music_config_suffix[i].type);
2381 /* explicit loop mode setting in configuration overrides default value */
2382 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2383 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
2386 static void InitMusicInfo()
2388 int num_music = getMusicListSize();
2391 checked_free(music_info);
2393 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
2395 for (i = 0; i < num_music; i++)
2397 struct FileInfo *music = getMusicListEntry(i);
2398 int len_music_text = strlen(music->token);
2400 music_info[i].loop = TRUE; /* default: play music in loop mode */
2402 /* determine all loop music */
2404 for (j = 0; music_prefix_info[j].prefix; j++)
2406 int len_prefix_text = strlen(music_prefix_info[j].prefix);
2408 if (len_prefix_text < len_music_text &&
2409 strncmp(music->token,
2410 music_prefix_info[j].prefix, len_prefix_text) == 0)
2412 music_info[i].loop = music_prefix_info[j].is_loop_music;
2418 set_music_parameters(i, music->parameter);
2422 static void ReinitializeGraphics()
2424 print_timestamp_init("ReinitializeGraphics");
2426 #if NEW_GAME_TILESIZE
2427 InitGfxTileSizeInfo(game.tile_size, TILESIZE);
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_time("InitDoors");
2462 print_timestamp_done("ReinitializeGraphics");
2465 static void ReinitializeSounds()
2467 InitSoundInfo(); /* sound properties mapping */
2468 InitElementSoundInfo(); /* element game sound mapping */
2469 InitGameModeSoundInfo(); /* game mode sound mapping */
2471 InitPlayLevelSound(); /* internal game sound settings */
2474 static void ReinitializeMusic()
2476 InitMusicInfo(); /* music properties mapping */
2477 InitGameModeMusicInfo(); /* game mode music mapping */
2480 static int get_special_property_bit(int element, int property_bit_nr)
2482 struct PropertyBitInfo
2488 static struct PropertyBitInfo pb_can_move_into_acid[] =
2490 /* the player may be able fall into acid when gravity is activated */
2495 { EL_SP_MURPHY, 0 },
2496 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2498 /* all elements that can move may be able to also move into acid */
2501 { EL_BUG_RIGHT, 1 },
2504 { EL_SPACESHIP, 2 },
2505 { EL_SPACESHIP_LEFT, 2 },
2506 { EL_SPACESHIP_RIGHT, 2 },
2507 { EL_SPACESHIP_UP, 2 },
2508 { EL_SPACESHIP_DOWN, 2 },
2509 { EL_BD_BUTTERFLY, 3 },
2510 { EL_BD_BUTTERFLY_LEFT, 3 },
2511 { EL_BD_BUTTERFLY_RIGHT, 3 },
2512 { EL_BD_BUTTERFLY_UP, 3 },
2513 { EL_BD_BUTTERFLY_DOWN, 3 },
2514 { EL_BD_FIREFLY, 4 },
2515 { EL_BD_FIREFLY_LEFT, 4 },
2516 { EL_BD_FIREFLY_RIGHT, 4 },
2517 { EL_BD_FIREFLY_UP, 4 },
2518 { EL_BD_FIREFLY_DOWN, 4 },
2520 { EL_YAMYAM_LEFT, 5 },
2521 { EL_YAMYAM_RIGHT, 5 },
2522 { EL_YAMYAM_UP, 5 },
2523 { EL_YAMYAM_DOWN, 5 },
2524 { EL_DARK_YAMYAM, 6 },
2527 { EL_PACMAN_LEFT, 8 },
2528 { EL_PACMAN_RIGHT, 8 },
2529 { EL_PACMAN_UP, 8 },
2530 { EL_PACMAN_DOWN, 8 },
2532 { EL_MOLE_LEFT, 9 },
2533 { EL_MOLE_RIGHT, 9 },
2535 { EL_MOLE_DOWN, 9 },
2539 { EL_SATELLITE, 13 },
2540 { EL_SP_SNIKSNAK, 14 },
2541 { EL_SP_ELECTRON, 15 },
2544 { EL_EMC_ANDROID, 18 },
2549 static struct PropertyBitInfo pb_dont_collide_with[] =
2551 { EL_SP_SNIKSNAK, 0 },
2552 { EL_SP_ELECTRON, 1 },
2560 struct PropertyBitInfo *pb_info;
2563 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2564 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2569 struct PropertyBitInfo *pb_info = NULL;
2572 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2573 if (pb_definition[i].bit_nr == property_bit_nr)
2574 pb_info = pb_definition[i].pb_info;
2576 if (pb_info == NULL)
2579 for (i = 0; pb_info[i].element != -1; i++)
2580 if (pb_info[i].element == element)
2581 return pb_info[i].bit_nr;
2586 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2587 boolean property_value)
2589 int bit_nr = get_special_property_bit(element, property_bit_nr);
2594 *bitfield |= (1 << bit_nr);
2596 *bitfield &= ~(1 << bit_nr);
2600 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2602 int bit_nr = get_special_property_bit(element, property_bit_nr);
2605 return ((*bitfield & (1 << bit_nr)) != 0);
2610 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2612 static int group_nr;
2613 static struct ElementGroupInfo *group;
2614 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2617 if (actual_group == NULL) /* not yet initialized */
2620 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
2622 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2623 group_element - EL_GROUP_START + 1);
2625 /* replace element which caused too deep recursion by question mark */
2626 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2631 if (recursion_depth == 0) /* initialization */
2633 group = actual_group;
2634 group_nr = GROUP_NR(group_element);
2636 group->num_elements_resolved = 0;
2637 group->choice_pos = 0;
2639 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2640 element_info[i].in_group[group_nr] = FALSE;
2643 for (i = 0; i < actual_group->num_elements; i++)
2645 int element = actual_group->element[i];
2647 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2650 if (IS_GROUP_ELEMENT(element))
2651 ResolveGroupElementExt(element, recursion_depth + 1);
2654 group->element_resolved[group->num_elements_resolved++] = element;
2655 element_info[element].in_group[group_nr] = TRUE;
2660 void ResolveGroupElement(int group_element)
2662 ResolveGroupElementExt(group_element, 0);
2665 void InitElementPropertiesStatic()
2667 static boolean clipboard_elements_initialized = FALSE;
2669 static int ep_diggable[] =
2674 EL_SP_BUGGY_BASE_ACTIVATING,
2677 EL_INVISIBLE_SAND_ACTIVE,
2680 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2681 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2686 EL_SP_BUGGY_BASE_ACTIVE,
2693 static int ep_collectible_only[] =
2715 EL_DYNABOMB_INCREASE_NUMBER,
2716 EL_DYNABOMB_INCREASE_SIZE,
2717 EL_DYNABOMB_INCREASE_POWER,
2735 /* !!! handle separately !!! */
2736 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2742 static int ep_dont_run_into[] =
2744 /* same elements as in 'ep_dont_touch' */
2750 /* same elements as in 'ep_dont_collide_with' */
2762 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2767 EL_SP_BUGGY_BASE_ACTIVE,
2774 static int ep_dont_collide_with[] =
2776 /* same elements as in 'ep_dont_touch' */
2793 static int ep_dont_touch[] =
2803 static int ep_indestructible[] =
2807 EL_ACID_POOL_TOPLEFT,
2808 EL_ACID_POOL_TOPRIGHT,
2809 EL_ACID_POOL_BOTTOMLEFT,
2810 EL_ACID_POOL_BOTTOM,
2811 EL_ACID_POOL_BOTTOMRIGHT,
2812 EL_SP_HARDWARE_GRAY,
2813 EL_SP_HARDWARE_GREEN,
2814 EL_SP_HARDWARE_BLUE,
2816 EL_SP_HARDWARE_YELLOW,
2817 EL_SP_HARDWARE_BASE_1,
2818 EL_SP_HARDWARE_BASE_2,
2819 EL_SP_HARDWARE_BASE_3,
2820 EL_SP_HARDWARE_BASE_4,
2821 EL_SP_HARDWARE_BASE_5,
2822 EL_SP_HARDWARE_BASE_6,
2823 EL_INVISIBLE_STEELWALL,
2824 EL_INVISIBLE_STEELWALL_ACTIVE,
2825 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2826 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2827 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2828 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2829 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2830 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2831 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2832 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2833 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2834 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2835 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2836 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2838 EL_LIGHT_SWITCH_ACTIVE,
2839 EL_SIGN_EXCLAMATION,
2840 EL_SIGN_RADIOACTIVITY,
2847 EL_SIGN_ENTRY_FORBIDDEN,
2848 EL_SIGN_EMERGENCY_EXIT,
2856 EL_STEEL_EXIT_CLOSED,
2858 EL_STEEL_EXIT_OPENING,
2859 EL_STEEL_EXIT_CLOSING,
2860 EL_EM_STEEL_EXIT_CLOSED,
2861 EL_EM_STEEL_EXIT_OPEN,
2862 EL_EM_STEEL_EXIT_OPENING,
2863 EL_EM_STEEL_EXIT_CLOSING,
2864 EL_DC_STEELWALL_1_LEFT,
2865 EL_DC_STEELWALL_1_RIGHT,
2866 EL_DC_STEELWALL_1_TOP,
2867 EL_DC_STEELWALL_1_BOTTOM,
2868 EL_DC_STEELWALL_1_HORIZONTAL,
2869 EL_DC_STEELWALL_1_VERTICAL,
2870 EL_DC_STEELWALL_1_TOPLEFT,
2871 EL_DC_STEELWALL_1_TOPRIGHT,
2872 EL_DC_STEELWALL_1_BOTTOMLEFT,
2873 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2874 EL_DC_STEELWALL_1_TOPLEFT_2,
2875 EL_DC_STEELWALL_1_TOPRIGHT_2,
2876 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2877 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2878 EL_DC_STEELWALL_2_LEFT,
2879 EL_DC_STEELWALL_2_RIGHT,
2880 EL_DC_STEELWALL_2_TOP,
2881 EL_DC_STEELWALL_2_BOTTOM,
2882 EL_DC_STEELWALL_2_HORIZONTAL,
2883 EL_DC_STEELWALL_2_VERTICAL,
2884 EL_DC_STEELWALL_2_MIDDLE,
2885 EL_DC_STEELWALL_2_SINGLE,
2886 EL_STEELWALL_SLIPPERY,
2900 EL_GATE_1_GRAY_ACTIVE,
2901 EL_GATE_2_GRAY_ACTIVE,
2902 EL_GATE_3_GRAY_ACTIVE,
2903 EL_GATE_4_GRAY_ACTIVE,
2912 EL_EM_GATE_1_GRAY_ACTIVE,
2913 EL_EM_GATE_2_GRAY_ACTIVE,
2914 EL_EM_GATE_3_GRAY_ACTIVE,
2915 EL_EM_GATE_4_GRAY_ACTIVE,
2924 EL_EMC_GATE_5_GRAY_ACTIVE,
2925 EL_EMC_GATE_6_GRAY_ACTIVE,
2926 EL_EMC_GATE_7_GRAY_ACTIVE,
2927 EL_EMC_GATE_8_GRAY_ACTIVE,
2929 EL_DC_GATE_WHITE_GRAY,
2930 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2931 EL_DC_GATE_FAKE_GRAY,
2933 EL_SWITCHGATE_OPENING,
2934 EL_SWITCHGATE_CLOSED,
2935 EL_SWITCHGATE_CLOSING,
2937 EL_DC_SWITCHGATE_SWITCH_UP,
2938 EL_DC_SWITCHGATE_SWITCH_DOWN,
2941 EL_TIMEGATE_OPENING,
2943 EL_TIMEGATE_CLOSING,
2945 EL_DC_TIMEGATE_SWITCH,
2946 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2951 EL_TUBE_VERTICAL_LEFT,
2952 EL_TUBE_VERTICAL_RIGHT,
2953 EL_TUBE_HORIZONTAL_UP,
2954 EL_TUBE_HORIZONTAL_DOWN,
2959 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2960 EL_EXPANDABLE_STEELWALL_VERTICAL,
2961 EL_EXPANDABLE_STEELWALL_ANY,
2966 static int ep_slippery[] =
2980 EL_ROBOT_WHEEL_ACTIVE,
2986 EL_ACID_POOL_TOPLEFT,
2987 EL_ACID_POOL_TOPRIGHT,
2997 EL_STEELWALL_SLIPPERY,
3000 EL_EMC_WALL_SLIPPERY_1,
3001 EL_EMC_WALL_SLIPPERY_2,
3002 EL_EMC_WALL_SLIPPERY_3,
3003 EL_EMC_WALL_SLIPPERY_4,
3005 EL_EMC_MAGIC_BALL_ACTIVE,
3010 static int ep_can_change[] =
3015 static int ep_can_move[] =
3017 /* same elements as in 'pb_can_move_into_acid' */
3040 static int ep_can_fall[] =
3054 EL_QUICKSAND_FAST_FULL,
3056 EL_BD_MAGIC_WALL_FULL,
3057 EL_DC_MAGIC_WALL_FULL,
3071 static int ep_can_smash_player[] =
3097 static int ep_can_smash_enemies[] =
3106 static int ep_can_smash_everything[] =
3115 static int ep_explodes_by_fire[] =
3117 /* same elements as in 'ep_explodes_impact' */
3122 /* same elements as in 'ep_explodes_smashed' */
3132 EL_EM_DYNAMITE_ACTIVE,
3133 EL_DYNABOMB_PLAYER_1_ACTIVE,
3134 EL_DYNABOMB_PLAYER_2_ACTIVE,
3135 EL_DYNABOMB_PLAYER_3_ACTIVE,
3136 EL_DYNABOMB_PLAYER_4_ACTIVE,
3137 EL_DYNABOMB_INCREASE_NUMBER,
3138 EL_DYNABOMB_INCREASE_SIZE,
3139 EL_DYNABOMB_INCREASE_POWER,
3140 EL_SP_DISK_RED_ACTIVE,
3154 static int ep_explodes_smashed[] =
3156 /* same elements as in 'ep_explodes_impact' */
3170 static int ep_explodes_impact[] =
3179 static int ep_walkable_over[] =
3183 EL_SOKOBAN_FIELD_EMPTY,
3192 EL_EM_STEEL_EXIT_OPEN,
3194 EL_EM_STEEL_EXIT_OPENING,
3204 EL_GATE_1_GRAY_ACTIVE,
3205 EL_GATE_2_GRAY_ACTIVE,
3206 EL_GATE_3_GRAY_ACTIVE,
3207 EL_GATE_4_GRAY_ACTIVE,
3215 static int ep_walkable_inside[] =
3220 EL_TUBE_VERTICAL_LEFT,
3221 EL_TUBE_VERTICAL_RIGHT,
3222 EL_TUBE_HORIZONTAL_UP,
3223 EL_TUBE_HORIZONTAL_DOWN,
3232 static int ep_walkable_under[] =
3237 static int ep_passable_over[] =
3247 EL_EM_GATE_1_GRAY_ACTIVE,
3248 EL_EM_GATE_2_GRAY_ACTIVE,
3249 EL_EM_GATE_3_GRAY_ACTIVE,
3250 EL_EM_GATE_4_GRAY_ACTIVE,
3259 EL_EMC_GATE_5_GRAY_ACTIVE,
3260 EL_EMC_GATE_6_GRAY_ACTIVE,
3261 EL_EMC_GATE_7_GRAY_ACTIVE,
3262 EL_EMC_GATE_8_GRAY_ACTIVE,
3264 EL_DC_GATE_WHITE_GRAY,
3265 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3272 static int ep_passable_inside[] =
3278 EL_SP_PORT_HORIZONTAL,
3279 EL_SP_PORT_VERTICAL,
3281 EL_SP_GRAVITY_PORT_LEFT,
3282 EL_SP_GRAVITY_PORT_RIGHT,
3283 EL_SP_GRAVITY_PORT_UP,
3284 EL_SP_GRAVITY_PORT_DOWN,
3285 EL_SP_GRAVITY_ON_PORT_LEFT,
3286 EL_SP_GRAVITY_ON_PORT_RIGHT,
3287 EL_SP_GRAVITY_ON_PORT_UP,
3288 EL_SP_GRAVITY_ON_PORT_DOWN,
3289 EL_SP_GRAVITY_OFF_PORT_LEFT,
3290 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3291 EL_SP_GRAVITY_OFF_PORT_UP,
3292 EL_SP_GRAVITY_OFF_PORT_DOWN,
3297 static int ep_passable_under[] =
3302 static int ep_droppable[] =
3307 static int ep_explodes_1x1_old[] =
3312 static int ep_pushable[] =
3324 EL_SOKOBAN_FIELD_FULL,
3333 static int ep_explodes_cross_old[] =
3338 static int ep_protected[] =
3340 /* same elements as in 'ep_walkable_inside' */
3344 EL_TUBE_VERTICAL_LEFT,
3345 EL_TUBE_VERTICAL_RIGHT,
3346 EL_TUBE_HORIZONTAL_UP,
3347 EL_TUBE_HORIZONTAL_DOWN,
3353 /* same elements as in 'ep_passable_over' */
3362 EL_EM_GATE_1_GRAY_ACTIVE,
3363 EL_EM_GATE_2_GRAY_ACTIVE,
3364 EL_EM_GATE_3_GRAY_ACTIVE,
3365 EL_EM_GATE_4_GRAY_ACTIVE,
3374 EL_EMC_GATE_5_GRAY_ACTIVE,
3375 EL_EMC_GATE_6_GRAY_ACTIVE,
3376 EL_EMC_GATE_7_GRAY_ACTIVE,
3377 EL_EMC_GATE_8_GRAY_ACTIVE,
3379 EL_DC_GATE_WHITE_GRAY,
3380 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3384 /* same elements as in 'ep_passable_inside' */
3389 EL_SP_PORT_HORIZONTAL,
3390 EL_SP_PORT_VERTICAL,
3392 EL_SP_GRAVITY_PORT_LEFT,
3393 EL_SP_GRAVITY_PORT_RIGHT,
3394 EL_SP_GRAVITY_PORT_UP,
3395 EL_SP_GRAVITY_PORT_DOWN,
3396 EL_SP_GRAVITY_ON_PORT_LEFT,
3397 EL_SP_GRAVITY_ON_PORT_RIGHT,
3398 EL_SP_GRAVITY_ON_PORT_UP,
3399 EL_SP_GRAVITY_ON_PORT_DOWN,
3400 EL_SP_GRAVITY_OFF_PORT_LEFT,
3401 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3402 EL_SP_GRAVITY_OFF_PORT_UP,
3403 EL_SP_GRAVITY_OFF_PORT_DOWN,
3408 static int ep_throwable[] =
3413 static int ep_can_explode[] =
3415 /* same elements as in 'ep_explodes_impact' */
3420 /* same elements as in 'ep_explodes_smashed' */
3426 /* elements that can explode by explosion or by dragonfire */
3430 EL_EM_DYNAMITE_ACTIVE,
3431 EL_DYNABOMB_PLAYER_1_ACTIVE,
3432 EL_DYNABOMB_PLAYER_2_ACTIVE,
3433 EL_DYNABOMB_PLAYER_3_ACTIVE,
3434 EL_DYNABOMB_PLAYER_4_ACTIVE,
3435 EL_DYNABOMB_INCREASE_NUMBER,
3436 EL_DYNABOMB_INCREASE_SIZE,
3437 EL_DYNABOMB_INCREASE_POWER,
3438 EL_SP_DISK_RED_ACTIVE,
3446 /* elements that can explode only by explosion */
3452 static int ep_gravity_reachable[] =
3458 EL_INVISIBLE_SAND_ACTIVE,
3463 EL_SP_PORT_HORIZONTAL,
3464 EL_SP_PORT_VERTICAL,
3466 EL_SP_GRAVITY_PORT_LEFT,
3467 EL_SP_GRAVITY_PORT_RIGHT,
3468 EL_SP_GRAVITY_PORT_UP,
3469 EL_SP_GRAVITY_PORT_DOWN,
3470 EL_SP_GRAVITY_ON_PORT_LEFT,
3471 EL_SP_GRAVITY_ON_PORT_RIGHT,
3472 EL_SP_GRAVITY_ON_PORT_UP,
3473 EL_SP_GRAVITY_ON_PORT_DOWN,
3474 EL_SP_GRAVITY_OFF_PORT_LEFT,
3475 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3476 EL_SP_GRAVITY_OFF_PORT_UP,
3477 EL_SP_GRAVITY_OFF_PORT_DOWN,
3483 static int ep_player[] =
3490 EL_SOKOBAN_FIELD_PLAYER,
3496 static int ep_can_pass_magic_wall[] =
3510 static int ep_can_pass_dc_magic_wall[] =
3526 static int ep_switchable[] =
3530 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3531 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3532 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3533 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3534 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3535 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3536 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3537 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3538 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3539 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3540 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3541 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3542 EL_SWITCHGATE_SWITCH_UP,
3543 EL_SWITCHGATE_SWITCH_DOWN,
3544 EL_DC_SWITCHGATE_SWITCH_UP,
3545 EL_DC_SWITCHGATE_SWITCH_DOWN,
3547 EL_LIGHT_SWITCH_ACTIVE,
3549 EL_DC_TIMEGATE_SWITCH,
3550 EL_BALLOON_SWITCH_LEFT,
3551 EL_BALLOON_SWITCH_RIGHT,
3552 EL_BALLOON_SWITCH_UP,
3553 EL_BALLOON_SWITCH_DOWN,
3554 EL_BALLOON_SWITCH_ANY,
3555 EL_BALLOON_SWITCH_NONE,
3558 EL_EMC_MAGIC_BALL_SWITCH,
3559 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3564 static int ep_bd_element[] =
3598 static int ep_sp_element[] =
3600 /* should always be valid */
3603 /* standard classic Supaplex elements */
3610 EL_SP_HARDWARE_GRAY,
3618 EL_SP_GRAVITY_PORT_RIGHT,
3619 EL_SP_GRAVITY_PORT_DOWN,
3620 EL_SP_GRAVITY_PORT_LEFT,
3621 EL_SP_GRAVITY_PORT_UP,
3626 EL_SP_PORT_VERTICAL,
3627 EL_SP_PORT_HORIZONTAL,
3633 EL_SP_HARDWARE_BASE_1,
3634 EL_SP_HARDWARE_GREEN,
3635 EL_SP_HARDWARE_BLUE,
3637 EL_SP_HARDWARE_YELLOW,
3638 EL_SP_HARDWARE_BASE_2,
3639 EL_SP_HARDWARE_BASE_3,
3640 EL_SP_HARDWARE_BASE_4,
3641 EL_SP_HARDWARE_BASE_5,
3642 EL_SP_HARDWARE_BASE_6,
3646 /* additional elements that appeared in newer Supaplex levels */
3649 /* additional gravity port elements (not switching, but setting gravity) */
3650 EL_SP_GRAVITY_ON_PORT_LEFT,
3651 EL_SP_GRAVITY_ON_PORT_RIGHT,
3652 EL_SP_GRAVITY_ON_PORT_UP,
3653 EL_SP_GRAVITY_ON_PORT_DOWN,
3654 EL_SP_GRAVITY_OFF_PORT_LEFT,
3655 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3656 EL_SP_GRAVITY_OFF_PORT_UP,
3657 EL_SP_GRAVITY_OFF_PORT_DOWN,
3659 /* more than one Murphy in a level results in an inactive clone */
3662 /* runtime Supaplex elements */
3663 EL_SP_DISK_RED_ACTIVE,
3664 EL_SP_TERMINAL_ACTIVE,
3665 EL_SP_BUGGY_BASE_ACTIVATING,
3666 EL_SP_BUGGY_BASE_ACTIVE,
3673 static int ep_sb_element[] =
3678 EL_SOKOBAN_FIELD_EMPTY,
3679 EL_SOKOBAN_FIELD_FULL,
3680 EL_SOKOBAN_FIELD_PLAYER,
3685 EL_INVISIBLE_STEELWALL,
3690 static int ep_gem[] =
3702 static int ep_food_dark_yamyam[] =
3730 static int ep_food_penguin[] =
3744 static int ep_food_pig[] =
3756 static int ep_historic_wall[] =
3767 EL_GATE_1_GRAY_ACTIVE,
3768 EL_GATE_2_GRAY_ACTIVE,
3769 EL_GATE_3_GRAY_ACTIVE,
3770 EL_GATE_4_GRAY_ACTIVE,
3779 EL_EM_GATE_1_GRAY_ACTIVE,
3780 EL_EM_GATE_2_GRAY_ACTIVE,
3781 EL_EM_GATE_3_GRAY_ACTIVE,
3782 EL_EM_GATE_4_GRAY_ACTIVE,
3789 EL_EXPANDABLE_WALL_HORIZONTAL,
3790 EL_EXPANDABLE_WALL_VERTICAL,
3791 EL_EXPANDABLE_WALL_ANY,
3792 EL_EXPANDABLE_WALL_GROWING,
3793 EL_BD_EXPANDABLE_WALL,
3800 EL_SP_HARDWARE_GRAY,
3801 EL_SP_HARDWARE_GREEN,
3802 EL_SP_HARDWARE_BLUE,
3804 EL_SP_HARDWARE_YELLOW,
3805 EL_SP_HARDWARE_BASE_1,
3806 EL_SP_HARDWARE_BASE_2,
3807 EL_SP_HARDWARE_BASE_3,
3808 EL_SP_HARDWARE_BASE_4,
3809 EL_SP_HARDWARE_BASE_5,
3810 EL_SP_HARDWARE_BASE_6,
3812 EL_SP_TERMINAL_ACTIVE,
3815 EL_INVISIBLE_STEELWALL,
3816 EL_INVISIBLE_STEELWALL_ACTIVE,
3818 EL_INVISIBLE_WALL_ACTIVE,
3819 EL_STEELWALL_SLIPPERY,
3836 static int ep_historic_solid[] =
3840 EL_EXPANDABLE_WALL_HORIZONTAL,
3841 EL_EXPANDABLE_WALL_VERTICAL,
3842 EL_EXPANDABLE_WALL_ANY,
3843 EL_BD_EXPANDABLE_WALL,
3856 EL_QUICKSAND_FILLING,
3857 EL_QUICKSAND_EMPTYING,
3859 EL_MAGIC_WALL_ACTIVE,
3860 EL_MAGIC_WALL_EMPTYING,
3861 EL_MAGIC_WALL_FILLING,
3865 EL_BD_MAGIC_WALL_ACTIVE,
3866 EL_BD_MAGIC_WALL_EMPTYING,
3867 EL_BD_MAGIC_WALL_FULL,
3868 EL_BD_MAGIC_WALL_FILLING,
3869 EL_BD_MAGIC_WALL_DEAD,
3878 EL_SP_TERMINAL_ACTIVE,
3882 EL_INVISIBLE_WALL_ACTIVE,
3883 EL_SWITCHGATE_SWITCH_UP,
3884 EL_SWITCHGATE_SWITCH_DOWN,
3885 EL_DC_SWITCHGATE_SWITCH_UP,
3886 EL_DC_SWITCHGATE_SWITCH_DOWN,
3888 EL_TIMEGATE_SWITCH_ACTIVE,
3889 EL_DC_TIMEGATE_SWITCH,
3890 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3902 /* the following elements are a direct copy of "indestructible" elements,
3903 except "EL_ACID", which is "indestructible", but not "solid"! */
3908 EL_ACID_POOL_TOPLEFT,
3909 EL_ACID_POOL_TOPRIGHT,
3910 EL_ACID_POOL_BOTTOMLEFT,
3911 EL_ACID_POOL_BOTTOM,
3912 EL_ACID_POOL_BOTTOMRIGHT,
3913 EL_SP_HARDWARE_GRAY,
3914 EL_SP_HARDWARE_GREEN,
3915 EL_SP_HARDWARE_BLUE,
3917 EL_SP_HARDWARE_YELLOW,
3918 EL_SP_HARDWARE_BASE_1,
3919 EL_SP_HARDWARE_BASE_2,
3920 EL_SP_HARDWARE_BASE_3,
3921 EL_SP_HARDWARE_BASE_4,
3922 EL_SP_HARDWARE_BASE_5,
3923 EL_SP_HARDWARE_BASE_6,
3924 EL_INVISIBLE_STEELWALL,
3925 EL_INVISIBLE_STEELWALL_ACTIVE,
3926 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3927 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3928 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3929 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3930 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3931 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3932 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3933 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3934 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3935 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3936 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3937 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3939 EL_LIGHT_SWITCH_ACTIVE,
3940 EL_SIGN_EXCLAMATION,
3941 EL_SIGN_RADIOACTIVITY,
3948 EL_SIGN_ENTRY_FORBIDDEN,
3949 EL_SIGN_EMERGENCY_EXIT,
3957 EL_STEEL_EXIT_CLOSED,
3959 EL_DC_STEELWALL_1_LEFT,
3960 EL_DC_STEELWALL_1_RIGHT,
3961 EL_DC_STEELWALL_1_TOP,
3962 EL_DC_STEELWALL_1_BOTTOM,
3963 EL_DC_STEELWALL_1_HORIZONTAL,
3964 EL_DC_STEELWALL_1_VERTICAL,
3965 EL_DC_STEELWALL_1_TOPLEFT,
3966 EL_DC_STEELWALL_1_TOPRIGHT,
3967 EL_DC_STEELWALL_1_BOTTOMLEFT,
3968 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3969 EL_DC_STEELWALL_1_TOPLEFT_2,
3970 EL_DC_STEELWALL_1_TOPRIGHT_2,
3971 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3972 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3973 EL_DC_STEELWALL_2_LEFT,
3974 EL_DC_STEELWALL_2_RIGHT,
3975 EL_DC_STEELWALL_2_TOP,
3976 EL_DC_STEELWALL_2_BOTTOM,
3977 EL_DC_STEELWALL_2_HORIZONTAL,
3978 EL_DC_STEELWALL_2_VERTICAL,
3979 EL_DC_STEELWALL_2_MIDDLE,
3980 EL_DC_STEELWALL_2_SINGLE,
3981 EL_STEELWALL_SLIPPERY,
3995 EL_GATE_1_GRAY_ACTIVE,
3996 EL_GATE_2_GRAY_ACTIVE,
3997 EL_GATE_3_GRAY_ACTIVE,
3998 EL_GATE_4_GRAY_ACTIVE,
4007 EL_EM_GATE_1_GRAY_ACTIVE,
4008 EL_EM_GATE_2_GRAY_ACTIVE,
4009 EL_EM_GATE_3_GRAY_ACTIVE,
4010 EL_EM_GATE_4_GRAY_ACTIVE,
4012 EL_SWITCHGATE_OPENING,
4013 EL_SWITCHGATE_CLOSED,
4014 EL_SWITCHGATE_CLOSING,
4016 EL_TIMEGATE_OPENING,
4018 EL_TIMEGATE_CLOSING,
4022 EL_TUBE_VERTICAL_LEFT,
4023 EL_TUBE_VERTICAL_RIGHT,
4024 EL_TUBE_HORIZONTAL_UP,
4025 EL_TUBE_HORIZONTAL_DOWN,
4034 static int ep_classic_enemy[] =
4051 static int ep_belt[] =
4053 EL_CONVEYOR_BELT_1_LEFT,
4054 EL_CONVEYOR_BELT_1_MIDDLE,
4055 EL_CONVEYOR_BELT_1_RIGHT,
4056 EL_CONVEYOR_BELT_2_LEFT,
4057 EL_CONVEYOR_BELT_2_MIDDLE,
4058 EL_CONVEYOR_BELT_2_RIGHT,
4059 EL_CONVEYOR_BELT_3_LEFT,
4060 EL_CONVEYOR_BELT_3_MIDDLE,
4061 EL_CONVEYOR_BELT_3_RIGHT,
4062 EL_CONVEYOR_BELT_4_LEFT,
4063 EL_CONVEYOR_BELT_4_MIDDLE,
4064 EL_CONVEYOR_BELT_4_RIGHT,
4069 static int ep_belt_active[] =
4071 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
4072 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
4073 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
4074 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
4075 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
4076 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
4077 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
4078 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
4079 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
4080 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
4081 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
4082 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
4087 static int ep_belt_switch[] =
4089 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4090 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4091 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4092 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4093 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4094 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4095 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4096 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4097 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4098 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4099 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4100 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4105 static int ep_tube[] =
4112 EL_TUBE_HORIZONTAL_UP,
4113 EL_TUBE_HORIZONTAL_DOWN,
4115 EL_TUBE_VERTICAL_LEFT,
4116 EL_TUBE_VERTICAL_RIGHT,
4122 static int ep_acid_pool[] =
4124 EL_ACID_POOL_TOPLEFT,
4125 EL_ACID_POOL_TOPRIGHT,
4126 EL_ACID_POOL_BOTTOMLEFT,
4127 EL_ACID_POOL_BOTTOM,
4128 EL_ACID_POOL_BOTTOMRIGHT,
4133 static int ep_keygate[] =
4143 EL_GATE_1_GRAY_ACTIVE,
4144 EL_GATE_2_GRAY_ACTIVE,
4145 EL_GATE_3_GRAY_ACTIVE,
4146 EL_GATE_4_GRAY_ACTIVE,
4155 EL_EM_GATE_1_GRAY_ACTIVE,
4156 EL_EM_GATE_2_GRAY_ACTIVE,
4157 EL_EM_GATE_3_GRAY_ACTIVE,
4158 EL_EM_GATE_4_GRAY_ACTIVE,
4167 EL_EMC_GATE_5_GRAY_ACTIVE,
4168 EL_EMC_GATE_6_GRAY_ACTIVE,
4169 EL_EMC_GATE_7_GRAY_ACTIVE,
4170 EL_EMC_GATE_8_GRAY_ACTIVE,
4172 EL_DC_GATE_WHITE_GRAY,
4173 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4178 static int ep_amoeboid[] =
4190 static int ep_amoebalive[] =
4201 static int ep_has_editor_content[] =
4207 EL_SOKOBAN_FIELD_PLAYER,
4224 static int ep_can_turn_each_move[] =
4226 /* !!! do something with this one !!! */
4230 static int ep_can_grow[] =
4244 static int ep_active_bomb[] =
4247 EL_EM_DYNAMITE_ACTIVE,
4248 EL_DYNABOMB_PLAYER_1_ACTIVE,
4249 EL_DYNABOMB_PLAYER_2_ACTIVE,
4250 EL_DYNABOMB_PLAYER_3_ACTIVE,
4251 EL_DYNABOMB_PLAYER_4_ACTIVE,
4252 EL_SP_DISK_RED_ACTIVE,
4257 static int ep_inactive[] =
4267 EL_QUICKSAND_FAST_EMPTY,
4290 EL_GATE_1_GRAY_ACTIVE,
4291 EL_GATE_2_GRAY_ACTIVE,
4292 EL_GATE_3_GRAY_ACTIVE,
4293 EL_GATE_4_GRAY_ACTIVE,
4302 EL_EM_GATE_1_GRAY_ACTIVE,
4303 EL_EM_GATE_2_GRAY_ACTIVE,
4304 EL_EM_GATE_3_GRAY_ACTIVE,
4305 EL_EM_GATE_4_GRAY_ACTIVE,
4314 EL_EMC_GATE_5_GRAY_ACTIVE,
4315 EL_EMC_GATE_6_GRAY_ACTIVE,
4316 EL_EMC_GATE_7_GRAY_ACTIVE,
4317 EL_EMC_GATE_8_GRAY_ACTIVE,
4319 EL_DC_GATE_WHITE_GRAY,
4320 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4321 EL_DC_GATE_FAKE_GRAY,
4324 EL_INVISIBLE_STEELWALL,
4332 EL_WALL_EMERALD_YELLOW,
4333 EL_DYNABOMB_INCREASE_NUMBER,
4334 EL_DYNABOMB_INCREASE_SIZE,
4335 EL_DYNABOMB_INCREASE_POWER,
4339 EL_SOKOBAN_FIELD_EMPTY,
4340 EL_SOKOBAN_FIELD_FULL,
4341 EL_WALL_EMERALD_RED,
4342 EL_WALL_EMERALD_PURPLE,
4343 EL_ACID_POOL_TOPLEFT,
4344 EL_ACID_POOL_TOPRIGHT,
4345 EL_ACID_POOL_BOTTOMLEFT,
4346 EL_ACID_POOL_BOTTOM,
4347 EL_ACID_POOL_BOTTOMRIGHT,
4351 EL_BD_MAGIC_WALL_DEAD,
4353 EL_DC_MAGIC_WALL_DEAD,
4354 EL_AMOEBA_TO_DIAMOND,
4362 EL_SP_GRAVITY_PORT_RIGHT,
4363 EL_SP_GRAVITY_PORT_DOWN,
4364 EL_SP_GRAVITY_PORT_LEFT,
4365 EL_SP_GRAVITY_PORT_UP,
4366 EL_SP_PORT_HORIZONTAL,
4367 EL_SP_PORT_VERTICAL,
4378 EL_SP_HARDWARE_GRAY,
4379 EL_SP_HARDWARE_GREEN,
4380 EL_SP_HARDWARE_BLUE,
4382 EL_SP_HARDWARE_YELLOW,
4383 EL_SP_HARDWARE_BASE_1,
4384 EL_SP_HARDWARE_BASE_2,
4385 EL_SP_HARDWARE_BASE_3,
4386 EL_SP_HARDWARE_BASE_4,
4387 EL_SP_HARDWARE_BASE_5,
4388 EL_SP_HARDWARE_BASE_6,
4389 EL_SP_GRAVITY_ON_PORT_LEFT,
4390 EL_SP_GRAVITY_ON_PORT_RIGHT,
4391 EL_SP_GRAVITY_ON_PORT_UP,
4392 EL_SP_GRAVITY_ON_PORT_DOWN,
4393 EL_SP_GRAVITY_OFF_PORT_LEFT,
4394 EL_SP_GRAVITY_OFF_PORT_RIGHT,
4395 EL_SP_GRAVITY_OFF_PORT_UP,
4396 EL_SP_GRAVITY_OFF_PORT_DOWN,
4397 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4398 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4399 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4400 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4401 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4402 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4403 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4404 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4405 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4406 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4407 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4408 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4409 EL_SIGN_EXCLAMATION,
4410 EL_SIGN_RADIOACTIVITY,
4417 EL_SIGN_ENTRY_FORBIDDEN,
4418 EL_SIGN_EMERGENCY_EXIT,
4426 EL_DC_STEELWALL_1_LEFT,
4427 EL_DC_STEELWALL_1_RIGHT,
4428 EL_DC_STEELWALL_1_TOP,
4429 EL_DC_STEELWALL_1_BOTTOM,
4430 EL_DC_STEELWALL_1_HORIZONTAL,
4431 EL_DC_STEELWALL_1_VERTICAL,
4432 EL_DC_STEELWALL_1_TOPLEFT,
4433 EL_DC_STEELWALL_1_TOPRIGHT,
4434 EL_DC_STEELWALL_1_BOTTOMLEFT,
4435 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4436 EL_DC_STEELWALL_1_TOPLEFT_2,
4437 EL_DC_STEELWALL_1_TOPRIGHT_2,
4438 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4439 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4440 EL_DC_STEELWALL_2_LEFT,
4441 EL_DC_STEELWALL_2_RIGHT,
4442 EL_DC_STEELWALL_2_TOP,
4443 EL_DC_STEELWALL_2_BOTTOM,
4444 EL_DC_STEELWALL_2_HORIZONTAL,
4445 EL_DC_STEELWALL_2_VERTICAL,
4446 EL_DC_STEELWALL_2_MIDDLE,
4447 EL_DC_STEELWALL_2_SINGLE,
4448 EL_STEELWALL_SLIPPERY,
4453 EL_EMC_WALL_SLIPPERY_1,
4454 EL_EMC_WALL_SLIPPERY_2,
4455 EL_EMC_WALL_SLIPPERY_3,
4456 EL_EMC_WALL_SLIPPERY_4,
4477 static int ep_em_slippery_wall[] =
4482 static int ep_gfx_crumbled[] =
4493 static int ep_editor_cascade_active[] =
4495 EL_INTERNAL_CASCADE_BD_ACTIVE,
4496 EL_INTERNAL_CASCADE_EM_ACTIVE,
4497 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4498 EL_INTERNAL_CASCADE_RND_ACTIVE,
4499 EL_INTERNAL_CASCADE_SB_ACTIVE,
4500 EL_INTERNAL_CASCADE_SP_ACTIVE,
4501 EL_INTERNAL_CASCADE_DC_ACTIVE,
4502 EL_INTERNAL_CASCADE_DX_ACTIVE,
4503 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4504 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4505 EL_INTERNAL_CASCADE_CE_ACTIVE,
4506 EL_INTERNAL_CASCADE_GE_ACTIVE,
4507 EL_INTERNAL_CASCADE_REF_ACTIVE,
4508 EL_INTERNAL_CASCADE_USER_ACTIVE,
4509 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4514 static int ep_editor_cascade_inactive[] =
4516 EL_INTERNAL_CASCADE_BD,
4517 EL_INTERNAL_CASCADE_EM,
4518 EL_INTERNAL_CASCADE_EMC,
4519 EL_INTERNAL_CASCADE_RND,
4520 EL_INTERNAL_CASCADE_SB,
4521 EL_INTERNAL_CASCADE_SP,
4522 EL_INTERNAL_CASCADE_DC,
4523 EL_INTERNAL_CASCADE_DX,
4524 EL_INTERNAL_CASCADE_CHARS,
4525 EL_INTERNAL_CASCADE_STEEL_CHARS,
4526 EL_INTERNAL_CASCADE_CE,
4527 EL_INTERNAL_CASCADE_GE,
4528 EL_INTERNAL_CASCADE_REF,
4529 EL_INTERNAL_CASCADE_USER,
4530 EL_INTERNAL_CASCADE_DYNAMIC,
4535 static int ep_obsolete[] =
4539 EL_EM_KEY_1_FILE_OBSOLETE,
4540 EL_EM_KEY_2_FILE_OBSOLETE,
4541 EL_EM_KEY_3_FILE_OBSOLETE,
4542 EL_EM_KEY_4_FILE_OBSOLETE,
4543 EL_ENVELOPE_OBSOLETE,
4552 } element_properties[] =
4554 { ep_diggable, EP_DIGGABLE },
4555 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4556 { ep_dont_run_into, EP_DONT_RUN_INTO },
4557 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4558 { ep_dont_touch, EP_DONT_TOUCH },
4559 { ep_indestructible, EP_INDESTRUCTIBLE },
4560 { ep_slippery, EP_SLIPPERY },
4561 { ep_can_change, EP_CAN_CHANGE },
4562 { ep_can_move, EP_CAN_MOVE },
4563 { ep_can_fall, EP_CAN_FALL },
4564 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4565 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4566 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4567 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4568 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4569 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4570 { ep_walkable_over, EP_WALKABLE_OVER },
4571 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4572 { ep_walkable_under, EP_WALKABLE_UNDER },
4573 { ep_passable_over, EP_PASSABLE_OVER },
4574 { ep_passable_inside, EP_PASSABLE_INSIDE },
4575 { ep_passable_under, EP_PASSABLE_UNDER },
4576 { ep_droppable, EP_DROPPABLE },
4577 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4578 { ep_pushable, EP_PUSHABLE },
4579 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4580 { ep_protected, EP_PROTECTED },
4581 { ep_throwable, EP_THROWABLE },
4582 { ep_can_explode, EP_CAN_EXPLODE },
4583 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4585 { ep_player, EP_PLAYER },
4586 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4587 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4588 { ep_switchable, EP_SWITCHABLE },
4589 { ep_bd_element, EP_BD_ELEMENT },
4590 { ep_sp_element, EP_SP_ELEMENT },
4591 { ep_sb_element, EP_SB_ELEMENT },
4593 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4594 { ep_food_penguin, EP_FOOD_PENGUIN },
4595 { ep_food_pig, EP_FOOD_PIG },
4596 { ep_historic_wall, EP_HISTORIC_WALL },
4597 { ep_historic_solid, EP_HISTORIC_SOLID },
4598 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4599 { ep_belt, EP_BELT },
4600 { ep_belt_active, EP_BELT_ACTIVE },
4601 { ep_belt_switch, EP_BELT_SWITCH },
4602 { ep_tube, EP_TUBE },
4603 { ep_acid_pool, EP_ACID_POOL },
4604 { ep_keygate, EP_KEYGATE },
4605 { ep_amoeboid, EP_AMOEBOID },
4606 { ep_amoebalive, EP_AMOEBALIVE },
4607 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4608 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4609 { ep_can_grow, EP_CAN_GROW },
4610 { ep_active_bomb, EP_ACTIVE_BOMB },
4611 { ep_inactive, EP_INACTIVE },
4613 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4615 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4617 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4618 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4620 { ep_obsolete, EP_OBSOLETE },
4627 /* always start with reliable default values (element has no properties) */
4628 /* (but never initialize clipboard elements after the very first time) */
4629 /* (to be able to use clipboard elements between several levels) */
4630 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4631 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4632 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4633 SET_PROPERTY(i, j, FALSE);
4635 /* set all base element properties from above array definitions */
4636 for (i = 0; element_properties[i].elements != NULL; i++)
4637 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4638 SET_PROPERTY((element_properties[i].elements)[j],
4639 element_properties[i].property, TRUE);
4641 /* copy properties to some elements that are only stored in level file */
4642 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4643 for (j = 0; copy_properties[j][0] != -1; j++)
4644 if (HAS_PROPERTY(copy_properties[j][0], i))
4645 for (k = 1; k <= 4; k++)
4646 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4648 /* set static element properties that are not listed in array definitions */
4649 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4650 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4652 clipboard_elements_initialized = TRUE;
4655 void InitElementPropertiesEngine(int engine_version)
4657 static int no_wall_properties[] =
4660 EP_COLLECTIBLE_ONLY,
4662 EP_DONT_COLLIDE_WITH,
4665 EP_CAN_SMASH_PLAYER,
4666 EP_CAN_SMASH_ENEMIES,
4667 EP_CAN_SMASH_EVERYTHING,
4672 EP_FOOD_DARK_YAMYAM,
4688 /* important: after initialization in InitElementPropertiesStatic(), the
4689 elements are not again initialized to a default value; therefore all
4690 changes have to make sure that they leave the element with a defined
4691 property (which means that conditional property changes must be set to
4692 a reliable default value before) */
4694 /* resolve group elements */
4695 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4696 ResolveGroupElement(EL_GROUP_START + i);
4698 /* set all special, combined or engine dependent element properties */
4699 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4701 /* do not change (already initialized) clipboard elements here */
4702 if (IS_CLIPBOARD_ELEMENT(i))
4705 /* ---------- INACTIVE ------------------------------------------------- */
4706 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4707 i <= EL_CHAR_END) ||
4708 (i >= EL_STEEL_CHAR_START &&
4709 i <= EL_STEEL_CHAR_END)));
4711 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4712 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4713 IS_WALKABLE_INSIDE(i) ||
4714 IS_WALKABLE_UNDER(i)));
4716 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4717 IS_PASSABLE_INSIDE(i) ||
4718 IS_PASSABLE_UNDER(i)));
4720 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4721 IS_PASSABLE_OVER(i)));
4723 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4724 IS_PASSABLE_INSIDE(i)));
4726 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4727 IS_PASSABLE_UNDER(i)));
4729 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4732 /* ---------- COLLECTIBLE ---------------------------------------------- */
4733 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4737 /* ---------- SNAPPABLE ------------------------------------------------ */
4738 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4739 IS_COLLECTIBLE(i) ||
4743 /* ---------- WALL ----------------------------------------------------- */
4744 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4746 for (j = 0; no_wall_properties[j] != -1; j++)
4747 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4748 i >= EL_FIRST_RUNTIME_UNREAL)
4749 SET_PROPERTY(i, EP_WALL, FALSE);
4751 if (IS_HISTORIC_WALL(i))
4752 SET_PROPERTY(i, EP_WALL, TRUE);
4754 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4755 if (engine_version < VERSION_IDENT(2,2,0,0))
4756 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4758 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4760 !IS_COLLECTIBLE(i)));
4762 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4763 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4764 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4766 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4767 IS_INDESTRUCTIBLE(i)));
4769 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4771 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4772 else if (engine_version < VERSION_IDENT(2,2,0,0))
4773 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4775 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4779 if (IS_CUSTOM_ELEMENT(i))
4781 /* these are additional properties which are initially false when set */
4783 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4785 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4786 if (DONT_COLLIDE_WITH(i))
4787 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4789 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4790 if (CAN_SMASH_EVERYTHING(i))
4791 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4792 if (CAN_SMASH_ENEMIES(i))
4793 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4796 /* ---------- CAN_SMASH ------------------------------------------------ */
4797 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4798 CAN_SMASH_ENEMIES(i) ||
4799 CAN_SMASH_EVERYTHING(i)));
4801 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4802 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4803 EXPLODES_BY_FIRE(i)));
4805 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4806 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4807 EXPLODES_SMASHED(i)));
4809 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4810 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4811 EXPLODES_IMPACT(i)));
4813 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4814 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4816 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4817 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4818 i == EL_BLACK_ORB));
4820 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4821 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4823 IS_CUSTOM_ELEMENT(i)));
4825 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4826 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4827 i == EL_SP_ELECTRON));
4829 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4830 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4831 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4832 getMoveIntoAcidProperty(&level, i));
4834 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4835 if (MAYBE_DONT_COLLIDE_WITH(i))
4836 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4837 getDontCollideWithProperty(&level, i));
4839 /* ---------- SP_PORT -------------------------------------------------- */
4840 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4841 IS_PASSABLE_INSIDE(i)));
4843 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4844 for (j = 0; j < level.num_android_clone_elements; j++)
4845 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4847 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4849 /* ---------- CAN_CHANGE ----------------------------------------------- */
4850 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4851 for (j = 0; j < element_info[i].num_change_pages; j++)
4852 if (element_info[i].change_page[j].can_change)
4853 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4855 /* ---------- HAS_ACTION ----------------------------------------------- */
4856 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4857 for (j = 0; j < element_info[i].num_change_pages; j++)
4858 if (element_info[i].change_page[j].has_action)
4859 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4861 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4862 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4865 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4867 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4868 element_info[i].crumbled[ACTION_DEFAULT] !=
4869 element_info[i].graphic[ACTION_DEFAULT]);
4871 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
4872 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4873 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
4876 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4877 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4878 IS_EDITOR_CASCADE_INACTIVE(i)));
4881 /* dynamically adjust element properties according to game engine version */
4883 static int ep_em_slippery_wall[] =
4888 EL_EXPANDABLE_WALL_HORIZONTAL,
4889 EL_EXPANDABLE_WALL_VERTICAL,
4890 EL_EXPANDABLE_WALL_ANY,
4891 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4892 EL_EXPANDABLE_STEELWALL_VERTICAL,
4893 EL_EXPANDABLE_STEELWALL_ANY,
4894 EL_EXPANDABLE_STEELWALL_GROWING,
4898 static int ep_em_explodes_by_fire[] =
4901 EL_EM_DYNAMITE_ACTIVE,
4906 /* special EM style gems behaviour */
4907 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4908 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4909 level.em_slippery_gems);
4911 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4912 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4913 (level.em_slippery_gems &&
4914 engine_version > VERSION_IDENT(2,0,1,0)));
4916 /* special EM style explosion behaviour regarding chain reactions */
4917 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4918 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4919 level.em_explodes_by_fire);
4922 /* this is needed because some graphics depend on element properties */
4923 if (game_status == GAME_MODE_PLAYING)
4924 InitElementGraphicInfo();
4927 void InitElementPropertiesAfterLoading(int engine_version)
4931 /* set some other uninitialized values of custom elements in older levels */
4932 if (engine_version < VERSION_IDENT(3,1,0,0))
4934 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4936 int element = EL_CUSTOM_START + i;
4938 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4940 element_info[element].explosion_delay = 17;
4941 element_info[element].ignition_delay = 8;
4946 void InitElementPropertiesGfxElement()
4950 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4952 struct ElementInfo *ei = &element_info[i];
4954 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4958 static void InitGlobal()
4963 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4965 /* check if element_name_info entry defined for each element in "main.h" */
4966 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4967 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4969 element_info[i].token_name = element_name_info[i].token_name;
4970 element_info[i].class_name = element_name_info[i].class_name;
4971 element_info[i].editor_description= element_name_info[i].editor_description;
4974 printf("%04d: %s\n", i, element_name_info[i].token_name);
4978 /* create hash from image config list */
4979 image_config_hash = newSetupFileHash();
4980 for (i = 0; image_config[i].token != NULL; i++)
4981 setHashEntry(image_config_hash,
4982 image_config[i].token,
4983 image_config[i].value);
4985 /* create hash from element token list */
4986 element_token_hash = newSetupFileHash();
4987 for (i = 0; element_name_info[i].token_name != NULL; i++)
4988 setHashEntry(element_token_hash,
4989 element_name_info[i].token_name,
4992 /* create hash from graphic token list */
4993 graphic_token_hash = newSetupFileHash();
4994 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4995 if (strSuffix(image_config[i].value, ".png") ||
4996 strSuffix(image_config[i].value, ".pcx") ||
4997 strSuffix(image_config[i].value, ".wav") ||
4998 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4999 setHashEntry(graphic_token_hash,
5000 image_config[i].token,
5001 int2str(graphic++, 0));
5003 /* create hash from font token list */
5004 font_token_hash = newSetupFileHash();
5005 for (i = 0; font_info[i].token_name != NULL; i++)
5006 setHashEntry(font_token_hash,
5007 font_info[i].token_name,
5010 /* always start with reliable default values (all elements) */
5011 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5012 ActiveElement[i] = i;
5014 /* now add all entries that have an active state (active elements) */
5015 for (i = 0; element_with_active_state[i].element != -1; i++)
5017 int element = element_with_active_state[i].element;
5018 int element_active = element_with_active_state[i].element_active;
5020 ActiveElement[element] = element_active;
5023 /* always start with reliable default values (all buttons) */
5024 for (i = 0; i < NUM_IMAGE_FILES; i++)
5025 ActiveButton[i] = i;
5027 /* now add all entries that have an active state (active buttons) */
5028 for (i = 0; button_with_active_state[i].button != -1; i++)
5030 int button = button_with_active_state[i].button;
5031 int button_active = button_with_active_state[i].button_active;
5033 ActiveButton[button] = button_active;
5036 /* always start with reliable default values (all fonts) */
5037 for (i = 0; i < NUM_FONTS; i++)
5040 /* now add all entries that have an active state (active fonts) */
5041 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
5043 int font = font_with_active_state[i].font_nr;
5044 int font_active = font_with_active_state[i].font_nr_active;
5046 ActiveFont[font] = font_active;
5049 global.autoplay_leveldir = NULL;
5050 global.convert_leveldir = NULL;
5051 global.create_images_dir = NULL;
5053 global.frames_per_second = 0;
5054 global.fps_slowdown = FALSE;
5055 global.fps_slowdown_factor = 1;
5057 global.border_status = GAME_MODE_MAIN;
5059 global.fading_status = GAME_MODE_MAIN;
5060 global.fading_type = TYPE_ENTER_MENU;
5063 global.use_envelope_request = FALSE;
5066 void Execute_Command(char *command)
5070 if (strEqual(command, "print graphicsinfo.conf"))
5072 printf("# You can configure additional/alternative image files here.\n");
5073 printf("# (The entries below are default and therefore commented out.)\n");
5075 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
5077 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5080 for (i = 0; image_config[i].token != NULL; i++)
5081 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
5082 image_config[i].value));
5086 else if (strEqual(command, "print soundsinfo.conf"))
5088 printf("# You can configure additional/alternative sound files here.\n");
5089 printf("# (The entries below are default and therefore commented out.)\n");
5091 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
5093 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5096 for (i = 0; sound_config[i].token != NULL; i++)
5097 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
5098 sound_config[i].value));
5102 else if (strEqual(command, "print musicinfo.conf"))
5104 printf("# You can configure additional/alternative music files here.\n");
5105 printf("# (The entries below are default and therefore commented out.)\n");
5107 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
5109 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5112 for (i = 0; music_config[i].token != NULL; i++)
5113 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
5114 music_config[i].value));
5118 else if (strEqual(command, "print editorsetup.conf"))
5120 printf("# You can configure your personal editor element list here.\n");
5121 printf("# (The entries below are default and therefore commented out.)\n");
5124 /* this is needed to be able to check element list for cascade elements */
5125 InitElementPropertiesStatic();
5126 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5128 PrintEditorElementList();
5132 else if (strEqual(command, "print helpanim.conf"))
5134 printf("# You can configure different element help animations here.\n");
5135 printf("# (The entries below are default and therefore commented out.)\n");
5138 for (i = 0; helpanim_config[i].token != NULL; i++)
5140 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
5141 helpanim_config[i].value));
5143 if (strEqual(helpanim_config[i].token, "end"))
5149 else if (strEqual(command, "print helptext.conf"))
5151 printf("# You can configure different element help text here.\n");
5152 printf("# (The entries below are default and therefore commented out.)\n");
5155 for (i = 0; helptext_config[i].token != NULL; i++)
5156 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
5157 helptext_config[i].value));
5161 else if (strPrefix(command, "dump level "))
5163 char *filename = &command[11];
5165 if (!fileExists(filename))
5166 Error(ERR_EXIT, "cannot open file '%s'", filename);
5168 LoadLevelFromFilename(&level, filename);
5173 else if (strPrefix(command, "dump tape "))
5175 char *filename = &command[10];
5177 if (!fileExists(filename))
5178 Error(ERR_EXIT, "cannot open file '%s'", filename);
5180 LoadTapeFromFilename(filename);
5185 else if (strPrefix(command, "autoplay "))
5187 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
5189 while (*str_ptr != '\0') /* continue parsing string */
5191 /* cut leading whitespace from string, replace it by string terminator */
5192 while (*str_ptr == ' ' || *str_ptr == '\t')
5195 if (*str_ptr == '\0') /* end of string reached */
5198 if (global.autoplay_leveldir == NULL) /* read level set string */
5200 global.autoplay_leveldir = str_ptr;
5201 global.autoplay_all = TRUE; /* default: play all tapes */
5203 for (i = 0; i < MAX_TAPES_PER_SET; i++)
5204 global.autoplay_level[i] = FALSE;
5206 else /* read level number string */
5208 int level_nr = atoi(str_ptr); /* get level_nr value */
5210 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5211 global.autoplay_level[level_nr] = TRUE;
5213 global.autoplay_all = FALSE;
5216 /* advance string pointer to the next whitespace (or end of string) */
5217 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5221 else if (strPrefix(command, "convert "))
5223 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
5224 char *str_ptr = strchr(str_copy, ' ');
5226 global.convert_leveldir = str_copy;
5227 global.convert_level_nr = -1;
5229 if (str_ptr != NULL) /* level number follows */
5231 *str_ptr++ = '\0'; /* terminate leveldir string */
5232 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
5235 else if (strPrefix(command, "create images "))
5237 global.create_images_dir = getStringCopy(&command[14]);
5239 if (access(global.create_images_dir, W_OK) != 0)
5240 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
5241 global.create_images_dir);
5245 #if defined(TARGET_SDL2)
5246 else if (strEqual(command, "SDL_ListModes"))
5248 SDL_Init(SDL_INIT_VIDEO);
5250 int num_displays = SDL_GetNumVideoDisplays();
5252 // check if there are any displays available
5253 if (num_displays < 0)
5255 printf("No displays available: %s\n", SDL_GetError());
5260 for (i = 0; i < num_displays; i++)
5262 int num_modes = SDL_GetNumDisplayModes(i);
5265 printf("Available display modes for display %d:\n", i);
5267 // check if there are any display modes available for this display
5270 printf("No display modes available for display %d: %s\n",
5276 for (j = 0; j < num_modes; j++)
5278 SDL_DisplayMode mode;
5280 if (SDL_GetDisplayMode(i, j, &mode) < 0)
5282 printf("Cannot get display mode %d for display %d: %s\n",
5283 j, i, SDL_GetError());
5288 printf("- %d x %d\n", mode.w, mode.h);
5294 #elif defined(TARGET_SDL)
5295 else if (strEqual(command, "SDL_ListModes"))
5300 SDL_Init(SDL_INIT_VIDEO);
5302 /* get available fullscreen/hardware modes */
5303 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
5305 /* check if there are any modes available */
5308 printf("No modes available!\n");
5313 /* check if our resolution is restricted */
5314 if (modes == (SDL_Rect **)-1)
5316 printf("All resolutions available.\n");
5320 printf("Available display modes:\n");
5322 for (i = 0; modes[i]; i++)
5323 printf("- %d x %d\n", modes[i]->w, modes[i]->h);
5333 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
5337 static void InitSetup()
5339 LoadSetup(); /* global setup info */
5341 /* set some options from setup file */
5343 if (setup.options.verbose)
5344 options.verbose = TRUE;
5347 static void InitGameInfo()
5349 game.restart_level = FALSE;
5352 static void InitPlayerInfo()
5356 /* choose default local player */
5357 local_player = &stored_player[0];
5359 for (i = 0; i < MAX_PLAYERS; i++)
5360 stored_player[i].connected = FALSE;
5362 local_player->connected = TRUE;
5365 static void InitArtworkInfo()
5370 static char *get_string_in_brackets(char *string)
5372 char *string_in_brackets = checked_malloc(strlen(string) + 3);
5374 sprintf(string_in_brackets, "[%s]", string);
5376 return string_in_brackets;
5379 static char *get_level_id_suffix(int id_nr)
5381 char *id_suffix = checked_malloc(1 + 3 + 1);
5383 if (id_nr < 0 || id_nr > 999)
5386 sprintf(id_suffix, ".%03d", id_nr);
5392 static char *get_element_class_token(int element)
5394 char *element_class_name = element_info[element].class_name;
5395 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
5397 sprintf(element_class_token, "[%s]", element_class_name);
5399 return element_class_token;
5402 static char *get_action_class_token(int action)
5404 char *action_class_name = &element_action_info[action].suffix[1];
5405 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
5407 sprintf(action_class_token, "[%s]", action_class_name);
5409 return action_class_token;
5413 static void InitArtworkConfig()
5415 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
5416 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
5417 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
5418 static char *action_id_suffix[NUM_ACTIONS + 1];
5419 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5420 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5421 static char *level_id_suffix[MAX_LEVELS + 1];
5422 static char *dummy[1] = { NULL };
5423 static char *ignore_generic_tokens[] =
5429 static char **ignore_image_tokens;
5430 static char **ignore_sound_tokens;
5431 static char **ignore_music_tokens;
5432 int num_ignore_generic_tokens;
5433 int num_ignore_image_tokens;
5434 int num_ignore_sound_tokens;
5435 int num_ignore_music_tokens;
5438 /* dynamically determine list of generic tokens to be ignored */
5439 num_ignore_generic_tokens = 0;
5440 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5441 num_ignore_generic_tokens++;
5443 /* dynamically determine list of image tokens to be ignored */
5444 num_ignore_image_tokens = num_ignore_generic_tokens;
5445 for (i = 0; image_config_vars[i].token != NULL; i++)
5446 num_ignore_image_tokens++;
5447 ignore_image_tokens =
5448 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5449 for (i = 0; i < num_ignore_generic_tokens; i++)
5450 ignore_image_tokens[i] = ignore_generic_tokens[i];
5451 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5452 ignore_image_tokens[num_ignore_generic_tokens + i] =
5453 image_config_vars[i].token;
5454 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5456 /* dynamically determine list of sound tokens to be ignored */
5457 num_ignore_sound_tokens = num_ignore_generic_tokens;
5458 ignore_sound_tokens =
5459 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5460 for (i = 0; i < num_ignore_generic_tokens; i++)
5461 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5462 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5464 /* dynamically determine list of music tokens to be ignored */
5465 num_ignore_music_tokens = num_ignore_generic_tokens;
5466 ignore_music_tokens =
5467 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5468 for (i = 0; i < num_ignore_generic_tokens; i++)
5469 ignore_music_tokens[i] = ignore_generic_tokens[i];
5470 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5472 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5473 image_id_prefix[i] = element_info[i].token_name;
5474 for (i = 0; i < NUM_FONTS; i++)
5475 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5476 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
5478 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5479 sound_id_prefix[i] = element_info[i].token_name;
5480 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5481 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5482 get_string_in_brackets(element_info[i].class_name);
5483 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
5485 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5486 music_id_prefix[i] = music_prefix_info[i].prefix;
5487 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
5489 for (i = 0; i < NUM_ACTIONS; i++)
5490 action_id_suffix[i] = element_action_info[i].suffix;
5491 action_id_suffix[NUM_ACTIONS] = NULL;
5493 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5494 direction_id_suffix[i] = element_direction_info[i].suffix;
5495 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5497 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5498 special_id_suffix[i] = special_suffix_info[i].suffix;
5499 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5501 for (i = 0; i < MAX_LEVELS; i++)
5502 level_id_suffix[i] = get_level_id_suffix(i);
5503 level_id_suffix[MAX_LEVELS] = NULL;
5505 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5506 image_id_prefix, action_id_suffix, direction_id_suffix,
5507 special_id_suffix, ignore_image_tokens);
5508 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5509 sound_id_prefix, action_id_suffix, dummy,
5510 special_id_suffix, ignore_sound_tokens);
5511 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5512 music_id_prefix, special_id_suffix, level_id_suffix,
5513 dummy, ignore_music_tokens);
5516 static void InitMixer()
5523 void InitGfxBuffers()
5525 /* create additional image buffers for double-buffering and cross-fading */
5526 ReCreateBitmap(&bitmap_db_store, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5527 ReCreateBitmap(&bitmap_db_cross, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5528 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE, DEFAULT_DEPTH);
5529 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE, DEFAULT_DEPTH);
5531 ReCreateBitmap(&bitmap_db_door, 3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
5533 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE, DEFAULT_DEPTH);
5534 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE, DEFAULT_DEPTH);
5535 ReCreateBitmap(&bitmap_db_toons, FULL_SXSIZE, FULL_SYSIZE, DEFAULT_DEPTH);
5537 /* initialize screen properties */
5538 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5539 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5541 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5542 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5543 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5544 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5545 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5546 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5548 InitGfxBuffers_EM();
5549 InitGfxBuffers_SP();
5554 struct GraphicInfo *graphic_info_last = graphic_info;
5555 char *filename_font_initial = NULL;
5556 char *filename_anim_initial = NULL;
5557 Bitmap *bitmap_font_initial = NULL;
5561 /* determine settings for initial font (for displaying startup messages) */
5562 for (i = 0; image_config[i].token != NULL; i++)
5564 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5566 char font_token[128];
5569 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5570 len_font_token = strlen(font_token);
5572 if (strEqual(image_config[i].token, font_token))
5573 filename_font_initial = image_config[i].value;
5574 else if (strlen(image_config[i].token) > len_font_token &&
5575 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5577 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5578 font_initial[j].src_x = atoi(image_config[i].value);
5579 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5580 font_initial[j].src_y = atoi(image_config[i].value);
5581 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5582 font_initial[j].width = atoi(image_config[i].value);
5583 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5584 font_initial[j].height = atoi(image_config[i].value);
5589 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5591 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5592 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5595 if (filename_font_initial == NULL) /* should not happen */
5596 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5599 InitGfxCustomArtworkInfo();
5601 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5603 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5604 font_initial[j].bitmap = bitmap_font_initial;
5606 InitFontGraphicInfo();
5608 font_height = getFontHeight(FC_RED);
5611 DrawInitTextAlways(getWindowTitleString(), 20, FC_YELLOW);
5613 DrawInitTextAlways(getProgramInitString(), 20, FC_YELLOW);
5615 DrawInitTextAlways(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
5616 DrawInitTextAlways(PROGRAM_WEBSITE_STRING, WIN_YSIZE - 20 - font_height,
5619 DrawInitTextAlways("Loading graphics", 120, FC_GREEN);
5623 /* initialize busy animation with default values */
5624 int parameter[NUM_GFX_ARGS];
5625 for (i = 0; i < NUM_GFX_ARGS; i++)
5626 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5627 image_config_suffix[i].token,
5628 image_config_suffix[i].type);
5630 for (i = 0; i < NUM_GFX_ARGS; i++)
5631 printf("::: '%s' => %d\n", image_config_suffix[i].token, parameter[i]);
5635 /* determine settings for busy animation (when displaying startup messages) */
5636 for (i = 0; image_config[i].token != NULL; i++)
5638 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5639 int len_anim_token = strlen(anim_token);
5641 if (strEqual(image_config[i].token, anim_token))
5642 filename_anim_initial = image_config[i].value;
5643 else if (strlen(image_config[i].token) > len_anim_token &&
5644 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5647 for (j = 0; image_config_suffix[j].token != NULL; j++)
5649 if (strEqual(&image_config[i].token[len_anim_token],
5650 image_config_suffix[j].token))
5652 get_graphic_parameter_value(image_config[i].value,
5653 image_config_suffix[j].token,
5654 image_config_suffix[j].type);
5657 if (strEqual(&image_config[i].token[len_anim_token], ".x"))
5658 anim_initial.src_x = atoi(image_config[i].value);
5659 else if (strEqual(&image_config[i].token[len_anim_token], ".y"))
5660 anim_initial.src_y = atoi(image_config[i].value);
5661 else if (strEqual(&image_config[i].token[len_anim_token], ".width"))
5662 anim_initial.width = atoi(image_config[i].value);
5663 else if (strEqual(&image_config[i].token[len_anim_token], ".height"))
5664 anim_initial.height = atoi(image_config[i].value);
5665 else if (strEqual(&image_config[i].token[len_anim_token], ".frames"))
5666 anim_initial.anim_frames = atoi(image_config[i].value);
5667 else if (strEqual(&image_config[i].token[len_anim_token],
5668 ".frames_per_line"))
5669 anim_initial.anim_frames_per_line = atoi(image_config[i].value);
5670 else if (strEqual(&image_config[i].token[len_anim_token], ".delay"))
5671 anim_initial.anim_delay = atoi(image_config[i].value);
5676 #if defined(CREATE_SPECIAL_EDITION_RND_JUE)
5677 filename_anim_initial = "loading.pcx";
5679 parameter[GFX_ARG_X] = 0;
5680 parameter[GFX_ARG_Y] = 0;
5681 parameter[GFX_ARG_WIDTH] = 128;
5682 parameter[GFX_ARG_HEIGHT] = 40;
5683 parameter[GFX_ARG_FRAMES] = 32;
5684 parameter[GFX_ARG_DELAY] = 4;
5685 parameter[GFX_ARG_FRAMES_PER_LINE] = ARG_UNDEFINED_VALUE;
5688 if (filename_anim_initial == NULL) /* should not happen */
5689 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5691 anim_initial.bitmap = LoadCustomImage(filename_anim_initial);
5693 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
5695 set_graphic_parameters_ext(0, parameter, anim_initial.bitmap);
5698 printf("::: INIT_GFX: anim_frames_per_line == %d [%d / %d] [%d, %d]\n",
5699 graphic_info[0].anim_frames_per_line,
5700 get_scaled_graphic_width(0),
5701 graphic_info[0].width,
5702 getOriginalImageWidthFromImageID(0),
5703 graphic_info[0].scale_up_factor);
5706 graphic_info = graphic_info_last;
5708 init.busy.width = anim_initial.width;
5709 init.busy.height = anim_initial.height;
5711 InitMenuDesignSettings_Static();
5712 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5714 /* use copy of busy animation to prevent change while reloading artwork */
5719 void RedrawBackground()
5721 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
5722 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
5724 redraw_mask = REDRAW_ALL;
5727 void InitGfxBackground()
5731 fieldbuffer = bitmap_db_field;
5732 SetDrawtoField(DRAW_BACKBUFFER);
5735 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5739 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
5740 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
5743 for (x = 0; x < MAX_BUF_XSIZE; x++)
5744 for (y = 0; y < MAX_BUF_YSIZE; y++)
5747 redraw_mask = REDRAW_ALL;
5750 static void InitLevelInfo()
5752 LoadLevelInfo(); /* global level info */
5753 LoadLevelSetup_LastSeries(); /* last played series info */
5754 LoadLevelSetup_SeriesInfo(); /* last played level info */
5757 static void InitLevelArtworkInfo()
5759 LoadLevelArtworkInfo();
5762 static void InitImages()
5764 print_timestamp_init("InitImages");
5767 printf("::: leveldir_current->identifier == '%s'\n",
5768 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5769 printf("::: leveldir_current->graphics_path == '%s'\n",
5770 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5771 printf("::: leveldir_current->graphics_set == '%s'\n",
5772 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5773 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5774 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5777 setLevelArtworkDir(artwork.gfx_first);
5780 printf("::: leveldir_current->identifier == '%s'\n",
5781 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5782 printf("::: leveldir_current->graphics_path == '%s'\n",
5783 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5784 printf("::: leveldir_current->graphics_set == '%s'\n",
5785 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5786 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5787 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5791 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5792 leveldir_current->identifier,
5793 artwork.gfx_current_identifier,
5794 artwork.gfx_current->identifier,
5795 leveldir_current->graphics_set,
5796 leveldir_current->graphics_path);
5799 UPDATE_BUSY_STATE();
5801 ReloadCustomImages();
5802 print_timestamp_time("ReloadCustomImages");
5804 UPDATE_BUSY_STATE();
5806 LoadCustomElementDescriptions();
5807 print_timestamp_time("LoadCustomElementDescriptions");
5809 UPDATE_BUSY_STATE();
5811 LoadMenuDesignSettings();
5812 print_timestamp_time("LoadMenuDesignSettings");
5814 UPDATE_BUSY_STATE();
5816 ReinitializeGraphics();
5817 print_timestamp_time("ReinitializeGraphics");
5819 UPDATE_BUSY_STATE();
5821 print_timestamp_done("InitImages");
5824 static void InitSound(char *identifier)
5826 print_timestamp_init("InitSound");
5828 if (identifier == NULL)
5829 identifier = artwork.snd_current->identifier;
5831 /* set artwork path to send it to the sound server process */
5832 setLevelArtworkDir(artwork.snd_first);
5834 InitReloadCustomSounds(identifier);
5835 print_timestamp_time("InitReloadCustomSounds");
5837 ReinitializeSounds();
5838 print_timestamp_time("ReinitializeSounds");
5840 print_timestamp_done("InitSound");
5843 static void InitMusic(char *identifier)
5845 print_timestamp_init("InitMusic");
5847 if (identifier == NULL)
5848 identifier = artwork.mus_current->identifier;
5850 /* set artwork path to send it to the sound server process */
5851 setLevelArtworkDir(artwork.mus_first);
5853 InitReloadCustomMusic(identifier);
5854 print_timestamp_time("InitReloadCustomMusic");
5856 ReinitializeMusic();
5857 print_timestamp_time("ReinitializeMusic");
5859 print_timestamp_done("InitMusic");
5862 void InitNetworkServer()
5864 #if defined(NETWORK_AVALIABLE)
5868 if (!options.network)
5871 #if defined(NETWORK_AVALIABLE)
5872 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5874 if (!ConnectToServer(options.server_host, options.server_port))
5875 Error(ERR_EXIT, "cannot connect to network game server");
5877 SendToServer_PlayerName(setup.player_name);
5878 SendToServer_ProtocolVersion();
5881 SendToServer_NrWanted(nr_wanted);
5885 static boolean CheckArtworkConfigForCustomElements(char *filename)
5887 SetupFileHash *setup_file_hash;
5888 boolean redefined_ce_found = FALSE;
5890 /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */
5892 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5894 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5896 char *token = HASH_ITERATION_TOKEN(itr);
5898 if (strPrefix(token, "custom_"))
5900 redefined_ce_found = TRUE;
5905 END_HASH_ITERATION(setup_file_hash, itr)
5907 freeSetupFileHash(setup_file_hash);
5910 return redefined_ce_found;
5913 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5915 char *filename_base, *filename_local;
5916 boolean redefined_ce_found = FALSE;
5918 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5921 printf("::: leveldir_current->identifier == '%s'\n",
5922 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5923 printf("::: leveldir_current->graphics_path == '%s'\n",
5924 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5925 printf("::: leveldir_current->graphics_set == '%s'\n",
5926 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5927 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5928 leveldir_current == NULL ? "[NULL]" :
5929 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5932 /* first look for special artwork configured in level series config */
5933 filename_base = getCustomArtworkLevelConfigFilename(type);
5936 printf("::: filename_base == '%s'\n", filename_base);
5939 if (fileExists(filename_base))
5940 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5942 filename_local = getCustomArtworkConfigFilename(type);
5945 printf("::: filename_local == '%s'\n", filename_local);
5948 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5949 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5952 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5955 return redefined_ce_found;
5958 static void InitOverrideArtwork()
5960 boolean redefined_ce_found = FALSE;
5962 /* to check if this level set redefines any CEs, do not use overriding */
5963 gfx.override_level_graphics = FALSE;
5964 gfx.override_level_sounds = FALSE;
5965 gfx.override_level_music = FALSE;
5967 /* now check if this level set has definitions for custom elements */
5968 if (setup.override_level_graphics == AUTO ||
5969 setup.override_level_sounds == AUTO ||
5970 setup.override_level_music == AUTO)
5971 redefined_ce_found =
5972 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5973 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5974 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5977 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5980 if (redefined_ce_found)
5982 /* this level set has CE definitions: change "AUTO" to "FALSE" */
5983 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5984 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
5985 gfx.override_level_music = (setup.override_level_music == TRUE);
5989 /* this level set has no CE definitions: change "AUTO" to "TRUE" */
5990 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5991 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
5992 gfx.override_level_music = (setup.override_level_music != FALSE);
5996 printf("::: => %d, %d, %d\n",
5997 gfx.override_level_graphics,
5998 gfx.override_level_sounds,
5999 gfx.override_level_music);
6003 static char *getNewArtworkIdentifier(int type)
6005 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
6006 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
6007 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
6008 static boolean initialized[3] = { FALSE, FALSE, FALSE };
6009 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
6011 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
6013 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
6015 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
6016 char *leveldir_identifier = leveldir_current->identifier;
6018 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
6019 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
6021 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
6023 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
6024 char *artwork_current_identifier;
6025 char *artwork_new_identifier = NULL; /* default: nothing has changed */
6027 /* leveldir_current may be invalid (level group, parent link) */
6028 if (!validLevelSeries(leveldir_current))
6031 /* 1st step: determine artwork set to be activated in descending order:
6032 --------------------------------------------------------------------
6033 1. setup artwork (when configured to override everything else)
6034 2. artwork set configured in "levelinfo.conf" of current level set
6035 (artwork in level directory will have priority when loading later)
6036 3. artwork in level directory (stored in artwork sub-directory)
6037 4. setup artwork (currently configured in setup menu) */
6039 if (setup_override_artwork)
6040 artwork_current_identifier = setup_artwork_set;
6041 else if (leveldir_artwork_set != NULL)
6042 artwork_current_identifier = leveldir_artwork_set;
6043 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
6044 artwork_current_identifier = leveldir_identifier;
6046 artwork_current_identifier = setup_artwork_set;
6049 /* 2nd step: check if it is really needed to reload artwork set
6050 ------------------------------------------------------------ */
6053 if (type == ARTWORK_TYPE_GRAPHICS)
6054 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
6055 artwork_new_identifier,
6056 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
6057 artwork_current_identifier,
6058 leveldir_current->graphics_set,
6059 leveldir_current->identifier);
6062 /* ---------- reload if level set and also artwork set has changed ------- */
6063 if (leveldir_current_identifier[type] != leveldir_identifier &&
6064 (last_has_level_artwork_set[type] || has_level_artwork_set))
6065 artwork_new_identifier = artwork_current_identifier;
6067 leveldir_current_identifier[type] = leveldir_identifier;
6068 last_has_level_artwork_set[type] = has_level_artwork_set;
6071 if (type == ARTWORK_TYPE_GRAPHICS)
6072 printf("::: 1: '%s'\n", artwork_new_identifier);
6075 /* ---------- reload if "override artwork" setting has changed ----------- */
6076 if (last_override_level_artwork[type] != setup_override_artwork)
6077 artwork_new_identifier = artwork_current_identifier;
6079 last_override_level_artwork[type] = setup_override_artwork;
6082 if (type == ARTWORK_TYPE_GRAPHICS)
6083 printf("::: 2: '%s'\n", artwork_new_identifier);
6086 /* ---------- reload if current artwork identifier has changed ----------- */
6087 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
6088 artwork_current_identifier))
6089 artwork_new_identifier = artwork_current_identifier;
6091 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
6094 if (type == ARTWORK_TYPE_GRAPHICS)
6095 printf("::: 3: '%s'\n", artwork_new_identifier);
6098 /* ---------- do not reload directly after starting ---------------------- */
6099 if (!initialized[type])
6100 artwork_new_identifier = NULL;
6102 initialized[type] = TRUE;
6105 if (type == ARTWORK_TYPE_GRAPHICS)
6106 printf("::: 4: '%s'\n", artwork_new_identifier);
6110 if (type == ARTWORK_TYPE_GRAPHICS)
6111 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
6112 artwork.gfx_current_identifier, artwork_current_identifier,
6113 artwork.gfx_current->identifier, leveldir_current->graphics_set,
6114 artwork_new_identifier);
6117 return artwork_new_identifier;
6120 void ReloadCustomArtwork(int force_reload)
6122 int last_game_status = game_status; /* save current game status */
6123 char *gfx_new_identifier;
6124 char *snd_new_identifier;
6125 char *mus_new_identifier;
6126 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
6127 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
6128 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
6129 boolean reload_needed;
6131 InitOverrideArtwork();
6133 force_reload_gfx |= AdjustGraphicsForEMC();
6135 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
6136 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
6137 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
6139 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
6140 snd_new_identifier != NULL || force_reload_snd ||
6141 mus_new_identifier != NULL || force_reload_mus);
6146 print_timestamp_init("ReloadCustomArtwork");
6148 game_status = GAME_MODE_LOADING;
6150 FadeOut(REDRAW_ALL);
6153 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6155 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
6157 print_timestamp_time("ClearRectangle");
6160 printf("::: fading in ... %d\n", fading.fade_mode);
6164 printf("::: done\n");
6167 if (gfx_new_identifier != NULL || force_reload_gfx)
6170 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
6171 artwork.gfx_current_identifier,
6173 artwork.gfx_current->identifier,
6174 leveldir_current->graphics_set);
6178 print_timestamp_time("InitImages");
6181 if (snd_new_identifier != NULL || force_reload_snd)
6183 InitSound(snd_new_identifier);
6184 print_timestamp_time("InitSound");
6187 if (mus_new_identifier != NULL || force_reload_mus)
6189 InitMusic(mus_new_identifier);
6190 print_timestamp_time("InitMusic");
6193 game_status = last_game_status; /* restore current game status */
6195 init_last = init; /* switch to new busy animation */
6198 printf("::: ----------------DELAY 1 ...\n");
6203 printf("::: FadeOut @ ReloadCustomArtwork ...\n");
6205 FadeOut(REDRAW_ALL);
6207 printf("::: FadeOut @ ReloadCustomArtwork done\n");
6212 /* force redraw of (open or closed) door graphics */
6213 SetDoorState(DOOR_OPEN_ALL);
6214 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
6219 FadeSetEnterScreen();
6220 FadeSkipNextFadeOut();
6221 // FadeSetDisabled();
6226 fading = fading_none;
6231 redraw_mask = REDRAW_ALL;
6234 print_timestamp_done("ReloadCustomArtwork");
6236 LimitScreenUpdates(FALSE);
6239 void KeyboardAutoRepeatOffUnlessAutoplay()
6241 if (global.autoplay_leveldir == NULL)
6242 KeyboardAutoRepeatOff();
6245 void DisplayExitMessage(char *format, va_list ap)
6247 // check if draw buffer and fonts for exit message are already available
6248 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
6251 int font_1 = FC_RED;
6252 int font_2 = FC_YELLOW;
6253 int font_3 = FC_BLUE;
6254 int font_width = getFontWidth(font_2);
6255 int font_height = getFontHeight(font_2);
6258 int sxsize = WIN_XSIZE - 2 * sx;
6259 int sysize = WIN_YSIZE - 2 * sy;
6260 int line_length = sxsize / font_width;
6261 int max_lines = sysize / font_height;
6262 int num_lines_printed;
6266 gfx.sxsize = sxsize;
6267 gfx.sysize = sysize;
6271 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6273 DrawTextSCentered(sy, font_1, "Fatal error:");
6274 sy += 3 * font_height;;
6277 DrawTextBufferVA(sx, sy, format, ap, font_2,
6278 line_length, line_length, max_lines,
6279 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6280 sy += (num_lines_printed + 3) * font_height;
6282 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
6283 sy += 3 * font_height;
6286 DrawTextBuffer(sx, sy, program.error_filename, font_2,
6287 line_length, line_length, max_lines,
6288 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6290 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
6292 redraw_mask = REDRAW_ALL;
6296 /* deactivate toons on error message screen */
6297 setup.toons = FALSE;
6299 WaitForEventToContinue();
6303 /* ========================================================================= */
6305 /* ========================================================================= */
6309 print_timestamp_init("OpenAll");
6311 game_status = GAME_MODE_LOADING;
6317 InitGlobal(); /* initialize some global variables */
6319 print_timestamp_time("[init global stuff]");
6321 if (options.execute_command)
6322 Execute_Command(options.execute_command);
6324 if (options.serveronly)
6326 #if defined(PLATFORM_UNIX)
6327 NetworkServer(options.server_port, options.serveronly);
6329 Error(ERR_WARN, "networking only supported in Unix version");
6332 exit(0); /* never reached, server loops forever */
6337 print_timestamp_time("[init setup/config stuff (1)]");
6340 print_timestamp_time("[init setup/config stuff (2)]");
6342 print_timestamp_time("[init setup/config stuff (3)]");
6343 InitArtworkInfo(); /* needed before loading gfx, sound & music */
6344 print_timestamp_time("[init setup/config stuff (4)]");
6345 InitArtworkConfig(); /* needed before forking sound child process */
6346 print_timestamp_time("[init setup/config stuff (5)]");
6348 print_timestamp_time("[init setup/config stuff (6)]");
6354 InitRND(NEW_RANDOMIZE);
6355 InitSimpleRandom(NEW_RANDOMIZE);
6359 print_timestamp_time("[init setup/config stuff]");
6362 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
6364 InitEventFilter(FilterEvents);
6366 print_timestamp_time("[init video stuff]");
6368 InitElementPropertiesStatic();
6369 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
6370 InitElementPropertiesGfxElement();
6372 print_timestamp_time("[init element properties stuff]");
6376 print_timestamp_time("InitGfx");
6379 print_timestamp_time("InitLevelInfo");
6381 InitLevelArtworkInfo();
6382 print_timestamp_time("InitLevelArtworkInfo");
6384 InitOverrideArtwork(); /* needs to know current level directory */
6385 print_timestamp_time("InitOverrideArtwork");
6387 InitImages(); /* needs to know current level directory */
6388 print_timestamp_time("InitImages");
6390 InitSound(NULL); /* needs to know current level directory */
6391 print_timestamp_time("InitSound");
6393 InitMusic(NULL); /* needs to know current level directory */
6394 print_timestamp_time("InitMusic");
6396 InitGfxBackground();
6406 if (global.autoplay_leveldir)
6411 else if (global.convert_leveldir)
6416 else if (global.create_images_dir)
6418 CreateLevelSketchImages();
6422 game_status = GAME_MODE_MAIN;
6425 FadeSetEnterScreen();
6426 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
6427 FadeSkipNextFadeOut();
6428 // FadeSetDisabled();
6430 fading = fading_none;
6433 print_timestamp_time("[post-artwork]");
6435 print_timestamp_done("OpenAll");
6439 InitNetworkServer();
6442 Error(ERR_DEBUG, "::: SDL_GetBasePath() == '%s'",
6444 Error(ERR_DEBUG, "::: SDL_GetPrefPath() == '%s'",
6445 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
6446 #if defined(PLATFORM_ANDROID)
6447 Error(ERR_DEBUG, "::: SDL_AndroidGetInternalStoragePath() == '%s'",
6448 SDL_AndroidGetInternalStoragePath());
6449 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStoragePath() == '%s'",
6450 SDL_AndroidGetExternalStoragePath());
6451 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStorageState() == '%s'",
6452 (SDL_AndroidGetExternalStorageState() ==
6453 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "read" :
6454 SDL_AndroidGetExternalStorageState() ==
6455 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "write" : "not available"));
6460 void CloseAllAndExit(int exit_value)
6465 CloseAudio(); /* called after freeing sounds (needed for SDL) */
6477 #if defined(TARGET_SDL)
6478 #if defined(TARGET_SDL2)
6480 // set a flag to tell the network server thread to quit and wait for it
6481 // using SDL_WaitThread()
6483 if (network_server) /* terminate network server */
6484 SDL_KillThread(server_thread);
6488 CloseVideoDisplay();
6489 ClosePlatformDependentStuff();
6491 if (exit_value != 0)
6493 /* fall back to default level set (current set may have caused an error) */
6494 SaveLevelSetup_LastSeries_Deactivate();
6496 /* tell user where to find error log file which may contain more details */
6497 // (error notification now directly displayed on screen inside R'n'D
6498 // NotifyUserAboutErrorFile(); /* currently only works for Windows */