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 static int special_graphics[] =
207 IMG_EDITOR_ELEMENT_BORDER,
208 IMG_EDITOR_ELEMENT_BORDER_INPUT,
209 IMG_EDITOR_CASCADE_LIST,
210 IMG_EDITOR_CASCADE_LIST_ACTIVE,
213 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
214 int num_property_mappings = getImageListPropertyMappingSize();
217 /* initialize normal images from static configuration */
218 for (i = 0; element_to_graphic[i].element > -1; i++)
219 InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
221 /* initialize special images from static configuration */
222 for (i = 0; element_to_special_graphic[i].element > -1; i++)
223 InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
225 /* initialize images from dynamic configuration (may be elements or other) */
226 for (i = 0; i < num_property_mappings; i++)
227 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
229 /* initialize special images from above list (non-element images) */
230 for (i = 0; special_graphics[i] > -1; i++)
231 InitElementSmallImagesScaledUp(special_graphics[i]);
234 void InitScaledImages()
238 /* scale normal images from static configuration, if not already scaled */
239 for (i = 0; i < NUM_IMAGE_FILES; i++)
240 ScaleImage(i, graphic_info[i].scale_up_factor);
244 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
245 void SetBitmaps_EM(Bitmap **em_bitmap)
247 em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
248 em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].bitmap;
253 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
254 void SetBitmaps_SP(Bitmap **sp_bitmap)
256 *sp_bitmap = graphic_info[IMG_SP_OBJECTS].bitmap;
260 static int getFontBitmapID(int font_nr)
264 /* (special case: do not use special font for GAME_MODE_LOADING) */
265 if (game_status >= GAME_MODE_TITLE_INITIAL &&
266 game_status <= GAME_MODE_PSEUDO_PREVIEW)
267 special = game_status;
268 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
269 special = GFX_SPECIAL_ARG_MAIN;
271 else if (game_status == GAME_MODE_PLAYING)
272 special = GFX_SPECIAL_ARG_DOOR;
279 font_info[font_nr].token_name,
280 special_suffix_info[special].suffix);
285 return font_info[font_nr].special_bitmap_id[special];
290 static int getFontFromToken(char *token)
293 char *value = getHashEntry(font_token_hash, token);
300 /* !!! OPTIMIZE THIS BY USING HASH !!! */
301 for (i = 0; i < NUM_FONTS; i++)
302 if (strEqual(token, font_info[i].token_name))
306 /* if font not found, use reliable default value */
307 return FONT_INITIAL_1;
310 void InitFontGraphicInfo()
312 static struct FontBitmapInfo *font_bitmap_info = NULL;
313 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
314 int num_property_mappings = getImageListPropertyMappingSize();
315 int num_font_bitmaps = NUM_FONTS;
318 if (graphic_info == NULL) /* still at startup phase */
320 InitFontInfo(font_initial, NUM_INITIAL_FONTS,
321 getFontBitmapID, getFontFromToken);
326 /* ---------- initialize font graphic definitions ---------- */
328 /* always start with reliable default values (normal font graphics) */
329 for (i = 0; i < NUM_FONTS; i++)
330 font_info[i].graphic = IMG_FONT_INITIAL_1;
332 /* initialize normal font/graphic mapping from static configuration */
333 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
335 int font_nr = font_to_graphic[i].font_nr;
336 int special = font_to_graphic[i].special;
337 int graphic = font_to_graphic[i].graphic;
342 font_info[font_nr].graphic = graphic;
345 /* always start with reliable default values (special font graphics) */
346 for (i = 0; i < NUM_FONTS; i++)
348 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
350 font_info[i].special_graphic[j] = font_info[i].graphic;
351 font_info[i].special_bitmap_id[j] = i;
355 /* initialize special font/graphic mapping from static configuration */
356 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
358 int font_nr = font_to_graphic[i].font_nr;
359 int special = font_to_graphic[i].special;
360 int graphic = font_to_graphic[i].graphic;
361 int base_graphic = font2baseimg(font_nr);
363 if (IS_SPECIAL_GFX_ARG(special))
365 boolean base_redefined =
366 getImageListEntryFromImageID(base_graphic)->redefined;
367 boolean special_redefined =
368 getImageListEntryFromImageID(graphic)->redefined;
369 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
371 /* if the base font ("font.title_1", for example) has been redefined,
372 but not the special font ("font.title_1.LEVELS", for example), do not
373 use an existing (in this case considered obsolete) special font
374 anymore, but use the automatically determined default font */
375 /* special case: cloned special fonts must be explicitly redefined,
376 but are not automatically redefined by redefining base font */
377 if (base_redefined && !special_redefined && !special_cloned)
380 font_info[font_nr].special_graphic[special] = graphic;
381 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
386 /* initialize special font/graphic mapping from dynamic configuration */
387 for (i = 0; i < num_property_mappings; i++)
389 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
390 int special = property_mapping[i].ext3_index;
391 int graphic = property_mapping[i].artwork_index;
396 if (IS_SPECIAL_GFX_ARG(special))
398 font_info[font_nr].special_graphic[special] = graphic;
399 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
404 /* correct special font/graphic mapping for cloned fonts for downwards
405 compatibility of PREVIEW fonts -- this is only needed for implicit
406 redefinition of special font by redefined base font, and only if other
407 fonts are cloned from this special font (like in the "Zelda" level set) */
408 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
410 int font_nr = font_to_graphic[i].font_nr;
411 int special = font_to_graphic[i].special;
412 int graphic = font_to_graphic[i].graphic;
414 if (IS_SPECIAL_GFX_ARG(special))
416 boolean special_redefined =
417 getImageListEntryFromImageID(graphic)->redefined;
418 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
420 if (special_cloned && !special_redefined)
424 for (j = 0; font_to_graphic[j].font_nr > -1; j++)
426 int font_nr2 = font_to_graphic[j].font_nr;
427 int special2 = font_to_graphic[j].special;
428 int graphic2 = font_to_graphic[j].graphic;
430 if (IS_SPECIAL_GFX_ARG(special2) &&
431 graphic2 == graphic_info[graphic].clone_from)
433 font_info[font_nr].special_graphic[special] =
434 font_info[font_nr2].special_graphic[special2];
435 font_info[font_nr].special_bitmap_id[special] =
436 font_info[font_nr2].special_bitmap_id[special2];
443 /* reset non-redefined ".active" font graphics if normal font is redefined */
444 /* (this different treatment is needed because normal and active fonts are
445 independently defined ("active" is not a property of font definitions!) */
446 for (i = 0; i < NUM_FONTS; i++)
448 int font_nr_base = i;
449 int font_nr_active = FONT_ACTIVE(font_nr_base);
451 /* check only those fonts with exist as normal and ".active" variant */
452 if (font_nr_base != font_nr_active)
454 int base_graphic = font_info[font_nr_base].graphic;
455 int active_graphic = font_info[font_nr_active].graphic;
456 boolean base_redefined =
457 getImageListEntryFromImageID(base_graphic)->redefined;
458 boolean active_redefined =
459 getImageListEntryFromImageID(active_graphic)->redefined;
461 /* if the base font ("font.menu_1", for example) has been redefined,
462 but not the active font ("font.menu_1.active", for example), do not
463 use an existing (in this case considered obsolete) active font
464 anymore, but use the automatically determined default font */
465 if (base_redefined && !active_redefined)
466 font_info[font_nr_active].graphic = base_graphic;
468 /* now also check each "special" font (which may be the same as above) */
469 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
471 int base_graphic = font_info[font_nr_base].special_graphic[j];
472 int active_graphic = font_info[font_nr_active].special_graphic[j];
473 boolean base_redefined =
474 getImageListEntryFromImageID(base_graphic)->redefined;
475 boolean active_redefined =
476 getImageListEntryFromImageID(active_graphic)->redefined;
478 /* same as above, but check special graphic definitions, for example:
479 redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN" */
480 if (base_redefined && !active_redefined)
482 font_info[font_nr_active].special_graphic[j] =
483 font_info[font_nr_base].special_graphic[j];
484 font_info[font_nr_active].special_bitmap_id[j] =
485 font_info[font_nr_base].special_bitmap_id[j];
491 /* ---------- initialize font bitmap array ---------- */
493 if (font_bitmap_info != NULL)
494 FreeFontInfo(font_bitmap_info);
497 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
499 /* ---------- initialize font bitmap definitions ---------- */
501 for (i = 0; i < NUM_FONTS; i++)
503 if (i < NUM_INITIAL_FONTS)
505 font_bitmap_info[i] = font_initial[i];
509 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
511 int font_bitmap_id = font_info[i].special_bitmap_id[j];
512 int graphic = font_info[i].special_graphic[j];
514 /* set 'graphic_info' for font entries, if uninitialized (guessed) */
515 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
517 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
518 graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
521 /* copy font relevant information from graphics information */
522 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
523 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
524 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
525 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
526 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
528 font_bitmap_info[font_bitmap_id].draw_xoffset =
529 graphic_info[graphic].draw_xoffset;
530 font_bitmap_info[font_bitmap_id].draw_yoffset =
531 graphic_info[graphic].draw_yoffset;
533 font_bitmap_info[font_bitmap_id].num_chars =
534 graphic_info[graphic].anim_frames;
535 font_bitmap_info[font_bitmap_id].num_chars_per_line =
536 graphic_info[graphic].anim_frames_per_line;
540 InitFontInfo(font_bitmap_info, num_font_bitmaps,
541 getFontBitmapID, getFontFromToken);
544 void InitElementGraphicInfo()
546 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
547 int num_property_mappings = getImageListPropertyMappingSize();
550 if (graphic_info == NULL) /* still at startup phase */
553 /* set values to -1 to identify later as "uninitialized" values */
554 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
556 for (act = 0; act < NUM_ACTIONS; act++)
558 element_info[i].graphic[act] = -1;
559 element_info[i].crumbled[act] = -1;
561 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
563 element_info[i].direction_graphic[act][dir] = -1;
564 element_info[i].direction_crumbled[act][dir] = -1;
571 /* initialize normal element/graphic mapping from static configuration */
572 for (i = 0; element_to_graphic[i].element > -1; i++)
574 int element = element_to_graphic[i].element;
575 int action = element_to_graphic[i].action;
576 int direction = element_to_graphic[i].direction;
577 boolean crumbled = element_to_graphic[i].crumbled;
578 int graphic = element_to_graphic[i].graphic;
579 int base_graphic = el2baseimg(element);
581 if (graphic_info[graphic].bitmap == NULL)
584 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
587 boolean base_redefined =
588 getImageListEntryFromImageID(base_graphic)->redefined;
589 boolean act_dir_redefined =
590 getImageListEntryFromImageID(graphic)->redefined;
592 /* if the base graphic ("emerald", for example) has been redefined,
593 but not the action graphic ("emerald.falling", for example), do not
594 use an existing (in this case considered obsolete) action graphic
595 anymore, but use the automatically determined default graphic */
596 if (base_redefined && !act_dir_redefined)
601 action = ACTION_DEFAULT;
606 element_info[element].direction_crumbled[action][direction] = graphic;
608 element_info[element].crumbled[action] = graphic;
613 element_info[element].direction_graphic[action][direction] = graphic;
615 element_info[element].graphic[action] = graphic;
619 /* initialize normal element/graphic mapping from dynamic configuration */
620 for (i = 0; i < num_property_mappings; i++)
622 int element = property_mapping[i].base_index;
623 int action = property_mapping[i].ext1_index;
624 int direction = property_mapping[i].ext2_index;
625 int special = property_mapping[i].ext3_index;
626 int graphic = property_mapping[i].artwork_index;
627 boolean crumbled = FALSE;
630 if ((element == EL_EM_DYNAMITE ||
631 element == EL_EM_DYNAMITE_ACTIVE) &&
632 action == ACTION_ACTIVE &&
633 (special == GFX_SPECIAL_ARG_EDITOR ||
634 special == GFX_SPECIAL_ARG_PANEL))
635 printf("::: DYNAMIC: %d, %d, %d -> %d\n",
636 element, action, special, graphic);
639 if (special == GFX_SPECIAL_ARG_CRUMBLED)
645 if (graphic_info[graphic].bitmap == NULL)
648 if (element >= MAX_NUM_ELEMENTS || special != -1)
652 action = ACTION_DEFAULT;
657 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
658 element_info[element].direction_crumbled[action][dir] = -1;
661 element_info[element].direction_crumbled[action][direction] = graphic;
663 element_info[element].crumbled[action] = graphic;
668 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
669 element_info[element].direction_graphic[action][dir] = -1;
672 element_info[element].direction_graphic[action][direction] = graphic;
674 element_info[element].graphic[action] = graphic;
678 /* now copy all graphics that are defined to be cloned from other graphics */
679 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
681 int graphic = element_info[i].graphic[ACTION_DEFAULT];
682 int crumbled_like, diggable_like;
687 crumbled_like = graphic_info[graphic].crumbled_like;
688 diggable_like = graphic_info[graphic].diggable_like;
690 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
692 for (act = 0; act < NUM_ACTIONS; act++)
693 element_info[i].crumbled[act] =
694 element_info[crumbled_like].crumbled[act];
695 for (act = 0; act < NUM_ACTIONS; act++)
696 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
697 element_info[i].direction_crumbled[act][dir] =
698 element_info[crumbled_like].direction_crumbled[act][dir];
701 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
703 element_info[i].graphic[ACTION_DIGGING] =
704 element_info[diggable_like].graphic[ACTION_DIGGING];
705 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
706 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
707 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
712 /* set hardcoded definitions for some runtime elements without graphic */
713 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
717 /* set hardcoded definitions for some internal elements without graphic */
718 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
720 if (IS_EDITOR_CASCADE_INACTIVE(i))
721 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
722 else if (IS_EDITOR_CASCADE_ACTIVE(i))
723 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
727 /* now set all undefined/invalid graphics to -1 to set to default after it */
728 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
730 for (act = 0; act < NUM_ACTIONS; act++)
734 graphic = element_info[i].graphic[act];
735 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
736 element_info[i].graphic[act] = -1;
738 graphic = element_info[i].crumbled[act];
739 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
740 element_info[i].crumbled[act] = -1;
742 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
744 graphic = element_info[i].direction_graphic[act][dir];
745 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
746 element_info[i].direction_graphic[act][dir] = -1;
748 graphic = element_info[i].direction_crumbled[act][dir];
749 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
750 element_info[i].direction_crumbled[act][dir] = -1;
757 /* adjust graphics with 2nd tile for movement according to direction
758 (do this before correcting '-1' values to minimize calculations) */
759 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
761 for (act = 0; act < NUM_ACTIONS; act++)
763 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
765 int graphic = element_info[i].direction_graphic[act][dir];
766 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
768 if (act == ACTION_FALLING) /* special case */
769 graphic = element_info[i].graphic[act];
772 graphic_info[graphic].double_movement &&
773 graphic_info[graphic].swap_double_tiles != 0)
775 struct GraphicInfo *g = &graphic_info[graphic];
776 int src_x_front = g->src_x;
777 int src_y_front = g->src_y;
778 int src_x_back = g->src_x + g->offset2_x;
779 int src_y_back = g->src_y + g->offset2_y;
780 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
782 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
783 src_y_front < src_y_back);
784 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
785 boolean swap_movement_tiles_autodetected =
786 (!frames_are_ordered_diagonally &&
787 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
788 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
789 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
790 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
793 /* swap frontside and backside graphic tile coordinates, if needed */
794 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
796 /* get current (wrong) backside tile coordinates */
797 getFixedGraphicSourceExt(graphic, 0, &dummy,
798 &src_x_back, &src_y_back, TRUE);
800 /* set frontside tile coordinates to backside tile coordinates */
801 g->src_x = src_x_back;
802 g->src_y = src_y_back;
804 /* invert tile offset to point to new backside tile coordinates */
808 /* do not swap front and backside tiles again after correction */
809 g->swap_double_tiles = 0;
818 /* now set all '-1' values to element specific default values */
819 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
821 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
822 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
823 int default_direction_graphic[NUM_DIRECTIONS_FULL];
824 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
826 if (default_graphic == -1)
827 default_graphic = IMG_UNKNOWN;
829 if (default_crumbled == -1)
830 default_crumbled = default_graphic;
832 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
833 if (default_crumbled == -1)
834 default_crumbled = IMG_EMPTY;
837 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
839 default_direction_graphic[dir] =
840 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
841 default_direction_crumbled[dir] =
842 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
844 if (default_direction_graphic[dir] == -1)
845 default_direction_graphic[dir] = default_graphic;
847 if (default_direction_crumbled[dir] == -1)
848 default_direction_crumbled[dir] = default_direction_graphic[dir];
850 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
851 if (default_direction_crumbled[dir] == -1)
852 default_direction_crumbled[dir] = default_crumbled;
856 for (act = 0; act < NUM_ACTIONS; act++)
858 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
859 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
860 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
861 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
862 act == ACTION_TURNING_FROM_RIGHT ||
863 act == ACTION_TURNING_FROM_UP ||
864 act == ACTION_TURNING_FROM_DOWN);
866 /* generic default action graphic (defined by "[default]" directive) */
867 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
868 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
869 int default_remove_graphic = IMG_EMPTY;
871 if (act_remove && default_action_graphic != -1)
872 default_remove_graphic = default_action_graphic;
874 /* look for special default action graphic (classic game specific) */
875 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
876 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
877 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
878 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
879 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
880 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
882 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
883 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
884 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
885 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
886 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
887 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
890 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
891 /* !!! make this better !!! */
892 if (i == EL_EMPTY_SPACE)
894 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
895 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
899 if (default_action_graphic == -1)
900 default_action_graphic = default_graphic;
902 if (default_action_crumbled == -1)
903 default_action_crumbled = default_action_graphic;
905 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
906 if (default_action_crumbled == -1)
907 default_action_crumbled = default_crumbled;
910 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
912 /* use action graphic as the default direction graphic, if undefined */
913 int default_action_direction_graphic = element_info[i].graphic[act];
914 int default_action_direction_crumbled = element_info[i].crumbled[act];
916 /* no graphic for current action -- use default direction graphic */
917 if (default_action_direction_graphic == -1)
918 default_action_direction_graphic =
919 (act_remove ? default_remove_graphic :
921 element_info[i].direction_graphic[ACTION_TURNING][dir] :
922 default_action_graphic != default_graphic ?
923 default_action_graphic :
924 default_direction_graphic[dir]);
926 if (element_info[i].direction_graphic[act][dir] == -1)
927 element_info[i].direction_graphic[act][dir] =
928 default_action_direction_graphic;
931 if (default_action_direction_crumbled == -1)
932 default_action_direction_crumbled =
933 element_info[i].direction_graphic[act][dir];
935 if (default_action_direction_crumbled == -1)
936 default_action_direction_crumbled =
937 (act_remove ? default_remove_graphic :
939 element_info[i].direction_crumbled[ACTION_TURNING][dir] :
940 default_action_crumbled != default_crumbled ?
941 default_action_crumbled :
942 default_direction_crumbled[dir]);
945 if (element_info[i].direction_crumbled[act][dir] == -1)
946 element_info[i].direction_crumbled[act][dir] =
947 default_action_direction_crumbled;
950 /* no graphic for this specific action -- use default action graphic */
951 if (element_info[i].graphic[act] == -1)
952 element_info[i].graphic[act] =
953 (act_remove ? default_remove_graphic :
954 act_turning ? element_info[i].graphic[ACTION_TURNING] :
955 default_action_graphic);
957 if (element_info[i].crumbled[act] == -1)
958 element_info[i].crumbled[act] = element_info[i].graphic[act];
960 if (element_info[i].crumbled[act] == -1)
961 element_info[i].crumbled[act] =
962 (act_remove ? default_remove_graphic :
963 act_turning ? element_info[i].crumbled[ACTION_TURNING] :
964 default_action_crumbled);
972 /* !!! THIS ALSO CLEARS SPECIAL FLAGS (AND IS NOT NEEDED ANYWAY) !!! */
973 /* set animation mode to "none" for each graphic with only 1 frame */
974 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
976 for (act = 0; act < NUM_ACTIONS; act++)
978 int graphic = element_info[i].graphic[act];
979 int crumbled = element_info[i].crumbled[act];
981 if (graphic_info[graphic].anim_frames == 1)
982 graphic_info[graphic].anim_mode = ANIM_NONE;
983 if (graphic_info[crumbled].anim_frames == 1)
984 graphic_info[crumbled].anim_mode = ANIM_NONE;
986 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
988 graphic = element_info[i].direction_graphic[act][dir];
989 crumbled = element_info[i].direction_crumbled[act][dir];
991 if (graphic_info[graphic].anim_frames == 1)
992 graphic_info[graphic].anim_mode = ANIM_NONE;
993 if (graphic_info[crumbled].anim_frames == 1)
994 graphic_info[crumbled].anim_mode = ANIM_NONE;
1002 if (options.verbose)
1004 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1005 if (element_info[i].graphic[ACTION_DEFAULT] == IMG_UNKNOWN &&
1007 Error(ERR_INFO, "warning: no graphic for element '%s' (%d)",
1008 element_info[i].token_name, i);
1014 void InitElementSpecialGraphicInfo()
1016 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
1017 int num_property_mappings = getImageListPropertyMappingSize();
1020 /* always start with reliable default values */
1021 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1022 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1023 element_info[i].special_graphic[j] =
1024 element_info[i].graphic[ACTION_DEFAULT];
1026 /* initialize special element/graphic mapping from static configuration */
1027 for (i = 0; element_to_special_graphic[i].element > -1; i++)
1029 int element = element_to_special_graphic[i].element;
1030 int special = element_to_special_graphic[i].special;
1031 int graphic = element_to_special_graphic[i].graphic;
1032 int base_graphic = el2baseimg(element);
1033 boolean base_redefined =
1034 getImageListEntryFromImageID(base_graphic)->redefined;
1035 boolean special_redefined =
1036 getImageListEntryFromImageID(graphic)->redefined;
1039 if ((element == EL_EM_DYNAMITE ||
1040 element == EL_EM_DYNAMITE_ACTIVE) &&
1041 (special == GFX_SPECIAL_ARG_EDITOR ||
1042 special == GFX_SPECIAL_ARG_PANEL))
1043 printf("::: SPECIAL STATIC: %d, %d -> %d\n",
1044 element, special, graphic);
1047 /* if the base graphic ("emerald", for example) has been redefined,
1048 but not the special graphic ("emerald.EDITOR", for example), do not
1049 use an existing (in this case considered obsolete) special graphic
1050 anymore, but use the automatically created (down-scaled) graphic */
1051 if (base_redefined && !special_redefined)
1054 element_info[element].special_graphic[special] = graphic;
1057 /* initialize special element/graphic mapping from dynamic configuration */
1058 for (i = 0; i < num_property_mappings; i++)
1060 int element = property_mapping[i].base_index;
1061 int action = property_mapping[i].ext1_index;
1062 int direction = property_mapping[i].ext2_index;
1063 int special = property_mapping[i].ext3_index;
1064 int graphic = property_mapping[i].artwork_index;
1067 if ((element == EL_EM_DYNAMITE ||
1068 element == EL_EM_DYNAMITE_ACTIVE ||
1069 element == EL_CONVEYOR_BELT_1_MIDDLE ||
1070 element == EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE) &&
1071 (special == GFX_SPECIAL_ARG_EDITOR ||
1072 special == GFX_SPECIAL_ARG_PANEL))
1073 printf("::: SPECIAL DYNAMIC: %d, %d -> %d [%d]\n",
1074 element, special, graphic, property_mapping[i].ext1_index);
1078 if (element == EL_CONVEYOR_BELT_1_MIDDLE &&
1079 action == ACTION_ACTIVE)
1081 element = EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE;
1087 if (element == EL_MAGIC_WALL &&
1088 action == ACTION_ACTIVE)
1090 element = EL_MAGIC_WALL_ACTIVE;
1096 /* for action ".active", replace element with active element, if exists */
1097 if (action == ACTION_ACTIVE && element != ELEMENT_ACTIVE(element))
1099 element = ELEMENT_ACTIVE(element);
1104 if (element >= MAX_NUM_ELEMENTS)
1107 /* do not change special graphic if action or direction was specified */
1108 if (action != -1 || direction != -1)
1111 if (IS_SPECIAL_GFX_ARG(special))
1112 element_info[element].special_graphic[special] = graphic;
1115 /* now set all undefined/invalid graphics to default */
1116 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1117 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1118 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
1119 element_info[i].special_graphic[j] =
1120 element_info[i].graphic[ACTION_DEFAULT];
1123 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
1125 if (type != TYPE_ELEMENT && type != TYPE_GRAPHIC)
1126 return get_parameter_value(value_raw, suffix, type);
1128 if (strEqual(value_raw, ARG_UNDEFINED))
1129 return ARG_UNDEFINED_VALUE;
1131 if (type == TYPE_ELEMENT)
1133 char *value = getHashEntry(element_token_hash, value_raw);
1135 return (value != NULL ? atoi(value) : EL_UNDEFINED);
1137 else if (type == TYPE_GRAPHIC)
1139 char *value = getHashEntry(graphic_token_hash, value_raw);
1141 return (value != NULL ? atoi(value) : IMG_UNDEFINED);
1147 static int get_scaled_graphic_width(int graphic)
1149 int original_width = getOriginalImageWidthFromImageID(graphic);
1150 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1152 return original_width * scale_up_factor;
1155 static int get_scaled_graphic_height(int graphic)
1157 int original_height = getOriginalImageHeightFromImageID(graphic);
1158 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1160 return original_height * scale_up_factor;
1163 static void set_graphic_parameters_ext(int graphic, int *parameter,
1166 struct GraphicInfo *g = &graphic_info[graphic];
1167 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1168 int anim_frames_per_line = 1;
1170 /* always start with reliable default values */
1171 g->src_image_width = 0;
1172 g->src_image_height = 0;
1175 g->width = TILEX; /* default for element graphics */
1176 g->height = TILEY; /* default for element graphics */
1177 g->offset_x = 0; /* one or both of these values ... */
1178 g->offset_y = 0; /* ... will be corrected later */
1179 g->offset2_x = 0; /* one or both of these values ... */
1180 g->offset2_y = 0; /* ... will be corrected later */
1181 g->swap_double_tiles = -1; /* auto-detect tile swapping */
1182 g->crumbled_like = -1; /* do not use clone element */
1183 g->diggable_like = -1; /* do not use clone element */
1184 g->border_size = TILEX / 8; /* "CRUMBLED" border size */
1185 g->scale_up_factor = 1; /* default: no scaling up */
1186 g->tile_size = TILESIZE; /* default: standard tile size */
1187 g->clone_from = -1; /* do not use clone graphic */
1188 g->anim_delay_fixed = 0;
1189 g->anim_delay_random = 0;
1190 g->post_delay_fixed = 0;
1191 g->post_delay_random = 0;
1192 g->fade_mode = FADE_MODE_DEFAULT;
1196 g->align = ALIGN_CENTER; /* default for title screens */
1197 g->valign = VALIGN_MIDDLE; /* default for title screens */
1198 g->sort_priority = 0; /* default for title screens */
1200 g->style = STYLE_DEFAULT;
1202 g->bitmap = src_bitmap;
1205 /* optional zoom factor for scaling up the image to a larger size */
1206 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1207 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1208 if (g->scale_up_factor < 1)
1209 g->scale_up_factor = 1; /* no scaling */
1213 /* optional tile size for using non-standard image size */
1214 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1215 g->tile_size = parameter[GFX_ARG_TILE_SIZE];
1216 if (g->tile_size < TILESIZE)
1217 g->tile_size = TILESIZE; /* standard tile size */
1221 if (g->use_image_size)
1223 /* set new default bitmap size (with scaling, but without small images) */
1224 g->width = get_scaled_graphic_width(graphic);
1225 g->height = get_scaled_graphic_height(graphic);
1229 /* optional x and y tile position of animation frame sequence */
1230 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1231 g->src_x = parameter[GFX_ARG_XPOS] * TILEX;
1232 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1233 g->src_y = parameter[GFX_ARG_YPOS] * TILEY;
1235 /* optional x and y pixel position of animation frame sequence */
1236 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1237 g->src_x = parameter[GFX_ARG_X];
1238 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1239 g->src_y = parameter[GFX_ARG_Y];
1241 /* optional width and height of each animation frame */
1242 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1243 g->width = parameter[GFX_ARG_WIDTH];
1244 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1245 g->height = parameter[GFX_ARG_HEIGHT];
1251 Error(ERR_INFO_LINE, "-");
1252 Error(ERR_WARN, "invalid value %d for '%s.width' (fallback done to %d)",
1253 g->width, getTokenFromImageID(graphic), TILEX);
1254 Error(ERR_INFO_LINE, "-");
1256 g->width = TILEX; /* will be checked to be inside bitmap later */
1261 Error(ERR_INFO_LINE, "-");
1262 Error(ERR_WARN, "invalid value %d for '%s.height' (fallback done to %d)",
1263 g->height, getTokenFromImageID(graphic), TILEY);
1264 Error(ERR_INFO_LINE, "-");
1266 g->height = TILEY; /* will be checked to be inside bitmap later */
1271 /* optional zoom factor for scaling up the image to a larger size */
1272 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1273 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1274 if (g->scale_up_factor < 1)
1275 g->scale_up_factor = 1; /* no scaling */
1280 /* get final bitmap size (with scaling, but without small images) */
1281 int src_image_width = get_scaled_graphic_width(graphic);
1282 int src_image_height = get_scaled_graphic_height(graphic);
1284 if (src_image_width == 0 || src_image_height == 0)
1286 /* only happens when loaded outside artwork system (like "global.busy") */
1287 src_image_width = src_bitmap->width;
1288 src_image_height = src_bitmap->height;
1291 anim_frames_per_row = src_image_width / g->width;
1292 anim_frames_per_col = src_image_height / g->height;
1294 g->src_image_width = src_image_width;
1295 g->src_image_height = src_image_height;
1298 /* correct x or y offset dependent of vertical or horizontal frame order */
1299 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1301 g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1302 parameter[GFX_ARG_OFFSET] : g->height);
1303 anim_frames_per_line = anim_frames_per_col;
1305 else /* frames are ordered horizontally */
1307 g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1308 parameter[GFX_ARG_OFFSET] : g->width);
1309 anim_frames_per_line = anim_frames_per_row;
1312 /* optionally, the x and y offset of frames can be specified directly */
1313 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1314 g->offset_x = parameter[GFX_ARG_XOFFSET];
1315 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1316 g->offset_y = parameter[GFX_ARG_YOFFSET];
1318 /* optionally, moving animations may have separate start and end graphics */
1319 g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1321 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1322 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1324 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1325 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1326 g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1327 parameter[GFX_ARG_2ND_OFFSET] : g->height);
1328 else /* frames are ordered horizontally */
1329 g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1330 parameter[GFX_ARG_2ND_OFFSET] : g->width);
1332 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1333 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1334 g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1335 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1336 g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1338 /* optionally, the second movement tile can be specified as start tile */
1339 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1340 g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1342 /* automatically determine correct number of frames, if not defined */
1343 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1344 g->anim_frames = parameter[GFX_ARG_FRAMES];
1345 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1346 g->anim_frames = anim_frames_per_row;
1347 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1348 g->anim_frames = anim_frames_per_col;
1352 if (g->anim_frames == 0) /* frames must be at least 1 */
1355 g->anim_frames_per_line =
1356 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1357 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1359 g->anim_delay = parameter[GFX_ARG_DELAY];
1360 if (g->anim_delay == 0) /* delay must be at least 1 */
1363 g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1365 if (g->anim_frames == 1)
1366 g->anim_mode = ANIM_NONE;
1369 /* automatically determine correct start frame, if not defined */
1370 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1371 g->anim_start_frame = 0;
1372 else if (g->anim_mode & ANIM_REVERSE)
1373 g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1375 g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1377 /* animation synchronized with global frame counter, not move position */
1378 g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1380 /* optional element for cloning crumble graphics */
1381 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1382 g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1384 /* optional element for cloning digging graphics */
1385 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1386 g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1388 /* optional border size for "crumbling" diggable graphics */
1389 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1390 g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1392 /* this is only used for player "boring" and "sleeping" actions */
1393 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1394 g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1395 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1396 g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1397 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1398 g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1399 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1400 g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1402 /* this is only used for toon animations */
1403 g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1404 g->step_delay = parameter[GFX_ARG_STEP_DELAY];
1406 /* this is only used for drawing font characters */
1407 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1408 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1410 /* this is only used for drawing envelope graphics */
1411 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1413 /* optional graphic for cloning all graphics settings */
1414 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1415 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1417 /* optional settings for drawing title screens and title messages */
1418 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1419 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1420 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1421 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1422 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1423 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1424 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1425 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1426 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1427 g->align = parameter[GFX_ARG_ALIGN];
1428 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1429 g->valign = parameter[GFX_ARG_VALIGN];
1430 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1431 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1433 if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
1434 g->class = parameter[GFX_ARG_CLASS];
1435 if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
1436 g->style = parameter[GFX_ARG_STYLE];
1438 /* this is only used for drawing menu buttons and text */
1439 g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
1440 g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
1441 g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
1442 g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
1445 static void set_graphic_parameters(int graphic)
1448 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1449 char **parameter_raw = image->parameter;
1450 Bitmap *src_bitmap = getBitmapFromImageID(graphic);
1451 int parameter[NUM_GFX_ARGS];
1454 /* if fallback to default artwork is done, also use the default parameters */
1455 if (image->fallback_to_default)
1456 parameter_raw = image->default_parameter;
1458 /* get integer values from string parameters */
1459 for (i = 0; i < NUM_GFX_ARGS; i++)
1460 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1461 image_config_suffix[i].token,
1462 image_config_suffix[i].type);
1464 set_graphic_parameters_ext(graphic, parameter, src_bitmap);
1468 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1469 char **parameter_raw = image->parameter;
1470 Bitmap *src_bitmap = getBitmapFromImageID(graphic);
1471 int parameter[NUM_GFX_ARGS];
1472 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1473 int anim_frames_per_line = 1;
1476 /* if fallback to default artwork is done, also use the default parameters */
1477 if (image->fallback_to_default)
1478 parameter_raw = image->default_parameter;
1480 /* get integer values from string parameters */
1481 for (i = 0; i < NUM_GFX_ARGS; i++)
1482 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1483 image_config_suffix[i].token,
1484 image_config_suffix[i].type);
1486 graphic_info[graphic].bitmap = src_bitmap;
1488 /* always start with reliable default values */
1489 graphic_info[graphic].src_image_width = 0;
1490 graphic_info[graphic].src_image_height = 0;
1491 graphic_info[graphic].src_x = 0;
1492 graphic_info[graphic].src_y = 0;
1493 graphic_info[graphic].width = TILEX; /* default for element graphics */
1494 graphic_info[graphic].height = TILEY; /* default for element graphics */
1495 graphic_info[graphic].offset_x = 0; /* one or both of these values ... */
1496 graphic_info[graphic].offset_y = 0; /* ... will be corrected later */
1497 graphic_info[graphic].offset2_x = 0; /* one or both of these values ... */
1498 graphic_info[graphic].offset2_y = 0; /* ... will be corrected later */
1499 graphic_info[graphic].swap_double_tiles = -1; /* auto-detect tile swapping */
1500 graphic_info[graphic].crumbled_like = -1; /* do not use clone element */
1501 graphic_info[graphic].diggable_like = -1; /* do not use clone element */
1502 graphic_info[graphic].border_size = TILEX / 8; /* "CRUMBLED" border size */
1503 graphic_info[graphic].scale_up_factor = 1; /* default: no scaling up */
1504 graphic_info[graphic].clone_from = -1; /* do not use clone graphic */
1505 graphic_info[graphic].anim_delay_fixed = 0;
1506 graphic_info[graphic].anim_delay_random = 0;
1507 graphic_info[graphic].post_delay_fixed = 0;
1508 graphic_info[graphic].post_delay_random = 0;
1509 graphic_info[graphic].fade_mode = FADE_MODE_DEFAULT;
1510 graphic_info[graphic].fade_delay = -1;
1511 graphic_info[graphic].post_delay = -1;
1512 graphic_info[graphic].auto_delay = -1;
1513 graphic_info[graphic].align = ALIGN_CENTER; /* default for title screens */
1514 graphic_info[graphic].valign = VALIGN_MIDDLE; /* default for title screens */
1515 graphic_info[graphic].sort_priority = 0; /* default for title screens */
1518 /* optional zoom factor for scaling up the image to a larger size */
1519 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1520 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1521 if (graphic_info[graphic].scale_up_factor < 1)
1522 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
1526 if (graphic_info[graphic].use_image_size)
1528 /* set new default bitmap size (with scaling, but without small images) */
1529 graphic_info[graphic].width = get_scaled_graphic_width(graphic);
1530 graphic_info[graphic].height = get_scaled_graphic_height(graphic);
1534 /* optional x and y tile position of animation frame sequence */
1535 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1536 graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
1537 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1538 graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
1540 /* optional x and y pixel position of animation frame sequence */
1541 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1542 graphic_info[graphic].src_x = parameter[GFX_ARG_X];
1543 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1544 graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
1546 /* optional width and height of each animation frame */
1547 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1548 graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
1549 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1550 graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
1553 /* optional zoom factor for scaling up the image to a larger size */
1554 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1555 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1556 if (graphic_info[graphic].scale_up_factor < 1)
1557 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
1562 /* get final bitmap size (with scaling, but without small images) */
1563 int src_image_width = get_scaled_graphic_width(graphic);
1564 int src_image_height = get_scaled_graphic_height(graphic);
1566 anim_frames_per_row = src_image_width / graphic_info[graphic].width;
1567 anim_frames_per_col = src_image_height / graphic_info[graphic].height;
1569 graphic_info[graphic].src_image_width = src_image_width;
1570 graphic_info[graphic].src_image_height = src_image_height;
1573 /* correct x or y offset dependent of vertical or horizontal frame order */
1574 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1576 graphic_info[graphic].offset_y =
1577 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1578 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
1579 anim_frames_per_line = anim_frames_per_col;
1581 else /* frames are ordered horizontally */
1583 graphic_info[graphic].offset_x =
1584 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1585 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
1586 anim_frames_per_line = anim_frames_per_row;
1589 /* optionally, the x and y offset of frames can be specified directly */
1590 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1591 graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
1592 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1593 graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
1595 /* optionally, moving animations may have separate start and end graphics */
1596 graphic_info[graphic].double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1598 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1599 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1601 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1602 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1603 graphic_info[graphic].offset2_y =
1604 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1605 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].height);
1606 else /* frames are ordered horizontally */
1607 graphic_info[graphic].offset2_x =
1608 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1609 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].width);
1611 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1612 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1613 graphic_info[graphic].offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1614 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1615 graphic_info[graphic].offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1617 /* optionally, the second movement tile can be specified as start tile */
1618 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1619 graphic_info[graphic].swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1621 /* automatically determine correct number of frames, if not defined */
1622 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1623 graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
1624 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1625 graphic_info[graphic].anim_frames = anim_frames_per_row;
1626 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1627 graphic_info[graphic].anim_frames = anim_frames_per_col;
1629 graphic_info[graphic].anim_frames = 1;
1631 if (graphic_info[graphic].anim_frames == 0) /* frames must be at least 1 */
1632 graphic_info[graphic].anim_frames = 1;
1634 graphic_info[graphic].anim_frames_per_line =
1635 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1636 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1638 graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
1639 if (graphic_info[graphic].anim_delay == 0) /* delay must be at least 1 */
1640 graphic_info[graphic].anim_delay = 1;
1642 graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
1644 if (graphic_info[graphic].anim_frames == 1)
1645 graphic_info[graphic].anim_mode = ANIM_NONE;
1648 /* automatically determine correct start frame, if not defined */
1649 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1650 graphic_info[graphic].anim_start_frame = 0;
1651 else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
1652 graphic_info[graphic].anim_start_frame =
1653 graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1655 graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
1657 /* animation synchronized with global frame counter, not move position */
1658 graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1660 /* optional element for cloning crumble graphics */
1661 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1662 graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1664 /* optional element for cloning digging graphics */
1665 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1666 graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1668 /* optional border size for "crumbling" diggable graphics */
1669 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1670 graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
1672 /* this is only used for player "boring" and "sleeping" actions */
1673 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1674 graphic_info[graphic].anim_delay_fixed =
1675 parameter[GFX_ARG_ANIM_DELAY_FIXED];
1676 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1677 graphic_info[graphic].anim_delay_random =
1678 parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1679 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1680 graphic_info[graphic].post_delay_fixed =
1681 parameter[GFX_ARG_POST_DELAY_FIXED];
1682 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1683 graphic_info[graphic].post_delay_random =
1684 parameter[GFX_ARG_POST_DELAY_RANDOM];
1686 /* this is only used for toon animations */
1687 graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
1688 graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY];
1690 /* this is only used for drawing font characters */
1691 graphic_info[graphic].draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1692 graphic_info[graphic].draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1694 /* this is only used for drawing envelope graphics */
1695 graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1697 /* optional graphic for cloning all graphics settings */
1698 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1699 graphic_info[graphic].clone_from = parameter[GFX_ARG_CLONE_FROM];
1701 /* optional settings for drawing title screens and title messages */
1702 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1703 graphic_info[graphic].fade_mode = parameter[GFX_ARG_FADE_MODE];
1704 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1705 graphic_info[graphic].fade_delay = parameter[GFX_ARG_FADE_DELAY];
1706 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1707 graphic_info[graphic].post_delay = parameter[GFX_ARG_POST_DELAY];
1708 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1709 graphic_info[graphic].auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1710 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1711 graphic_info[graphic].align = parameter[GFX_ARG_ALIGN];
1712 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1713 graphic_info[graphic].valign = parameter[GFX_ARG_VALIGN];
1714 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1715 graphic_info[graphic].sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1718 UPDATE_BUSY_STATE();
1721 static void set_cloned_graphic_parameters(int graphic)
1723 int fallback_graphic = IMG_CHAR_EXCLAM;
1724 int max_num_images = getImageListSize();
1725 int clone_graphic = graphic_info[graphic].clone_from;
1726 int num_references_followed = 1;
1728 while (graphic_info[clone_graphic].clone_from != -1 &&
1729 num_references_followed < max_num_images)
1731 clone_graphic = graphic_info[clone_graphic].clone_from;
1733 num_references_followed++;
1736 if (num_references_followed >= max_num_images)
1738 Error(ERR_INFO_LINE, "-");
1739 Error(ERR_INFO, "warning: error found in config file:");
1740 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1741 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1742 Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1743 Error(ERR_INFO, "custom graphic rejected for this element/action");
1745 if (graphic == fallback_graphic)
1746 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1748 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1749 Error(ERR_INFO_LINE, "-");
1751 graphic_info[graphic] = graphic_info[fallback_graphic];
1755 graphic_info[graphic] = graphic_info[clone_graphic];
1756 graphic_info[graphic].clone_from = clone_graphic;
1760 static void InitGraphicInfo()
1762 int fallback_graphic = IMG_CHAR_EXCLAM;
1763 int num_images = getImageListSize();
1766 /* use image size as default values for width and height for these images */
1767 static int full_size_graphics[] =
1772 IMG_BACKGROUND_ENVELOPE_1,
1773 IMG_BACKGROUND_ENVELOPE_2,
1774 IMG_BACKGROUND_ENVELOPE_3,
1775 IMG_BACKGROUND_ENVELOPE_4,
1776 IMG_BACKGROUND_REQUEST,
1779 IMG_BACKGROUND_TITLE_INITIAL,
1780 IMG_BACKGROUND_TITLE,
1781 IMG_BACKGROUND_MAIN,
1782 IMG_BACKGROUND_LEVELS,
1783 IMG_BACKGROUND_LEVELNR,
1784 IMG_BACKGROUND_SCORES,
1785 IMG_BACKGROUND_EDITOR,
1786 IMG_BACKGROUND_INFO,
1787 IMG_BACKGROUND_INFO_ELEMENTS,
1788 IMG_BACKGROUND_INFO_MUSIC,
1789 IMG_BACKGROUND_INFO_CREDITS,
1790 IMG_BACKGROUND_INFO_PROGRAM,
1791 IMG_BACKGROUND_INFO_VERSION,
1792 IMG_BACKGROUND_INFO_LEVELSET,
1793 IMG_BACKGROUND_SETUP,
1794 IMG_BACKGROUND_PLAYING,
1795 IMG_BACKGROUND_DOOR,
1796 IMG_BACKGROUND_TAPE,
1797 IMG_BACKGROUND_PANEL,
1798 IMG_BACKGROUND_PALETTE,
1799 IMG_BACKGROUND_TOOLBOX,
1801 IMG_TITLESCREEN_INITIAL_1,
1802 IMG_TITLESCREEN_INITIAL_2,
1803 IMG_TITLESCREEN_INITIAL_3,
1804 IMG_TITLESCREEN_INITIAL_4,
1805 IMG_TITLESCREEN_INITIAL_5,
1812 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1,
1813 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2,
1814 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3,
1815 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4,
1816 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5,
1817 IMG_BACKGROUND_TITLEMESSAGE_1,
1818 IMG_BACKGROUND_TITLEMESSAGE_2,
1819 IMG_BACKGROUND_TITLEMESSAGE_3,
1820 IMG_BACKGROUND_TITLEMESSAGE_4,
1821 IMG_BACKGROUND_TITLEMESSAGE_5,
1826 checked_free(graphic_info);
1828 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1831 /* initialize "use_image_size" flag with default value */
1832 for (i = 0; i < num_images; i++)
1833 graphic_info[i].use_image_size = FALSE;
1835 /* initialize "use_image_size" flag from static configuration above */
1836 for (i = 0; full_size_graphics[i] != -1; i++)
1837 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1840 /* first set all graphic paramaters ... */
1841 for (i = 0; i < num_images; i++)
1842 set_graphic_parameters(i);
1844 /* ... then copy these parameters for cloned graphics */
1845 for (i = 0; i < num_images; i++)
1846 if (graphic_info[i].clone_from != -1)
1847 set_cloned_graphic_parameters(i);
1849 for (i = 0; i < num_images; i++)
1854 int first_frame, last_frame;
1855 int src_bitmap_width, src_bitmap_height;
1857 /* now check if no animation frames are outside of the loaded image */
1859 if (graphic_info[i].bitmap == NULL)
1860 continue; /* skip check for optional images that are undefined */
1862 /* get image size (this can differ from the standard element tile size!) */
1863 width = graphic_info[i].width;
1864 height = graphic_info[i].height;
1866 /* get final bitmap size (with scaling, but without small images) */
1867 src_bitmap_width = graphic_info[i].src_image_width;
1868 src_bitmap_height = graphic_info[i].src_image_height;
1870 /* check if first animation frame is inside specified bitmap */
1873 getFixedGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1876 /* this avoids calculating wrong start position for out-of-bounds frame */
1877 src_x = graphic_info[i].src_x;
1878 src_y = graphic_info[i].src_y;
1881 if (src_x < 0 || src_y < 0 ||
1882 src_x + width > src_bitmap_width ||
1883 src_y + height > src_bitmap_height)
1885 Error(ERR_INFO_LINE, "-");
1886 Error(ERR_INFO, "warning: error found in config file:");
1887 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1888 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1889 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1891 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1892 src_x, src_y, src_bitmap_width, src_bitmap_height);
1893 Error(ERR_INFO, "custom graphic rejected for this element/action");
1895 if (i == fallback_graphic)
1896 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1898 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1899 Error(ERR_INFO_LINE, "-");
1901 graphic_info[i] = graphic_info[fallback_graphic];
1904 /* check if last animation frame is inside specified bitmap */
1906 last_frame = graphic_info[i].anim_frames - 1;
1907 getFixedGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1909 if (src_x < 0 || src_y < 0 ||
1910 src_x + width > src_bitmap_width ||
1911 src_y + height > src_bitmap_height)
1913 Error(ERR_INFO_LINE, "-");
1914 Error(ERR_INFO, "warning: error found in config file:");
1915 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1916 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1917 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1919 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1920 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1921 Error(ERR_INFO, "::: %d, %d", width, height);
1922 Error(ERR_INFO, "custom graphic rejected for this element/action");
1924 if (i == fallback_graphic)
1925 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1927 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1928 Error(ERR_INFO_LINE, "-");
1930 graphic_info[i] = graphic_info[fallback_graphic];
1935 static void InitGraphicCompatibilityInfo()
1937 struct FileInfo *fi_global_door =
1938 getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1939 int num_images = getImageListSize();
1942 /* the following compatibility handling is needed for the following case:
1943 versions up to 3.3.0.0 used one large bitmap "global.door" for various
1944 graphics mainly used for door and panel graphics, like editor, tape and
1945 in-game buttons with hard-coded bitmap positions and button sizes; as
1946 these graphics now have individual definitions, redefining "global.door"
1947 to change all these graphics at once like before does not work anymore
1948 (because all those individual definitions still have their default values);
1949 to solve this, remap all those individual definitions that are not
1950 redefined to the new bitmap of "global.door" if it was redefined */
1952 /* special compatibility handling if image "global.door" was redefined */
1953 if (fi_global_door->redefined)
1955 for (i = 0; i < num_images; i++)
1957 struct FileInfo *fi = getImageListEntryFromImageID(i);
1959 /* process only those images that still use the default settings */
1962 /* process all images which default to same image as "global.door" */
1963 if (strEqual(fi->default_filename, fi_global_door->default_filename))
1965 // printf("::: special treatment needed for token '%s'\n", fi->token);
1967 graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
1974 InitGraphicCompatibilityInfo_Doors();
1981 int *width, *height;
1986 { IMG_DOOR_1_WING_LEFT, &door_1.width, &door_1.height, FALSE },
1987 { IMG_DOOR_1_WING_RIGHT, &door_1.width, &door_1.height, TRUE },
1988 { IMG_DOOR_2_WING_LEFT, &door_2.width, &door_2.height, FALSE },
1989 { IMG_DOOR_2_WING_RIGHT, &door_2.width, &door_2.height, TRUE },
1991 { 0, NULL, NULL, FALSE }
1994 for (i = 0; doors[i].graphic != 0; i++)
1996 int graphic = doors[i].graphic;
1997 int *width = doors[i].width;
1998 int *height = doors[i].height;
1999 boolean right_wing = doors[i].right_wing;
2001 struct FileInfo *fi = getImageListEntryFromImageID(graphic);
2002 struct GraphicInfo *g = &graphic_info[graphic];
2008 // correct start position for right wing of "standard" door graphic
2010 g->src_x += g->width - *width;
2016 g->height = *height;
2022 for (i = 0; i < num_images; i++)
2024 struct FileInfo *fi = getImageListEntryFromImageID(i);
2026 if (i == IMG_GLOBAL_DOOR)
2028 printf("::: %s, %s, %d\n",
2029 fi->default_filename,
2037 static void InitElementSoundInfo()
2039 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
2040 int num_property_mappings = getSoundListPropertyMappingSize();
2043 /* set values to -1 to identify later as "uninitialized" values */
2044 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2045 for (act = 0; act < NUM_ACTIONS; act++)
2046 element_info[i].sound[act] = -1;
2048 /* initialize element/sound mapping from static configuration */
2049 for (i = 0; element_to_sound[i].element > -1; i++)
2051 int element = element_to_sound[i].element;
2052 int action = element_to_sound[i].action;
2053 int sound = element_to_sound[i].sound;
2054 boolean is_class = element_to_sound[i].is_class;
2057 action = ACTION_DEFAULT;
2060 element_info[element].sound[action] = sound;
2062 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2063 if (strEqual(element_info[j].class_name,
2064 element_info[element].class_name))
2065 element_info[j].sound[action] = sound;
2068 /* initialize element class/sound mapping from dynamic configuration */
2069 for (i = 0; i < num_property_mappings; i++)
2071 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
2072 int action = property_mapping[i].ext1_index;
2073 int sound = property_mapping[i].artwork_index;
2075 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
2079 action = ACTION_DEFAULT;
2081 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2082 if (strEqual(element_info[j].class_name,
2083 element_info[element_class].class_name))
2084 element_info[j].sound[action] = sound;
2087 /* initialize element/sound mapping from dynamic configuration */
2088 for (i = 0; i < num_property_mappings; i++)
2090 int element = property_mapping[i].base_index;
2091 int action = property_mapping[i].ext1_index;
2092 int sound = property_mapping[i].artwork_index;
2094 if (element >= MAX_NUM_ELEMENTS)
2098 action = ACTION_DEFAULT;
2100 element_info[element].sound[action] = sound;
2103 /* now set all '-1' values to element specific default values */
2104 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2106 for (act = 0; act < NUM_ACTIONS; act++)
2108 /* generic default action sound (defined by "[default]" directive) */
2109 int default_action_sound = element_info[EL_DEFAULT].sound[act];
2111 /* look for special default action sound (classic game specific) */
2112 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
2113 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
2114 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
2115 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
2116 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
2117 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
2119 /* !!! there's no such thing as a "default action sound" !!! */
2121 /* look for element specific default sound (independent from action) */
2122 if (element_info[i].sound[ACTION_DEFAULT] != -1)
2123 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
2127 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
2128 /* !!! make this better !!! */
2129 if (i == EL_EMPTY_SPACE)
2130 default_action_sound = element_info[EL_DEFAULT].sound[act];
2133 /* no sound for this specific action -- use default action sound */
2134 if (element_info[i].sound[act] == -1)
2135 element_info[i].sound[act] = default_action_sound;
2139 /* copy sound settings to some elements that are only stored in level file
2140 in native R'n'D levels, but are used by game engine in native EM levels */
2141 for (i = 0; copy_properties[i][0] != -1; i++)
2142 for (j = 1; j <= 4; j++)
2143 for (act = 0; act < NUM_ACTIONS; act++)
2144 element_info[copy_properties[i][j]].sound[act] =
2145 element_info[copy_properties[i][0]].sound[act];
2148 static void InitGameModeSoundInfo()
2152 /* set values to -1 to identify later as "uninitialized" values */
2153 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2156 /* initialize gamemode/sound mapping from static configuration */
2157 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
2159 int gamemode = gamemode_to_sound[i].gamemode;
2160 int sound = gamemode_to_sound[i].sound;
2163 gamemode = GAME_MODE_DEFAULT;
2165 menu.sound[gamemode] = sound;
2168 /* now set all '-1' values to levelset specific default values */
2169 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2170 if (menu.sound[i] == -1)
2171 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
2174 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2175 if (menu.sound[i] != -1)
2176 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
2180 static void set_sound_parameters(int sound, char **parameter_raw)
2182 int parameter[NUM_SND_ARGS];
2185 /* get integer values from string parameters */
2186 for (i = 0; i < NUM_SND_ARGS; i++)
2188 get_parameter_value(parameter_raw[i],
2189 sound_config_suffix[i].token,
2190 sound_config_suffix[i].type);
2192 /* explicit loop mode setting in configuration overrides default value */
2193 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2194 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
2196 /* sound volume to change the original volume when loading the sound file */
2197 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
2199 /* sound priority to give certain sounds a higher or lower priority */
2200 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
2203 static void InitSoundInfo()
2205 int *sound_effect_properties;
2206 int num_sounds = getSoundListSize();
2209 checked_free(sound_info);
2211 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
2212 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
2214 /* initialize sound effect for all elements to "no sound" */
2215 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2216 for (j = 0; j < NUM_ACTIONS; j++)
2217 element_info[i].sound[j] = SND_UNDEFINED;
2219 for (i = 0; i < num_sounds; i++)
2221 struct FileInfo *sound = getSoundListEntry(i);
2222 int len_effect_text = strlen(sound->token);
2224 sound_effect_properties[i] = ACTION_OTHER;
2225 sound_info[i].loop = FALSE; /* default: play sound only once */
2228 printf("::: sound %d: '%s'\n", i, sound->token);
2231 /* determine all loop sounds and identify certain sound classes */
2233 for (j = 0; element_action_info[j].suffix; j++)
2235 int len_action_text = strlen(element_action_info[j].suffix);
2237 if (len_action_text < len_effect_text &&
2238 strEqual(&sound->token[len_effect_text - len_action_text],
2239 element_action_info[j].suffix))
2241 sound_effect_properties[i] = element_action_info[j].value;
2242 sound_info[i].loop = element_action_info[j].is_loop_sound;
2248 /* associate elements and some selected sound actions */
2250 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2252 if (element_info[j].class_name)
2254 int len_class_text = strlen(element_info[j].class_name);
2256 if (len_class_text + 1 < len_effect_text &&
2257 strncmp(sound->token,
2258 element_info[j].class_name, len_class_text) == 0 &&
2259 sound->token[len_class_text] == '.')
2261 int sound_action_value = sound_effect_properties[i];
2263 element_info[j].sound[sound_action_value] = i;
2268 set_sound_parameters(i, sound->parameter);
2271 free(sound_effect_properties);
2274 static void InitGameModeMusicInfo()
2276 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
2277 int num_property_mappings = getMusicListPropertyMappingSize();
2278 int default_levelset_music = -1;
2281 /* set values to -1 to identify later as "uninitialized" values */
2282 for (i = 0; i < MAX_LEVELS; i++)
2283 levelset.music[i] = -1;
2284 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2287 /* initialize gamemode/music mapping from static configuration */
2288 for (i = 0; gamemode_to_music[i].music > -1; i++)
2290 int gamemode = gamemode_to_music[i].gamemode;
2291 int music = gamemode_to_music[i].music;
2294 printf("::: gamemode == %d, music == %d\n", gamemode, music);
2298 gamemode = GAME_MODE_DEFAULT;
2300 menu.music[gamemode] = music;
2303 /* initialize gamemode/music mapping from dynamic configuration */
2304 for (i = 0; i < num_property_mappings; i++)
2306 int prefix = property_mapping[i].base_index;
2307 int gamemode = property_mapping[i].ext1_index;
2308 int level = property_mapping[i].ext2_index;
2309 int music = property_mapping[i].artwork_index;
2312 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
2313 prefix, gamemode, level, music);
2316 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
2320 gamemode = GAME_MODE_DEFAULT;
2322 /* level specific music only allowed for in-game music */
2323 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
2324 gamemode = GAME_MODE_PLAYING;
2329 default_levelset_music = music;
2332 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
2333 levelset.music[level] = music;
2334 if (gamemode != GAME_MODE_PLAYING)
2335 menu.music[gamemode] = music;
2338 /* now set all '-1' values to menu specific default values */
2339 /* (undefined values of "levelset.music[]" might stay at "-1" to
2340 allow dynamic selection of music files from music directory!) */
2341 for (i = 0; i < MAX_LEVELS; i++)
2342 if (levelset.music[i] == -1)
2343 levelset.music[i] = default_levelset_music;
2344 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2345 if (menu.music[i] == -1)
2346 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
2349 for (i = 0; i < MAX_LEVELS; i++)
2350 if (levelset.music[i] != -1)
2351 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
2352 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2353 if (menu.music[i] != -1)
2354 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
2358 static void set_music_parameters(int music, char **parameter_raw)
2360 int parameter[NUM_MUS_ARGS];
2363 /* get integer values from string parameters */
2364 for (i = 0; i < NUM_MUS_ARGS; i++)
2366 get_parameter_value(parameter_raw[i],
2367 music_config_suffix[i].token,
2368 music_config_suffix[i].type);
2370 /* explicit loop mode setting in configuration overrides default value */
2371 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2372 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
2375 static void InitMusicInfo()
2377 int num_music = getMusicListSize();
2380 checked_free(music_info);
2382 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
2384 for (i = 0; i < num_music; i++)
2386 struct FileInfo *music = getMusicListEntry(i);
2387 int len_music_text = strlen(music->token);
2389 music_info[i].loop = TRUE; /* default: play music in loop mode */
2391 /* determine all loop music */
2393 for (j = 0; music_prefix_info[j].prefix; j++)
2395 int len_prefix_text = strlen(music_prefix_info[j].prefix);
2397 if (len_prefix_text < len_music_text &&
2398 strncmp(music->token,
2399 music_prefix_info[j].prefix, len_prefix_text) == 0)
2401 music_info[i].loop = music_prefix_info[j].is_loop_music;
2407 set_music_parameters(i, music->parameter);
2411 static void ReinitializeGraphics()
2413 print_timestamp_init("ReinitializeGraphics");
2415 #if NEW_GAME_TILESIZE
2416 InitGfxTileSizeInfo(game.tile_size, TILESIZE);
2419 InitGraphicInfo(); /* graphic properties mapping */
2420 print_timestamp_time("InitGraphicInfo");
2421 InitElementGraphicInfo(); /* element game graphic mapping */
2422 print_timestamp_time("InitElementGraphicInfo");
2423 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
2424 print_timestamp_time("InitElementSpecialGraphicInfo");
2426 InitElementSmallImages(); /* scale elements to all needed sizes */
2427 print_timestamp_time("InitElementSmallImages");
2428 InitScaledImages(); /* scale all other images, if needed */
2429 print_timestamp_time("InitScaledImages");
2430 InitFontGraphicInfo(); /* initialize text drawing functions */
2431 print_timestamp_time("InitFontGraphicInfo");
2433 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
2434 print_timestamp_time("InitGraphicInfo_EM");
2436 InitGraphicCompatibilityInfo();
2437 print_timestamp_time("InitGraphicCompatibilityInfo");
2439 SetMainBackgroundImage(IMG_BACKGROUND);
2440 print_timestamp_time("SetMainBackgroundImage");
2441 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2442 print_timestamp_time("SetDoorBackgroundImage");
2445 print_timestamp_time("InitGadgets");
2447 print_timestamp_time("InitToons");
2449 print_timestamp_time("InitDoors");
2451 print_timestamp_done("ReinitializeGraphics");
2454 static void ReinitializeSounds()
2456 InitSoundInfo(); /* sound properties mapping */
2457 InitElementSoundInfo(); /* element game sound mapping */
2458 InitGameModeSoundInfo(); /* game mode sound mapping */
2460 InitPlayLevelSound(); /* internal game sound settings */
2463 static void ReinitializeMusic()
2465 InitMusicInfo(); /* music properties mapping */
2466 InitGameModeMusicInfo(); /* game mode music mapping */
2469 static int get_special_property_bit(int element, int property_bit_nr)
2471 struct PropertyBitInfo
2477 static struct PropertyBitInfo pb_can_move_into_acid[] =
2479 /* the player may be able fall into acid when gravity is activated */
2484 { EL_SP_MURPHY, 0 },
2485 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2487 /* all elements that can move may be able to also move into acid */
2490 { EL_BUG_RIGHT, 1 },
2493 { EL_SPACESHIP, 2 },
2494 { EL_SPACESHIP_LEFT, 2 },
2495 { EL_SPACESHIP_RIGHT, 2 },
2496 { EL_SPACESHIP_UP, 2 },
2497 { EL_SPACESHIP_DOWN, 2 },
2498 { EL_BD_BUTTERFLY, 3 },
2499 { EL_BD_BUTTERFLY_LEFT, 3 },
2500 { EL_BD_BUTTERFLY_RIGHT, 3 },
2501 { EL_BD_BUTTERFLY_UP, 3 },
2502 { EL_BD_BUTTERFLY_DOWN, 3 },
2503 { EL_BD_FIREFLY, 4 },
2504 { EL_BD_FIREFLY_LEFT, 4 },
2505 { EL_BD_FIREFLY_RIGHT, 4 },
2506 { EL_BD_FIREFLY_UP, 4 },
2507 { EL_BD_FIREFLY_DOWN, 4 },
2509 { EL_YAMYAM_LEFT, 5 },
2510 { EL_YAMYAM_RIGHT, 5 },
2511 { EL_YAMYAM_UP, 5 },
2512 { EL_YAMYAM_DOWN, 5 },
2513 { EL_DARK_YAMYAM, 6 },
2516 { EL_PACMAN_LEFT, 8 },
2517 { EL_PACMAN_RIGHT, 8 },
2518 { EL_PACMAN_UP, 8 },
2519 { EL_PACMAN_DOWN, 8 },
2521 { EL_MOLE_LEFT, 9 },
2522 { EL_MOLE_RIGHT, 9 },
2524 { EL_MOLE_DOWN, 9 },
2528 { EL_SATELLITE, 13 },
2529 { EL_SP_SNIKSNAK, 14 },
2530 { EL_SP_ELECTRON, 15 },
2533 { EL_EMC_ANDROID, 18 },
2538 static struct PropertyBitInfo pb_dont_collide_with[] =
2540 { EL_SP_SNIKSNAK, 0 },
2541 { EL_SP_ELECTRON, 1 },
2549 struct PropertyBitInfo *pb_info;
2552 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2553 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2558 struct PropertyBitInfo *pb_info = NULL;
2561 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2562 if (pb_definition[i].bit_nr == property_bit_nr)
2563 pb_info = pb_definition[i].pb_info;
2565 if (pb_info == NULL)
2568 for (i = 0; pb_info[i].element != -1; i++)
2569 if (pb_info[i].element == element)
2570 return pb_info[i].bit_nr;
2575 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2576 boolean property_value)
2578 int bit_nr = get_special_property_bit(element, property_bit_nr);
2583 *bitfield |= (1 << bit_nr);
2585 *bitfield &= ~(1 << bit_nr);
2589 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2591 int bit_nr = get_special_property_bit(element, property_bit_nr);
2594 return ((*bitfield & (1 << bit_nr)) != 0);
2599 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2601 static int group_nr;
2602 static struct ElementGroupInfo *group;
2603 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2606 if (actual_group == NULL) /* not yet initialized */
2609 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
2611 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2612 group_element - EL_GROUP_START + 1);
2614 /* replace element which caused too deep recursion by question mark */
2615 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2620 if (recursion_depth == 0) /* initialization */
2622 group = actual_group;
2623 group_nr = GROUP_NR(group_element);
2625 group->num_elements_resolved = 0;
2626 group->choice_pos = 0;
2628 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2629 element_info[i].in_group[group_nr] = FALSE;
2632 for (i = 0; i < actual_group->num_elements; i++)
2634 int element = actual_group->element[i];
2636 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2639 if (IS_GROUP_ELEMENT(element))
2640 ResolveGroupElementExt(element, recursion_depth + 1);
2643 group->element_resolved[group->num_elements_resolved++] = element;
2644 element_info[element].in_group[group_nr] = TRUE;
2649 void ResolveGroupElement(int group_element)
2651 ResolveGroupElementExt(group_element, 0);
2654 void InitElementPropertiesStatic()
2656 static boolean clipboard_elements_initialized = FALSE;
2658 static int ep_diggable[] =
2663 EL_SP_BUGGY_BASE_ACTIVATING,
2666 EL_INVISIBLE_SAND_ACTIVE,
2669 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2670 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2675 EL_SP_BUGGY_BASE_ACTIVE,
2682 static int ep_collectible_only[] =
2704 EL_DYNABOMB_INCREASE_NUMBER,
2705 EL_DYNABOMB_INCREASE_SIZE,
2706 EL_DYNABOMB_INCREASE_POWER,
2724 /* !!! handle separately !!! */
2725 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2731 static int ep_dont_run_into[] =
2733 /* same elements as in 'ep_dont_touch' */
2739 /* same elements as in 'ep_dont_collide_with' */
2751 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2756 EL_SP_BUGGY_BASE_ACTIVE,
2763 static int ep_dont_collide_with[] =
2765 /* same elements as in 'ep_dont_touch' */
2782 static int ep_dont_touch[] =
2792 static int ep_indestructible[] =
2796 EL_ACID_POOL_TOPLEFT,
2797 EL_ACID_POOL_TOPRIGHT,
2798 EL_ACID_POOL_BOTTOMLEFT,
2799 EL_ACID_POOL_BOTTOM,
2800 EL_ACID_POOL_BOTTOMRIGHT,
2801 EL_SP_HARDWARE_GRAY,
2802 EL_SP_HARDWARE_GREEN,
2803 EL_SP_HARDWARE_BLUE,
2805 EL_SP_HARDWARE_YELLOW,
2806 EL_SP_HARDWARE_BASE_1,
2807 EL_SP_HARDWARE_BASE_2,
2808 EL_SP_HARDWARE_BASE_3,
2809 EL_SP_HARDWARE_BASE_4,
2810 EL_SP_HARDWARE_BASE_5,
2811 EL_SP_HARDWARE_BASE_6,
2812 EL_INVISIBLE_STEELWALL,
2813 EL_INVISIBLE_STEELWALL_ACTIVE,
2814 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2815 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2816 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2817 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2818 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2819 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2820 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2821 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2822 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2823 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2824 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2825 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2827 EL_LIGHT_SWITCH_ACTIVE,
2828 EL_SIGN_EXCLAMATION,
2829 EL_SIGN_RADIOACTIVITY,
2836 EL_SIGN_ENTRY_FORBIDDEN,
2837 EL_SIGN_EMERGENCY_EXIT,
2845 EL_STEEL_EXIT_CLOSED,
2847 EL_STEEL_EXIT_OPENING,
2848 EL_STEEL_EXIT_CLOSING,
2849 EL_EM_STEEL_EXIT_CLOSED,
2850 EL_EM_STEEL_EXIT_OPEN,
2851 EL_EM_STEEL_EXIT_OPENING,
2852 EL_EM_STEEL_EXIT_CLOSING,
2853 EL_DC_STEELWALL_1_LEFT,
2854 EL_DC_STEELWALL_1_RIGHT,
2855 EL_DC_STEELWALL_1_TOP,
2856 EL_DC_STEELWALL_1_BOTTOM,
2857 EL_DC_STEELWALL_1_HORIZONTAL,
2858 EL_DC_STEELWALL_1_VERTICAL,
2859 EL_DC_STEELWALL_1_TOPLEFT,
2860 EL_DC_STEELWALL_1_TOPRIGHT,
2861 EL_DC_STEELWALL_1_BOTTOMLEFT,
2862 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2863 EL_DC_STEELWALL_1_TOPLEFT_2,
2864 EL_DC_STEELWALL_1_TOPRIGHT_2,
2865 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2866 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2867 EL_DC_STEELWALL_2_LEFT,
2868 EL_DC_STEELWALL_2_RIGHT,
2869 EL_DC_STEELWALL_2_TOP,
2870 EL_DC_STEELWALL_2_BOTTOM,
2871 EL_DC_STEELWALL_2_HORIZONTAL,
2872 EL_DC_STEELWALL_2_VERTICAL,
2873 EL_DC_STEELWALL_2_MIDDLE,
2874 EL_DC_STEELWALL_2_SINGLE,
2875 EL_STEELWALL_SLIPPERY,
2889 EL_GATE_1_GRAY_ACTIVE,
2890 EL_GATE_2_GRAY_ACTIVE,
2891 EL_GATE_3_GRAY_ACTIVE,
2892 EL_GATE_4_GRAY_ACTIVE,
2901 EL_EM_GATE_1_GRAY_ACTIVE,
2902 EL_EM_GATE_2_GRAY_ACTIVE,
2903 EL_EM_GATE_3_GRAY_ACTIVE,
2904 EL_EM_GATE_4_GRAY_ACTIVE,
2913 EL_EMC_GATE_5_GRAY_ACTIVE,
2914 EL_EMC_GATE_6_GRAY_ACTIVE,
2915 EL_EMC_GATE_7_GRAY_ACTIVE,
2916 EL_EMC_GATE_8_GRAY_ACTIVE,
2918 EL_DC_GATE_WHITE_GRAY,
2919 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2920 EL_DC_GATE_FAKE_GRAY,
2922 EL_SWITCHGATE_OPENING,
2923 EL_SWITCHGATE_CLOSED,
2924 EL_SWITCHGATE_CLOSING,
2926 EL_DC_SWITCHGATE_SWITCH_UP,
2927 EL_DC_SWITCHGATE_SWITCH_DOWN,
2930 EL_TIMEGATE_OPENING,
2932 EL_TIMEGATE_CLOSING,
2934 EL_DC_TIMEGATE_SWITCH,
2935 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2940 EL_TUBE_VERTICAL_LEFT,
2941 EL_TUBE_VERTICAL_RIGHT,
2942 EL_TUBE_HORIZONTAL_UP,
2943 EL_TUBE_HORIZONTAL_DOWN,
2948 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2949 EL_EXPANDABLE_STEELWALL_VERTICAL,
2950 EL_EXPANDABLE_STEELWALL_ANY,
2955 static int ep_slippery[] =
2969 EL_ROBOT_WHEEL_ACTIVE,
2975 EL_ACID_POOL_TOPLEFT,
2976 EL_ACID_POOL_TOPRIGHT,
2986 EL_STEELWALL_SLIPPERY,
2989 EL_EMC_WALL_SLIPPERY_1,
2990 EL_EMC_WALL_SLIPPERY_2,
2991 EL_EMC_WALL_SLIPPERY_3,
2992 EL_EMC_WALL_SLIPPERY_4,
2994 EL_EMC_MAGIC_BALL_ACTIVE,
2999 static int ep_can_change[] =
3004 static int ep_can_move[] =
3006 /* same elements as in 'pb_can_move_into_acid' */
3029 static int ep_can_fall[] =
3043 EL_QUICKSAND_FAST_FULL,
3045 EL_BD_MAGIC_WALL_FULL,
3046 EL_DC_MAGIC_WALL_FULL,
3060 static int ep_can_smash_player[] =
3086 static int ep_can_smash_enemies[] =
3095 static int ep_can_smash_everything[] =
3104 static int ep_explodes_by_fire[] =
3106 /* same elements as in 'ep_explodes_impact' */
3111 /* same elements as in 'ep_explodes_smashed' */
3121 EL_EM_DYNAMITE_ACTIVE,
3122 EL_DYNABOMB_PLAYER_1_ACTIVE,
3123 EL_DYNABOMB_PLAYER_2_ACTIVE,
3124 EL_DYNABOMB_PLAYER_3_ACTIVE,
3125 EL_DYNABOMB_PLAYER_4_ACTIVE,
3126 EL_DYNABOMB_INCREASE_NUMBER,
3127 EL_DYNABOMB_INCREASE_SIZE,
3128 EL_DYNABOMB_INCREASE_POWER,
3129 EL_SP_DISK_RED_ACTIVE,
3143 static int ep_explodes_smashed[] =
3145 /* same elements as in 'ep_explodes_impact' */
3159 static int ep_explodes_impact[] =
3168 static int ep_walkable_over[] =
3172 EL_SOKOBAN_FIELD_EMPTY,
3181 EL_EM_STEEL_EXIT_OPEN,
3183 EL_EM_STEEL_EXIT_OPENING,
3193 EL_GATE_1_GRAY_ACTIVE,
3194 EL_GATE_2_GRAY_ACTIVE,
3195 EL_GATE_3_GRAY_ACTIVE,
3196 EL_GATE_4_GRAY_ACTIVE,
3204 static int ep_walkable_inside[] =
3209 EL_TUBE_VERTICAL_LEFT,
3210 EL_TUBE_VERTICAL_RIGHT,
3211 EL_TUBE_HORIZONTAL_UP,
3212 EL_TUBE_HORIZONTAL_DOWN,
3221 static int ep_walkable_under[] =
3226 static int ep_passable_over[] =
3236 EL_EM_GATE_1_GRAY_ACTIVE,
3237 EL_EM_GATE_2_GRAY_ACTIVE,
3238 EL_EM_GATE_3_GRAY_ACTIVE,
3239 EL_EM_GATE_4_GRAY_ACTIVE,
3248 EL_EMC_GATE_5_GRAY_ACTIVE,
3249 EL_EMC_GATE_6_GRAY_ACTIVE,
3250 EL_EMC_GATE_7_GRAY_ACTIVE,
3251 EL_EMC_GATE_8_GRAY_ACTIVE,
3253 EL_DC_GATE_WHITE_GRAY,
3254 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3261 static int ep_passable_inside[] =
3267 EL_SP_PORT_HORIZONTAL,
3268 EL_SP_PORT_VERTICAL,
3270 EL_SP_GRAVITY_PORT_LEFT,
3271 EL_SP_GRAVITY_PORT_RIGHT,
3272 EL_SP_GRAVITY_PORT_UP,
3273 EL_SP_GRAVITY_PORT_DOWN,
3274 EL_SP_GRAVITY_ON_PORT_LEFT,
3275 EL_SP_GRAVITY_ON_PORT_RIGHT,
3276 EL_SP_GRAVITY_ON_PORT_UP,
3277 EL_SP_GRAVITY_ON_PORT_DOWN,
3278 EL_SP_GRAVITY_OFF_PORT_LEFT,
3279 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3280 EL_SP_GRAVITY_OFF_PORT_UP,
3281 EL_SP_GRAVITY_OFF_PORT_DOWN,
3286 static int ep_passable_under[] =
3291 static int ep_droppable[] =
3296 static int ep_explodes_1x1_old[] =
3301 static int ep_pushable[] =
3313 EL_SOKOBAN_FIELD_FULL,
3322 static int ep_explodes_cross_old[] =
3327 static int ep_protected[] =
3329 /* same elements as in 'ep_walkable_inside' */
3333 EL_TUBE_VERTICAL_LEFT,
3334 EL_TUBE_VERTICAL_RIGHT,
3335 EL_TUBE_HORIZONTAL_UP,
3336 EL_TUBE_HORIZONTAL_DOWN,
3342 /* same elements as in 'ep_passable_over' */
3351 EL_EM_GATE_1_GRAY_ACTIVE,
3352 EL_EM_GATE_2_GRAY_ACTIVE,
3353 EL_EM_GATE_3_GRAY_ACTIVE,
3354 EL_EM_GATE_4_GRAY_ACTIVE,
3363 EL_EMC_GATE_5_GRAY_ACTIVE,
3364 EL_EMC_GATE_6_GRAY_ACTIVE,
3365 EL_EMC_GATE_7_GRAY_ACTIVE,
3366 EL_EMC_GATE_8_GRAY_ACTIVE,
3368 EL_DC_GATE_WHITE_GRAY,
3369 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3373 /* same elements as in 'ep_passable_inside' */
3378 EL_SP_PORT_HORIZONTAL,
3379 EL_SP_PORT_VERTICAL,
3381 EL_SP_GRAVITY_PORT_LEFT,
3382 EL_SP_GRAVITY_PORT_RIGHT,
3383 EL_SP_GRAVITY_PORT_UP,
3384 EL_SP_GRAVITY_PORT_DOWN,
3385 EL_SP_GRAVITY_ON_PORT_LEFT,
3386 EL_SP_GRAVITY_ON_PORT_RIGHT,
3387 EL_SP_GRAVITY_ON_PORT_UP,
3388 EL_SP_GRAVITY_ON_PORT_DOWN,
3389 EL_SP_GRAVITY_OFF_PORT_LEFT,
3390 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3391 EL_SP_GRAVITY_OFF_PORT_UP,
3392 EL_SP_GRAVITY_OFF_PORT_DOWN,
3397 static int ep_throwable[] =
3402 static int ep_can_explode[] =
3404 /* same elements as in 'ep_explodes_impact' */
3409 /* same elements as in 'ep_explodes_smashed' */
3415 /* elements that can explode by explosion or by dragonfire */
3419 EL_EM_DYNAMITE_ACTIVE,
3420 EL_DYNABOMB_PLAYER_1_ACTIVE,
3421 EL_DYNABOMB_PLAYER_2_ACTIVE,
3422 EL_DYNABOMB_PLAYER_3_ACTIVE,
3423 EL_DYNABOMB_PLAYER_4_ACTIVE,
3424 EL_DYNABOMB_INCREASE_NUMBER,
3425 EL_DYNABOMB_INCREASE_SIZE,
3426 EL_DYNABOMB_INCREASE_POWER,
3427 EL_SP_DISK_RED_ACTIVE,
3435 /* elements that can explode only by explosion */
3441 static int ep_gravity_reachable[] =
3447 EL_INVISIBLE_SAND_ACTIVE,
3452 EL_SP_PORT_HORIZONTAL,
3453 EL_SP_PORT_VERTICAL,
3455 EL_SP_GRAVITY_PORT_LEFT,
3456 EL_SP_GRAVITY_PORT_RIGHT,
3457 EL_SP_GRAVITY_PORT_UP,
3458 EL_SP_GRAVITY_PORT_DOWN,
3459 EL_SP_GRAVITY_ON_PORT_LEFT,
3460 EL_SP_GRAVITY_ON_PORT_RIGHT,
3461 EL_SP_GRAVITY_ON_PORT_UP,
3462 EL_SP_GRAVITY_ON_PORT_DOWN,
3463 EL_SP_GRAVITY_OFF_PORT_LEFT,
3464 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3465 EL_SP_GRAVITY_OFF_PORT_UP,
3466 EL_SP_GRAVITY_OFF_PORT_DOWN,
3472 static int ep_player[] =
3479 EL_SOKOBAN_FIELD_PLAYER,
3485 static int ep_can_pass_magic_wall[] =
3499 static int ep_can_pass_dc_magic_wall[] =
3515 static int ep_switchable[] =
3519 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3520 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3521 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3522 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3523 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3524 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3525 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3526 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3527 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3528 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3529 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3530 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3531 EL_SWITCHGATE_SWITCH_UP,
3532 EL_SWITCHGATE_SWITCH_DOWN,
3533 EL_DC_SWITCHGATE_SWITCH_UP,
3534 EL_DC_SWITCHGATE_SWITCH_DOWN,
3536 EL_LIGHT_SWITCH_ACTIVE,
3538 EL_DC_TIMEGATE_SWITCH,
3539 EL_BALLOON_SWITCH_LEFT,
3540 EL_BALLOON_SWITCH_RIGHT,
3541 EL_BALLOON_SWITCH_UP,
3542 EL_BALLOON_SWITCH_DOWN,
3543 EL_BALLOON_SWITCH_ANY,
3544 EL_BALLOON_SWITCH_NONE,
3547 EL_EMC_MAGIC_BALL_SWITCH,
3548 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3553 static int ep_bd_element[] =
3587 static int ep_sp_element[] =
3589 /* should always be valid */
3592 /* standard classic Supaplex elements */
3599 EL_SP_HARDWARE_GRAY,
3607 EL_SP_GRAVITY_PORT_RIGHT,
3608 EL_SP_GRAVITY_PORT_DOWN,
3609 EL_SP_GRAVITY_PORT_LEFT,
3610 EL_SP_GRAVITY_PORT_UP,
3615 EL_SP_PORT_VERTICAL,
3616 EL_SP_PORT_HORIZONTAL,
3622 EL_SP_HARDWARE_BASE_1,
3623 EL_SP_HARDWARE_GREEN,
3624 EL_SP_HARDWARE_BLUE,
3626 EL_SP_HARDWARE_YELLOW,
3627 EL_SP_HARDWARE_BASE_2,
3628 EL_SP_HARDWARE_BASE_3,
3629 EL_SP_HARDWARE_BASE_4,
3630 EL_SP_HARDWARE_BASE_5,
3631 EL_SP_HARDWARE_BASE_6,
3635 /* additional elements that appeared in newer Supaplex levels */
3638 /* additional gravity port elements (not switching, but setting gravity) */
3639 EL_SP_GRAVITY_ON_PORT_LEFT,
3640 EL_SP_GRAVITY_ON_PORT_RIGHT,
3641 EL_SP_GRAVITY_ON_PORT_UP,
3642 EL_SP_GRAVITY_ON_PORT_DOWN,
3643 EL_SP_GRAVITY_OFF_PORT_LEFT,
3644 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3645 EL_SP_GRAVITY_OFF_PORT_UP,
3646 EL_SP_GRAVITY_OFF_PORT_DOWN,
3648 /* more than one Murphy in a level results in an inactive clone */
3651 /* runtime Supaplex elements */
3652 EL_SP_DISK_RED_ACTIVE,
3653 EL_SP_TERMINAL_ACTIVE,
3654 EL_SP_BUGGY_BASE_ACTIVATING,
3655 EL_SP_BUGGY_BASE_ACTIVE,
3662 static int ep_sb_element[] =
3667 EL_SOKOBAN_FIELD_EMPTY,
3668 EL_SOKOBAN_FIELD_FULL,
3669 EL_SOKOBAN_FIELD_PLAYER,
3674 EL_INVISIBLE_STEELWALL,
3679 static int ep_gem[] =
3691 static int ep_food_dark_yamyam[] =
3719 static int ep_food_penguin[] =
3733 static int ep_food_pig[] =
3745 static int ep_historic_wall[] =
3756 EL_GATE_1_GRAY_ACTIVE,
3757 EL_GATE_2_GRAY_ACTIVE,
3758 EL_GATE_3_GRAY_ACTIVE,
3759 EL_GATE_4_GRAY_ACTIVE,
3768 EL_EM_GATE_1_GRAY_ACTIVE,
3769 EL_EM_GATE_2_GRAY_ACTIVE,
3770 EL_EM_GATE_3_GRAY_ACTIVE,
3771 EL_EM_GATE_4_GRAY_ACTIVE,
3778 EL_EXPANDABLE_WALL_HORIZONTAL,
3779 EL_EXPANDABLE_WALL_VERTICAL,
3780 EL_EXPANDABLE_WALL_ANY,
3781 EL_EXPANDABLE_WALL_GROWING,
3782 EL_BD_EXPANDABLE_WALL,
3789 EL_SP_HARDWARE_GRAY,
3790 EL_SP_HARDWARE_GREEN,
3791 EL_SP_HARDWARE_BLUE,
3793 EL_SP_HARDWARE_YELLOW,
3794 EL_SP_HARDWARE_BASE_1,
3795 EL_SP_HARDWARE_BASE_2,
3796 EL_SP_HARDWARE_BASE_3,
3797 EL_SP_HARDWARE_BASE_4,
3798 EL_SP_HARDWARE_BASE_5,
3799 EL_SP_HARDWARE_BASE_6,
3801 EL_SP_TERMINAL_ACTIVE,
3804 EL_INVISIBLE_STEELWALL,
3805 EL_INVISIBLE_STEELWALL_ACTIVE,
3807 EL_INVISIBLE_WALL_ACTIVE,
3808 EL_STEELWALL_SLIPPERY,
3825 static int ep_historic_solid[] =
3829 EL_EXPANDABLE_WALL_HORIZONTAL,
3830 EL_EXPANDABLE_WALL_VERTICAL,
3831 EL_EXPANDABLE_WALL_ANY,
3832 EL_BD_EXPANDABLE_WALL,
3845 EL_QUICKSAND_FILLING,
3846 EL_QUICKSAND_EMPTYING,
3848 EL_MAGIC_WALL_ACTIVE,
3849 EL_MAGIC_WALL_EMPTYING,
3850 EL_MAGIC_WALL_FILLING,
3854 EL_BD_MAGIC_WALL_ACTIVE,
3855 EL_BD_MAGIC_WALL_EMPTYING,
3856 EL_BD_MAGIC_WALL_FULL,
3857 EL_BD_MAGIC_WALL_FILLING,
3858 EL_BD_MAGIC_WALL_DEAD,
3867 EL_SP_TERMINAL_ACTIVE,
3871 EL_INVISIBLE_WALL_ACTIVE,
3872 EL_SWITCHGATE_SWITCH_UP,
3873 EL_SWITCHGATE_SWITCH_DOWN,
3874 EL_DC_SWITCHGATE_SWITCH_UP,
3875 EL_DC_SWITCHGATE_SWITCH_DOWN,
3877 EL_TIMEGATE_SWITCH_ACTIVE,
3878 EL_DC_TIMEGATE_SWITCH,
3879 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3891 /* the following elements are a direct copy of "indestructible" elements,
3892 except "EL_ACID", which is "indestructible", but not "solid"! */
3897 EL_ACID_POOL_TOPLEFT,
3898 EL_ACID_POOL_TOPRIGHT,
3899 EL_ACID_POOL_BOTTOMLEFT,
3900 EL_ACID_POOL_BOTTOM,
3901 EL_ACID_POOL_BOTTOMRIGHT,
3902 EL_SP_HARDWARE_GRAY,
3903 EL_SP_HARDWARE_GREEN,
3904 EL_SP_HARDWARE_BLUE,
3906 EL_SP_HARDWARE_YELLOW,
3907 EL_SP_HARDWARE_BASE_1,
3908 EL_SP_HARDWARE_BASE_2,
3909 EL_SP_HARDWARE_BASE_3,
3910 EL_SP_HARDWARE_BASE_4,
3911 EL_SP_HARDWARE_BASE_5,
3912 EL_SP_HARDWARE_BASE_6,
3913 EL_INVISIBLE_STEELWALL,
3914 EL_INVISIBLE_STEELWALL_ACTIVE,
3915 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3916 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3917 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3918 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3919 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3920 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3921 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3922 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3923 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3924 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3925 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3926 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3928 EL_LIGHT_SWITCH_ACTIVE,
3929 EL_SIGN_EXCLAMATION,
3930 EL_SIGN_RADIOACTIVITY,
3937 EL_SIGN_ENTRY_FORBIDDEN,
3938 EL_SIGN_EMERGENCY_EXIT,
3946 EL_STEEL_EXIT_CLOSED,
3948 EL_DC_STEELWALL_1_LEFT,
3949 EL_DC_STEELWALL_1_RIGHT,
3950 EL_DC_STEELWALL_1_TOP,
3951 EL_DC_STEELWALL_1_BOTTOM,
3952 EL_DC_STEELWALL_1_HORIZONTAL,
3953 EL_DC_STEELWALL_1_VERTICAL,
3954 EL_DC_STEELWALL_1_TOPLEFT,
3955 EL_DC_STEELWALL_1_TOPRIGHT,
3956 EL_DC_STEELWALL_1_BOTTOMLEFT,
3957 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3958 EL_DC_STEELWALL_1_TOPLEFT_2,
3959 EL_DC_STEELWALL_1_TOPRIGHT_2,
3960 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3961 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3962 EL_DC_STEELWALL_2_LEFT,
3963 EL_DC_STEELWALL_2_RIGHT,
3964 EL_DC_STEELWALL_2_TOP,
3965 EL_DC_STEELWALL_2_BOTTOM,
3966 EL_DC_STEELWALL_2_HORIZONTAL,
3967 EL_DC_STEELWALL_2_VERTICAL,
3968 EL_DC_STEELWALL_2_MIDDLE,
3969 EL_DC_STEELWALL_2_SINGLE,
3970 EL_STEELWALL_SLIPPERY,
3984 EL_GATE_1_GRAY_ACTIVE,
3985 EL_GATE_2_GRAY_ACTIVE,
3986 EL_GATE_3_GRAY_ACTIVE,
3987 EL_GATE_4_GRAY_ACTIVE,
3996 EL_EM_GATE_1_GRAY_ACTIVE,
3997 EL_EM_GATE_2_GRAY_ACTIVE,
3998 EL_EM_GATE_3_GRAY_ACTIVE,
3999 EL_EM_GATE_4_GRAY_ACTIVE,
4001 EL_SWITCHGATE_OPENING,
4002 EL_SWITCHGATE_CLOSED,
4003 EL_SWITCHGATE_CLOSING,
4005 EL_TIMEGATE_OPENING,
4007 EL_TIMEGATE_CLOSING,
4011 EL_TUBE_VERTICAL_LEFT,
4012 EL_TUBE_VERTICAL_RIGHT,
4013 EL_TUBE_HORIZONTAL_UP,
4014 EL_TUBE_HORIZONTAL_DOWN,
4023 static int ep_classic_enemy[] =
4040 static int ep_belt[] =
4042 EL_CONVEYOR_BELT_1_LEFT,
4043 EL_CONVEYOR_BELT_1_MIDDLE,
4044 EL_CONVEYOR_BELT_1_RIGHT,
4045 EL_CONVEYOR_BELT_2_LEFT,
4046 EL_CONVEYOR_BELT_2_MIDDLE,
4047 EL_CONVEYOR_BELT_2_RIGHT,
4048 EL_CONVEYOR_BELT_3_LEFT,
4049 EL_CONVEYOR_BELT_3_MIDDLE,
4050 EL_CONVEYOR_BELT_3_RIGHT,
4051 EL_CONVEYOR_BELT_4_LEFT,
4052 EL_CONVEYOR_BELT_4_MIDDLE,
4053 EL_CONVEYOR_BELT_4_RIGHT,
4058 static int ep_belt_active[] =
4060 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
4061 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
4062 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
4063 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
4064 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
4065 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
4066 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
4067 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
4068 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
4069 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
4070 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
4071 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
4076 static int ep_belt_switch[] =
4078 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4079 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4080 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4081 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4082 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4083 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4084 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4085 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4086 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4087 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4088 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4089 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4094 static int ep_tube[] =
4101 EL_TUBE_HORIZONTAL_UP,
4102 EL_TUBE_HORIZONTAL_DOWN,
4104 EL_TUBE_VERTICAL_LEFT,
4105 EL_TUBE_VERTICAL_RIGHT,
4111 static int ep_acid_pool[] =
4113 EL_ACID_POOL_TOPLEFT,
4114 EL_ACID_POOL_TOPRIGHT,
4115 EL_ACID_POOL_BOTTOMLEFT,
4116 EL_ACID_POOL_BOTTOM,
4117 EL_ACID_POOL_BOTTOMRIGHT,
4122 static int ep_keygate[] =
4132 EL_GATE_1_GRAY_ACTIVE,
4133 EL_GATE_2_GRAY_ACTIVE,
4134 EL_GATE_3_GRAY_ACTIVE,
4135 EL_GATE_4_GRAY_ACTIVE,
4144 EL_EM_GATE_1_GRAY_ACTIVE,
4145 EL_EM_GATE_2_GRAY_ACTIVE,
4146 EL_EM_GATE_3_GRAY_ACTIVE,
4147 EL_EM_GATE_4_GRAY_ACTIVE,
4156 EL_EMC_GATE_5_GRAY_ACTIVE,
4157 EL_EMC_GATE_6_GRAY_ACTIVE,
4158 EL_EMC_GATE_7_GRAY_ACTIVE,
4159 EL_EMC_GATE_8_GRAY_ACTIVE,
4161 EL_DC_GATE_WHITE_GRAY,
4162 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4167 static int ep_amoeboid[] =
4179 static int ep_amoebalive[] =
4190 static int ep_has_editor_content[] =
4196 EL_SOKOBAN_FIELD_PLAYER,
4213 static int ep_can_turn_each_move[] =
4215 /* !!! do something with this one !!! */
4219 static int ep_can_grow[] =
4233 static int ep_active_bomb[] =
4236 EL_EM_DYNAMITE_ACTIVE,
4237 EL_DYNABOMB_PLAYER_1_ACTIVE,
4238 EL_DYNABOMB_PLAYER_2_ACTIVE,
4239 EL_DYNABOMB_PLAYER_3_ACTIVE,
4240 EL_DYNABOMB_PLAYER_4_ACTIVE,
4241 EL_SP_DISK_RED_ACTIVE,
4246 static int ep_inactive[] =
4256 EL_QUICKSAND_FAST_EMPTY,
4279 EL_GATE_1_GRAY_ACTIVE,
4280 EL_GATE_2_GRAY_ACTIVE,
4281 EL_GATE_3_GRAY_ACTIVE,
4282 EL_GATE_4_GRAY_ACTIVE,
4291 EL_EM_GATE_1_GRAY_ACTIVE,
4292 EL_EM_GATE_2_GRAY_ACTIVE,
4293 EL_EM_GATE_3_GRAY_ACTIVE,
4294 EL_EM_GATE_4_GRAY_ACTIVE,
4303 EL_EMC_GATE_5_GRAY_ACTIVE,
4304 EL_EMC_GATE_6_GRAY_ACTIVE,
4305 EL_EMC_GATE_7_GRAY_ACTIVE,
4306 EL_EMC_GATE_8_GRAY_ACTIVE,
4308 EL_DC_GATE_WHITE_GRAY,
4309 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4310 EL_DC_GATE_FAKE_GRAY,
4313 EL_INVISIBLE_STEELWALL,
4321 EL_WALL_EMERALD_YELLOW,
4322 EL_DYNABOMB_INCREASE_NUMBER,
4323 EL_DYNABOMB_INCREASE_SIZE,
4324 EL_DYNABOMB_INCREASE_POWER,
4328 EL_SOKOBAN_FIELD_EMPTY,
4329 EL_SOKOBAN_FIELD_FULL,
4330 EL_WALL_EMERALD_RED,
4331 EL_WALL_EMERALD_PURPLE,
4332 EL_ACID_POOL_TOPLEFT,
4333 EL_ACID_POOL_TOPRIGHT,
4334 EL_ACID_POOL_BOTTOMLEFT,
4335 EL_ACID_POOL_BOTTOM,
4336 EL_ACID_POOL_BOTTOMRIGHT,
4340 EL_BD_MAGIC_WALL_DEAD,
4342 EL_DC_MAGIC_WALL_DEAD,
4343 EL_AMOEBA_TO_DIAMOND,
4351 EL_SP_GRAVITY_PORT_RIGHT,
4352 EL_SP_GRAVITY_PORT_DOWN,
4353 EL_SP_GRAVITY_PORT_LEFT,
4354 EL_SP_GRAVITY_PORT_UP,
4355 EL_SP_PORT_HORIZONTAL,
4356 EL_SP_PORT_VERTICAL,
4367 EL_SP_HARDWARE_GRAY,
4368 EL_SP_HARDWARE_GREEN,
4369 EL_SP_HARDWARE_BLUE,
4371 EL_SP_HARDWARE_YELLOW,
4372 EL_SP_HARDWARE_BASE_1,
4373 EL_SP_HARDWARE_BASE_2,
4374 EL_SP_HARDWARE_BASE_3,
4375 EL_SP_HARDWARE_BASE_4,
4376 EL_SP_HARDWARE_BASE_5,
4377 EL_SP_HARDWARE_BASE_6,
4378 EL_SP_GRAVITY_ON_PORT_LEFT,
4379 EL_SP_GRAVITY_ON_PORT_RIGHT,
4380 EL_SP_GRAVITY_ON_PORT_UP,
4381 EL_SP_GRAVITY_ON_PORT_DOWN,
4382 EL_SP_GRAVITY_OFF_PORT_LEFT,
4383 EL_SP_GRAVITY_OFF_PORT_RIGHT,
4384 EL_SP_GRAVITY_OFF_PORT_UP,
4385 EL_SP_GRAVITY_OFF_PORT_DOWN,
4386 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4387 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4388 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4389 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4390 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4391 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4392 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4393 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4394 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4395 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4396 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4397 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4398 EL_SIGN_EXCLAMATION,
4399 EL_SIGN_RADIOACTIVITY,
4406 EL_SIGN_ENTRY_FORBIDDEN,
4407 EL_SIGN_EMERGENCY_EXIT,
4415 EL_DC_STEELWALL_1_LEFT,
4416 EL_DC_STEELWALL_1_RIGHT,
4417 EL_DC_STEELWALL_1_TOP,
4418 EL_DC_STEELWALL_1_BOTTOM,
4419 EL_DC_STEELWALL_1_HORIZONTAL,
4420 EL_DC_STEELWALL_1_VERTICAL,
4421 EL_DC_STEELWALL_1_TOPLEFT,
4422 EL_DC_STEELWALL_1_TOPRIGHT,
4423 EL_DC_STEELWALL_1_BOTTOMLEFT,
4424 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4425 EL_DC_STEELWALL_1_TOPLEFT_2,
4426 EL_DC_STEELWALL_1_TOPRIGHT_2,
4427 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4428 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4429 EL_DC_STEELWALL_2_LEFT,
4430 EL_DC_STEELWALL_2_RIGHT,
4431 EL_DC_STEELWALL_2_TOP,
4432 EL_DC_STEELWALL_2_BOTTOM,
4433 EL_DC_STEELWALL_2_HORIZONTAL,
4434 EL_DC_STEELWALL_2_VERTICAL,
4435 EL_DC_STEELWALL_2_MIDDLE,
4436 EL_DC_STEELWALL_2_SINGLE,
4437 EL_STEELWALL_SLIPPERY,
4442 EL_EMC_WALL_SLIPPERY_1,
4443 EL_EMC_WALL_SLIPPERY_2,
4444 EL_EMC_WALL_SLIPPERY_3,
4445 EL_EMC_WALL_SLIPPERY_4,
4466 static int ep_em_slippery_wall[] =
4471 static int ep_gfx_crumbled[] =
4482 static int ep_editor_cascade_active[] =
4484 EL_INTERNAL_CASCADE_BD_ACTIVE,
4485 EL_INTERNAL_CASCADE_EM_ACTIVE,
4486 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4487 EL_INTERNAL_CASCADE_RND_ACTIVE,
4488 EL_INTERNAL_CASCADE_SB_ACTIVE,
4489 EL_INTERNAL_CASCADE_SP_ACTIVE,
4490 EL_INTERNAL_CASCADE_DC_ACTIVE,
4491 EL_INTERNAL_CASCADE_DX_ACTIVE,
4492 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4493 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4494 EL_INTERNAL_CASCADE_CE_ACTIVE,
4495 EL_INTERNAL_CASCADE_GE_ACTIVE,
4496 EL_INTERNAL_CASCADE_REF_ACTIVE,
4497 EL_INTERNAL_CASCADE_USER_ACTIVE,
4498 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4503 static int ep_editor_cascade_inactive[] =
4505 EL_INTERNAL_CASCADE_BD,
4506 EL_INTERNAL_CASCADE_EM,
4507 EL_INTERNAL_CASCADE_EMC,
4508 EL_INTERNAL_CASCADE_RND,
4509 EL_INTERNAL_CASCADE_SB,
4510 EL_INTERNAL_CASCADE_SP,
4511 EL_INTERNAL_CASCADE_DC,
4512 EL_INTERNAL_CASCADE_DX,
4513 EL_INTERNAL_CASCADE_CHARS,
4514 EL_INTERNAL_CASCADE_STEEL_CHARS,
4515 EL_INTERNAL_CASCADE_CE,
4516 EL_INTERNAL_CASCADE_GE,
4517 EL_INTERNAL_CASCADE_REF,
4518 EL_INTERNAL_CASCADE_USER,
4519 EL_INTERNAL_CASCADE_DYNAMIC,
4524 static int ep_obsolete[] =
4528 EL_EM_KEY_1_FILE_OBSOLETE,
4529 EL_EM_KEY_2_FILE_OBSOLETE,
4530 EL_EM_KEY_3_FILE_OBSOLETE,
4531 EL_EM_KEY_4_FILE_OBSOLETE,
4532 EL_ENVELOPE_OBSOLETE,
4541 } element_properties[] =
4543 { ep_diggable, EP_DIGGABLE },
4544 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4545 { ep_dont_run_into, EP_DONT_RUN_INTO },
4546 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4547 { ep_dont_touch, EP_DONT_TOUCH },
4548 { ep_indestructible, EP_INDESTRUCTIBLE },
4549 { ep_slippery, EP_SLIPPERY },
4550 { ep_can_change, EP_CAN_CHANGE },
4551 { ep_can_move, EP_CAN_MOVE },
4552 { ep_can_fall, EP_CAN_FALL },
4553 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4554 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4555 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4556 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4557 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4558 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4559 { ep_walkable_over, EP_WALKABLE_OVER },
4560 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4561 { ep_walkable_under, EP_WALKABLE_UNDER },
4562 { ep_passable_over, EP_PASSABLE_OVER },
4563 { ep_passable_inside, EP_PASSABLE_INSIDE },
4564 { ep_passable_under, EP_PASSABLE_UNDER },
4565 { ep_droppable, EP_DROPPABLE },
4566 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4567 { ep_pushable, EP_PUSHABLE },
4568 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4569 { ep_protected, EP_PROTECTED },
4570 { ep_throwable, EP_THROWABLE },
4571 { ep_can_explode, EP_CAN_EXPLODE },
4572 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4574 { ep_player, EP_PLAYER },
4575 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4576 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4577 { ep_switchable, EP_SWITCHABLE },
4578 { ep_bd_element, EP_BD_ELEMENT },
4579 { ep_sp_element, EP_SP_ELEMENT },
4580 { ep_sb_element, EP_SB_ELEMENT },
4582 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4583 { ep_food_penguin, EP_FOOD_PENGUIN },
4584 { ep_food_pig, EP_FOOD_PIG },
4585 { ep_historic_wall, EP_HISTORIC_WALL },
4586 { ep_historic_solid, EP_HISTORIC_SOLID },
4587 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4588 { ep_belt, EP_BELT },
4589 { ep_belt_active, EP_BELT_ACTIVE },
4590 { ep_belt_switch, EP_BELT_SWITCH },
4591 { ep_tube, EP_TUBE },
4592 { ep_acid_pool, EP_ACID_POOL },
4593 { ep_keygate, EP_KEYGATE },
4594 { ep_amoeboid, EP_AMOEBOID },
4595 { ep_amoebalive, EP_AMOEBALIVE },
4596 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4597 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4598 { ep_can_grow, EP_CAN_GROW },
4599 { ep_active_bomb, EP_ACTIVE_BOMB },
4600 { ep_inactive, EP_INACTIVE },
4602 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4604 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4606 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4607 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4609 { ep_obsolete, EP_OBSOLETE },
4616 /* always start with reliable default values (element has no properties) */
4617 /* (but never initialize clipboard elements after the very first time) */
4618 /* (to be able to use clipboard elements between several levels) */
4619 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4620 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4621 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4622 SET_PROPERTY(i, j, FALSE);
4624 /* set all base element properties from above array definitions */
4625 for (i = 0; element_properties[i].elements != NULL; i++)
4626 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4627 SET_PROPERTY((element_properties[i].elements)[j],
4628 element_properties[i].property, TRUE);
4630 /* copy properties to some elements that are only stored in level file */
4631 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4632 for (j = 0; copy_properties[j][0] != -1; j++)
4633 if (HAS_PROPERTY(copy_properties[j][0], i))
4634 for (k = 1; k <= 4; k++)
4635 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4637 /* set static element properties that are not listed in array definitions */
4638 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4639 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4641 clipboard_elements_initialized = TRUE;
4644 void InitElementPropertiesEngine(int engine_version)
4646 static int no_wall_properties[] =
4649 EP_COLLECTIBLE_ONLY,
4651 EP_DONT_COLLIDE_WITH,
4654 EP_CAN_SMASH_PLAYER,
4655 EP_CAN_SMASH_ENEMIES,
4656 EP_CAN_SMASH_EVERYTHING,
4661 EP_FOOD_DARK_YAMYAM,
4677 /* important: after initialization in InitElementPropertiesStatic(), the
4678 elements are not again initialized to a default value; therefore all
4679 changes have to make sure that they leave the element with a defined
4680 property (which means that conditional property changes must be set to
4681 a reliable default value before) */
4683 /* resolve group elements */
4684 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4685 ResolveGroupElement(EL_GROUP_START + i);
4687 /* set all special, combined or engine dependent element properties */
4688 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4690 /* do not change (already initialized) clipboard elements here */
4691 if (IS_CLIPBOARD_ELEMENT(i))
4694 /* ---------- INACTIVE ------------------------------------------------- */
4695 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4696 i <= EL_CHAR_END) ||
4697 (i >= EL_STEEL_CHAR_START &&
4698 i <= EL_STEEL_CHAR_END)));
4700 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4701 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4702 IS_WALKABLE_INSIDE(i) ||
4703 IS_WALKABLE_UNDER(i)));
4705 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4706 IS_PASSABLE_INSIDE(i) ||
4707 IS_PASSABLE_UNDER(i)));
4709 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4710 IS_PASSABLE_OVER(i)));
4712 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4713 IS_PASSABLE_INSIDE(i)));
4715 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4716 IS_PASSABLE_UNDER(i)));
4718 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4721 /* ---------- COLLECTIBLE ---------------------------------------------- */
4722 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4726 /* ---------- SNAPPABLE ------------------------------------------------ */
4727 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4728 IS_COLLECTIBLE(i) ||
4732 /* ---------- WALL ----------------------------------------------------- */
4733 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4735 for (j = 0; no_wall_properties[j] != -1; j++)
4736 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4737 i >= EL_FIRST_RUNTIME_UNREAL)
4738 SET_PROPERTY(i, EP_WALL, FALSE);
4740 if (IS_HISTORIC_WALL(i))
4741 SET_PROPERTY(i, EP_WALL, TRUE);
4743 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4744 if (engine_version < VERSION_IDENT(2,2,0,0))
4745 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4747 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4749 !IS_COLLECTIBLE(i)));
4751 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4752 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4753 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4755 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4756 IS_INDESTRUCTIBLE(i)));
4758 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4760 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4761 else if (engine_version < VERSION_IDENT(2,2,0,0))
4762 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4764 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4768 if (IS_CUSTOM_ELEMENT(i))
4770 /* these are additional properties which are initially false when set */
4772 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4774 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4775 if (DONT_COLLIDE_WITH(i))
4776 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4778 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4779 if (CAN_SMASH_EVERYTHING(i))
4780 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4781 if (CAN_SMASH_ENEMIES(i))
4782 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4785 /* ---------- CAN_SMASH ------------------------------------------------ */
4786 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4787 CAN_SMASH_ENEMIES(i) ||
4788 CAN_SMASH_EVERYTHING(i)));
4790 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4791 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4792 EXPLODES_BY_FIRE(i)));
4794 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4795 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4796 EXPLODES_SMASHED(i)));
4798 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4799 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4800 EXPLODES_IMPACT(i)));
4802 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4803 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4805 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4806 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4807 i == EL_BLACK_ORB));
4809 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4810 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4812 IS_CUSTOM_ELEMENT(i)));
4814 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4815 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4816 i == EL_SP_ELECTRON));
4818 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4819 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4820 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4821 getMoveIntoAcidProperty(&level, i));
4823 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4824 if (MAYBE_DONT_COLLIDE_WITH(i))
4825 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4826 getDontCollideWithProperty(&level, i));
4828 /* ---------- SP_PORT -------------------------------------------------- */
4829 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4830 IS_PASSABLE_INSIDE(i)));
4832 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4833 for (j = 0; j < level.num_android_clone_elements; j++)
4834 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4836 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4838 /* ---------- CAN_CHANGE ----------------------------------------------- */
4839 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4840 for (j = 0; j < element_info[i].num_change_pages; j++)
4841 if (element_info[i].change_page[j].can_change)
4842 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4844 /* ---------- HAS_ACTION ----------------------------------------------- */
4845 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4846 for (j = 0; j < element_info[i].num_change_pages; j++)
4847 if (element_info[i].change_page[j].has_action)
4848 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4850 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4851 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4854 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4856 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4857 element_info[i].crumbled[ACTION_DEFAULT] !=
4858 element_info[i].graphic[ACTION_DEFAULT]);
4860 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
4861 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4862 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
4865 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4866 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4867 IS_EDITOR_CASCADE_INACTIVE(i)));
4870 /* dynamically adjust element properties according to game engine version */
4872 static int ep_em_slippery_wall[] =
4877 EL_EXPANDABLE_WALL_HORIZONTAL,
4878 EL_EXPANDABLE_WALL_VERTICAL,
4879 EL_EXPANDABLE_WALL_ANY,
4880 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4881 EL_EXPANDABLE_STEELWALL_VERTICAL,
4882 EL_EXPANDABLE_STEELWALL_ANY,
4883 EL_EXPANDABLE_STEELWALL_GROWING,
4887 static int ep_em_explodes_by_fire[] =
4890 EL_EM_DYNAMITE_ACTIVE,
4895 /* special EM style gems behaviour */
4896 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4897 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4898 level.em_slippery_gems);
4900 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4901 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4902 (level.em_slippery_gems &&
4903 engine_version > VERSION_IDENT(2,0,1,0)));
4905 /* special EM style explosion behaviour regarding chain reactions */
4906 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4907 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4908 level.em_explodes_by_fire);
4911 /* this is needed because some graphics depend on element properties */
4912 if (game_status == GAME_MODE_PLAYING)
4913 InitElementGraphicInfo();
4916 void InitElementPropertiesAfterLoading(int engine_version)
4920 /* set some other uninitialized values of custom elements in older levels */
4921 if (engine_version < VERSION_IDENT(3,1,0,0))
4923 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4925 int element = EL_CUSTOM_START + i;
4927 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4929 element_info[element].explosion_delay = 17;
4930 element_info[element].ignition_delay = 8;
4935 void InitElementPropertiesGfxElement()
4939 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4941 struct ElementInfo *ei = &element_info[i];
4943 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4947 static void InitGlobal()
4952 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4954 /* check if element_name_info entry defined for each element in "main.h" */
4955 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4956 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4958 element_info[i].token_name = element_name_info[i].token_name;
4959 element_info[i].class_name = element_name_info[i].class_name;
4960 element_info[i].editor_description= element_name_info[i].editor_description;
4963 printf("%04d: %s\n", i, element_name_info[i].token_name);
4967 /* create hash from image config list */
4968 image_config_hash = newSetupFileHash();
4969 for (i = 0; image_config[i].token != NULL; i++)
4970 setHashEntry(image_config_hash,
4971 image_config[i].token,
4972 image_config[i].value);
4974 /* create hash from element token list */
4975 element_token_hash = newSetupFileHash();
4976 for (i = 0; element_name_info[i].token_name != NULL; i++)
4977 setHashEntry(element_token_hash,
4978 element_name_info[i].token_name,
4981 /* create hash from graphic token list */
4982 graphic_token_hash = newSetupFileHash();
4983 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4984 if (strSuffix(image_config[i].value, ".png") ||
4985 strSuffix(image_config[i].value, ".pcx") ||
4986 strSuffix(image_config[i].value, ".wav") ||
4987 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4988 setHashEntry(graphic_token_hash,
4989 image_config[i].token,
4990 int2str(graphic++, 0));
4992 /* create hash from font token list */
4993 font_token_hash = newSetupFileHash();
4994 for (i = 0; font_info[i].token_name != NULL; i++)
4995 setHashEntry(font_token_hash,
4996 font_info[i].token_name,
4999 /* always start with reliable default values (all elements) */
5000 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5001 ActiveElement[i] = i;
5003 /* now add all entries that have an active state (active elements) */
5004 for (i = 0; element_with_active_state[i].element != -1; i++)
5006 int element = element_with_active_state[i].element;
5007 int element_active = element_with_active_state[i].element_active;
5009 ActiveElement[element] = element_active;
5012 /* always start with reliable default values (all buttons) */
5013 for (i = 0; i < NUM_IMAGE_FILES; i++)
5014 ActiveButton[i] = i;
5016 /* now add all entries that have an active state (active buttons) */
5017 for (i = 0; button_with_active_state[i].button != -1; i++)
5019 int button = button_with_active_state[i].button;
5020 int button_active = button_with_active_state[i].button_active;
5022 ActiveButton[button] = button_active;
5025 /* always start with reliable default values (all fonts) */
5026 for (i = 0; i < NUM_FONTS; i++)
5029 /* now add all entries that have an active state (active fonts) */
5030 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
5032 int font = font_with_active_state[i].font_nr;
5033 int font_active = font_with_active_state[i].font_nr_active;
5035 ActiveFont[font] = font_active;
5038 global.autoplay_leveldir = NULL;
5039 global.convert_leveldir = NULL;
5040 global.create_images_dir = NULL;
5042 global.frames_per_second = 0;
5043 global.fps_slowdown = FALSE;
5044 global.fps_slowdown_factor = 1;
5046 global.border_status = GAME_MODE_MAIN;
5048 global.fading_status = GAME_MODE_MAIN;
5049 global.fading_type = TYPE_ENTER_MENU;
5052 global.use_envelope_request = FALSE;
5055 void Execute_Command(char *command)
5059 if (strEqual(command, "print graphicsinfo.conf"))
5061 printf("# You can configure additional/alternative image files here.\n");
5062 printf("# (The entries below are default and therefore commented out.)\n");
5064 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
5066 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5069 for (i = 0; image_config[i].token != NULL; i++)
5070 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
5071 image_config[i].value));
5075 else if (strEqual(command, "print soundsinfo.conf"))
5077 printf("# You can configure additional/alternative sound files here.\n");
5078 printf("# (The entries below are default and therefore commented out.)\n");
5080 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
5082 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5085 for (i = 0; sound_config[i].token != NULL; i++)
5086 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
5087 sound_config[i].value));
5091 else if (strEqual(command, "print musicinfo.conf"))
5093 printf("# You can configure additional/alternative music files here.\n");
5094 printf("# (The entries below are default and therefore commented out.)\n");
5096 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
5098 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5101 for (i = 0; music_config[i].token != NULL; i++)
5102 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
5103 music_config[i].value));
5107 else if (strEqual(command, "print editorsetup.conf"))
5109 printf("# You can configure your personal editor element list here.\n");
5110 printf("# (The entries below are default and therefore commented out.)\n");
5113 /* this is needed to be able to check element list for cascade elements */
5114 InitElementPropertiesStatic();
5115 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5117 PrintEditorElementList();
5121 else if (strEqual(command, "print helpanim.conf"))
5123 printf("# You can configure different element help animations here.\n");
5124 printf("# (The entries below are default and therefore commented out.)\n");
5127 for (i = 0; helpanim_config[i].token != NULL; i++)
5129 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
5130 helpanim_config[i].value));
5132 if (strEqual(helpanim_config[i].token, "end"))
5138 else if (strEqual(command, "print helptext.conf"))
5140 printf("# You can configure different element help text here.\n");
5141 printf("# (The entries below are default and therefore commented out.)\n");
5144 for (i = 0; helptext_config[i].token != NULL; i++)
5145 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
5146 helptext_config[i].value));
5150 else if (strPrefix(command, "dump level "))
5152 char *filename = &command[11];
5154 if (!fileExists(filename))
5155 Error(ERR_EXIT, "cannot open file '%s'", filename);
5157 LoadLevelFromFilename(&level, filename);
5162 else if (strPrefix(command, "dump tape "))
5164 char *filename = &command[10];
5166 if (!fileExists(filename))
5167 Error(ERR_EXIT, "cannot open file '%s'", filename);
5169 LoadTapeFromFilename(filename);
5174 else if (strPrefix(command, "autoplay "))
5176 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
5178 while (*str_ptr != '\0') /* continue parsing string */
5180 /* cut leading whitespace from string, replace it by string terminator */
5181 while (*str_ptr == ' ' || *str_ptr == '\t')
5184 if (*str_ptr == '\0') /* end of string reached */
5187 if (global.autoplay_leveldir == NULL) /* read level set string */
5189 global.autoplay_leveldir = str_ptr;
5190 global.autoplay_all = TRUE; /* default: play all tapes */
5192 for (i = 0; i < MAX_TAPES_PER_SET; i++)
5193 global.autoplay_level[i] = FALSE;
5195 else /* read level number string */
5197 int level_nr = atoi(str_ptr); /* get level_nr value */
5199 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5200 global.autoplay_level[level_nr] = TRUE;
5202 global.autoplay_all = FALSE;
5205 /* advance string pointer to the next whitespace (or end of string) */
5206 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5210 else if (strPrefix(command, "convert "))
5212 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
5213 char *str_ptr = strchr(str_copy, ' ');
5215 global.convert_leveldir = str_copy;
5216 global.convert_level_nr = -1;
5218 if (str_ptr != NULL) /* level number follows */
5220 *str_ptr++ = '\0'; /* terminate leveldir string */
5221 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
5224 else if (strPrefix(command, "create images "))
5226 global.create_images_dir = getStringCopy(&command[14]);
5228 if (access(global.create_images_dir, W_OK) != 0)
5229 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
5230 global.create_images_dir);
5234 #if defined(TARGET_SDL2)
5235 else if (strEqual(command, "SDL_ListModes"))
5237 SDL_Init(SDL_INIT_VIDEO);
5239 int num_displays = SDL_GetNumVideoDisplays();
5241 // check if there are any displays available
5242 if (num_displays < 0)
5244 printf("No displays available: %s\n", SDL_GetError());
5249 for (i = 0; i < num_displays; i++)
5251 int num_modes = SDL_GetNumDisplayModes(i);
5254 printf("Available display modes for display %d:\n", i);
5256 // check if there are any display modes available for this display
5259 printf("No display modes available for display %d: %s\n",
5265 for (j = 0; j < num_modes; j++)
5267 SDL_DisplayMode mode;
5269 if (SDL_GetDisplayMode(i, j, &mode) < 0)
5271 printf("Cannot get display mode %d for display %d: %s\n",
5272 j, i, SDL_GetError());
5277 printf("- %d x %d\n", mode.w, mode.h);
5283 #elif defined(TARGET_SDL)
5284 else if (strEqual(command, "SDL_ListModes"))
5289 SDL_Init(SDL_INIT_VIDEO);
5291 /* get available fullscreen/hardware modes */
5292 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
5294 /* check if there are any modes available */
5297 printf("No modes available!\n");
5302 /* check if our resolution is restricted */
5303 if (modes == (SDL_Rect **)-1)
5305 printf("All resolutions available.\n");
5309 printf("Available display modes:\n");
5311 for (i = 0; modes[i]; i++)
5312 printf("- %d x %d\n", modes[i]->w, modes[i]->h);
5322 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
5326 static void InitSetup()
5328 LoadSetup(); /* global setup info */
5330 /* set some options from setup file */
5332 if (setup.options.verbose)
5333 options.verbose = TRUE;
5336 static void InitGameInfo()
5338 game.restart_level = FALSE;
5341 static void InitPlayerInfo()
5345 /* choose default local player */
5346 local_player = &stored_player[0];
5348 for (i = 0; i < MAX_PLAYERS; i++)
5349 stored_player[i].connected = FALSE;
5351 local_player->connected = TRUE;
5354 static void InitArtworkInfo()
5359 static char *get_string_in_brackets(char *string)
5361 char *string_in_brackets = checked_malloc(strlen(string) + 3);
5363 sprintf(string_in_brackets, "[%s]", string);
5365 return string_in_brackets;
5368 static char *get_level_id_suffix(int id_nr)
5370 char *id_suffix = checked_malloc(1 + 3 + 1);
5372 if (id_nr < 0 || id_nr > 999)
5375 sprintf(id_suffix, ".%03d", id_nr);
5381 static char *get_element_class_token(int element)
5383 char *element_class_name = element_info[element].class_name;
5384 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
5386 sprintf(element_class_token, "[%s]", element_class_name);
5388 return element_class_token;
5391 static char *get_action_class_token(int action)
5393 char *action_class_name = &element_action_info[action].suffix[1];
5394 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
5396 sprintf(action_class_token, "[%s]", action_class_name);
5398 return action_class_token;
5402 static void InitArtworkConfig()
5404 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
5405 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
5406 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
5407 static char *action_id_suffix[NUM_ACTIONS + 1];
5408 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5409 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5410 static char *level_id_suffix[MAX_LEVELS + 1];
5411 static char *dummy[1] = { NULL };
5412 static char *ignore_generic_tokens[] =
5418 static char **ignore_image_tokens;
5419 static char **ignore_sound_tokens;
5420 static char **ignore_music_tokens;
5421 int num_ignore_generic_tokens;
5422 int num_ignore_image_tokens;
5423 int num_ignore_sound_tokens;
5424 int num_ignore_music_tokens;
5427 /* dynamically determine list of generic tokens to be ignored */
5428 num_ignore_generic_tokens = 0;
5429 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5430 num_ignore_generic_tokens++;
5432 /* dynamically determine list of image tokens to be ignored */
5433 num_ignore_image_tokens = num_ignore_generic_tokens;
5434 for (i = 0; image_config_vars[i].token != NULL; i++)
5435 num_ignore_image_tokens++;
5436 ignore_image_tokens =
5437 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5438 for (i = 0; i < num_ignore_generic_tokens; i++)
5439 ignore_image_tokens[i] = ignore_generic_tokens[i];
5440 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5441 ignore_image_tokens[num_ignore_generic_tokens + i] =
5442 image_config_vars[i].token;
5443 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5445 /* dynamically determine list of sound tokens to be ignored */
5446 num_ignore_sound_tokens = num_ignore_generic_tokens;
5447 ignore_sound_tokens =
5448 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5449 for (i = 0; i < num_ignore_generic_tokens; i++)
5450 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5451 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5453 /* dynamically determine list of music tokens to be ignored */
5454 num_ignore_music_tokens = num_ignore_generic_tokens;
5455 ignore_music_tokens =
5456 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5457 for (i = 0; i < num_ignore_generic_tokens; i++)
5458 ignore_music_tokens[i] = ignore_generic_tokens[i];
5459 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5461 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5462 image_id_prefix[i] = element_info[i].token_name;
5463 for (i = 0; i < NUM_FONTS; i++)
5464 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5465 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
5467 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5468 sound_id_prefix[i] = element_info[i].token_name;
5469 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5470 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5471 get_string_in_brackets(element_info[i].class_name);
5472 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
5474 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5475 music_id_prefix[i] = music_prefix_info[i].prefix;
5476 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
5478 for (i = 0; i < NUM_ACTIONS; i++)
5479 action_id_suffix[i] = element_action_info[i].suffix;
5480 action_id_suffix[NUM_ACTIONS] = NULL;
5482 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5483 direction_id_suffix[i] = element_direction_info[i].suffix;
5484 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5486 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5487 special_id_suffix[i] = special_suffix_info[i].suffix;
5488 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5490 for (i = 0; i < MAX_LEVELS; i++)
5491 level_id_suffix[i] = get_level_id_suffix(i);
5492 level_id_suffix[MAX_LEVELS] = NULL;
5494 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5495 image_id_prefix, action_id_suffix, direction_id_suffix,
5496 special_id_suffix, ignore_image_tokens);
5497 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5498 sound_id_prefix, action_id_suffix, dummy,
5499 special_id_suffix, ignore_sound_tokens);
5500 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5501 music_id_prefix, special_id_suffix, level_id_suffix,
5502 dummy, ignore_music_tokens);
5505 static void InitMixer()
5512 void InitGfxBuffers()
5514 /* create additional image buffers for double-buffering and cross-fading */
5515 ReCreateBitmap(&bitmap_db_store, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5516 ReCreateBitmap(&bitmap_db_cross, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5517 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE, DEFAULT_DEPTH);
5518 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE, DEFAULT_DEPTH);
5520 ReCreateBitmap(&bitmap_db_door, 3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
5522 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE, DEFAULT_DEPTH);
5523 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE, DEFAULT_DEPTH);
5524 ReCreateBitmap(&bitmap_db_toons, FULL_SXSIZE, FULL_SYSIZE, DEFAULT_DEPTH);
5526 /* initialize screen properties */
5527 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5528 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5530 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5531 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5532 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5533 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5534 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5535 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5537 InitGfxBuffers_EM();
5538 InitGfxBuffers_SP();
5543 struct GraphicInfo *graphic_info_last = graphic_info;
5544 char *filename_font_initial = NULL;
5545 char *filename_anim_initial = NULL;
5546 Bitmap *bitmap_font_initial = NULL;
5550 /* determine settings for initial font (for displaying startup messages) */
5551 for (i = 0; image_config[i].token != NULL; i++)
5553 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5555 char font_token[128];
5558 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5559 len_font_token = strlen(font_token);
5561 if (strEqual(image_config[i].token, font_token))
5562 filename_font_initial = image_config[i].value;
5563 else if (strlen(image_config[i].token) > len_font_token &&
5564 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5566 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5567 font_initial[j].src_x = atoi(image_config[i].value);
5568 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5569 font_initial[j].src_y = atoi(image_config[i].value);
5570 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5571 font_initial[j].width = atoi(image_config[i].value);
5572 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5573 font_initial[j].height = atoi(image_config[i].value);
5578 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5580 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5581 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5584 if (filename_font_initial == NULL) /* should not happen */
5585 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5588 InitGfxCustomArtworkInfo();
5590 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5592 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5593 font_initial[j].bitmap = bitmap_font_initial;
5595 InitFontGraphicInfo();
5597 font_height = getFontHeight(FC_RED);
5600 DrawInitTextAlways(getWindowTitleString(), 20, FC_YELLOW);
5602 DrawInitTextAlways(getProgramInitString(), 20, FC_YELLOW);
5604 DrawInitTextAlways(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
5605 DrawInitTextAlways(PROGRAM_WEBSITE_STRING, WIN_YSIZE - 20 - font_height,
5608 DrawInitTextAlways("Loading graphics", 120, FC_GREEN);
5612 /* initialize busy animation with default values */
5613 int parameter[NUM_GFX_ARGS];
5614 for (i = 0; i < NUM_GFX_ARGS; i++)
5615 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5616 image_config_suffix[i].token,
5617 image_config_suffix[i].type);
5619 for (i = 0; i < NUM_GFX_ARGS; i++)
5620 printf("::: '%s' => %d\n", image_config_suffix[i].token, parameter[i]);
5624 /* determine settings for busy animation (when displaying startup messages) */
5625 for (i = 0; image_config[i].token != NULL; i++)
5627 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5628 int len_anim_token = strlen(anim_token);
5630 if (strEqual(image_config[i].token, anim_token))
5631 filename_anim_initial = image_config[i].value;
5632 else if (strlen(image_config[i].token) > len_anim_token &&
5633 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5636 for (j = 0; image_config_suffix[j].token != NULL; j++)
5638 if (strEqual(&image_config[i].token[len_anim_token],
5639 image_config_suffix[j].token))
5641 get_graphic_parameter_value(image_config[i].value,
5642 image_config_suffix[j].token,
5643 image_config_suffix[j].type);
5646 if (strEqual(&image_config[i].token[len_anim_token], ".x"))
5647 anim_initial.src_x = atoi(image_config[i].value);
5648 else if (strEqual(&image_config[i].token[len_anim_token], ".y"))
5649 anim_initial.src_y = atoi(image_config[i].value);
5650 else if (strEqual(&image_config[i].token[len_anim_token], ".width"))
5651 anim_initial.width = atoi(image_config[i].value);
5652 else if (strEqual(&image_config[i].token[len_anim_token], ".height"))
5653 anim_initial.height = atoi(image_config[i].value);
5654 else if (strEqual(&image_config[i].token[len_anim_token], ".frames"))
5655 anim_initial.anim_frames = atoi(image_config[i].value);
5656 else if (strEqual(&image_config[i].token[len_anim_token],
5657 ".frames_per_line"))
5658 anim_initial.anim_frames_per_line = atoi(image_config[i].value);
5659 else if (strEqual(&image_config[i].token[len_anim_token], ".delay"))
5660 anim_initial.anim_delay = atoi(image_config[i].value);
5665 #if defined(CREATE_SPECIAL_EDITION_RND_JUE)
5666 filename_anim_initial = "loading.pcx";
5668 parameter[GFX_ARG_X] = 0;
5669 parameter[GFX_ARG_Y] = 0;
5670 parameter[GFX_ARG_WIDTH] = 128;
5671 parameter[GFX_ARG_HEIGHT] = 40;
5672 parameter[GFX_ARG_FRAMES] = 32;
5673 parameter[GFX_ARG_DELAY] = 4;
5674 parameter[GFX_ARG_FRAMES_PER_LINE] = ARG_UNDEFINED_VALUE;
5677 if (filename_anim_initial == NULL) /* should not happen */
5678 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5680 anim_initial.bitmap = LoadCustomImage(filename_anim_initial);
5682 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
5684 set_graphic_parameters_ext(0, parameter, anim_initial.bitmap);
5687 printf("::: INIT_GFX: anim_frames_per_line == %d [%d / %d] [%d, %d]\n",
5688 graphic_info[0].anim_frames_per_line,
5689 get_scaled_graphic_width(0),
5690 graphic_info[0].width,
5691 getOriginalImageWidthFromImageID(0),
5692 graphic_info[0].scale_up_factor);
5695 graphic_info = graphic_info_last;
5697 init.busy.width = anim_initial.width;
5698 init.busy.height = anim_initial.height;
5700 InitMenuDesignSettings_Static();
5701 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5703 /* use copy of busy animation to prevent change while reloading artwork */
5708 void RedrawBackground()
5710 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
5711 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
5713 redraw_mask = REDRAW_ALL;
5716 void InitGfxBackground()
5720 fieldbuffer = bitmap_db_field;
5721 SetDrawtoField(DRAW_BACKBUFFER);
5724 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5728 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
5729 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
5732 for (x = 0; x < MAX_BUF_XSIZE; x++)
5733 for (y = 0; y < MAX_BUF_YSIZE; y++)
5736 redraw_mask = REDRAW_ALL;
5739 static void InitLevelInfo()
5741 LoadLevelInfo(); /* global level info */
5742 LoadLevelSetup_LastSeries(); /* last played series info */
5743 LoadLevelSetup_SeriesInfo(); /* last played level info */
5746 static void InitLevelArtworkInfo()
5748 LoadLevelArtworkInfo();
5751 static void InitImages()
5753 print_timestamp_init("InitImages");
5756 printf("::: leveldir_current->identifier == '%s'\n",
5757 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5758 printf("::: leveldir_current->graphics_path == '%s'\n",
5759 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5760 printf("::: leveldir_current->graphics_set == '%s'\n",
5761 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5762 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5763 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5766 setLevelArtworkDir(artwork.gfx_first);
5769 printf("::: leveldir_current->identifier == '%s'\n",
5770 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5771 printf("::: leveldir_current->graphics_path == '%s'\n",
5772 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5773 printf("::: leveldir_current->graphics_set == '%s'\n",
5774 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5775 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5776 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5780 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5781 leveldir_current->identifier,
5782 artwork.gfx_current_identifier,
5783 artwork.gfx_current->identifier,
5784 leveldir_current->graphics_set,
5785 leveldir_current->graphics_path);
5788 UPDATE_BUSY_STATE();
5790 ReloadCustomImages();
5791 print_timestamp_time("ReloadCustomImages");
5793 UPDATE_BUSY_STATE();
5795 LoadCustomElementDescriptions();
5796 print_timestamp_time("LoadCustomElementDescriptions");
5798 UPDATE_BUSY_STATE();
5800 LoadMenuDesignSettings();
5801 print_timestamp_time("LoadMenuDesignSettings");
5803 UPDATE_BUSY_STATE();
5805 ReinitializeGraphics();
5806 print_timestamp_time("ReinitializeGraphics");
5808 UPDATE_BUSY_STATE();
5810 print_timestamp_done("InitImages");
5813 static void InitSound(char *identifier)
5815 print_timestamp_init("InitSound");
5817 if (identifier == NULL)
5818 identifier = artwork.snd_current->identifier;
5820 /* set artwork path to send it to the sound server process */
5821 setLevelArtworkDir(artwork.snd_first);
5823 InitReloadCustomSounds(identifier);
5824 print_timestamp_time("InitReloadCustomSounds");
5826 ReinitializeSounds();
5827 print_timestamp_time("ReinitializeSounds");
5829 print_timestamp_done("InitSound");
5832 static void InitMusic(char *identifier)
5834 print_timestamp_init("InitMusic");
5836 if (identifier == NULL)
5837 identifier = artwork.mus_current->identifier;
5839 /* set artwork path to send it to the sound server process */
5840 setLevelArtworkDir(artwork.mus_first);
5842 InitReloadCustomMusic(identifier);
5843 print_timestamp_time("InitReloadCustomMusic");
5845 ReinitializeMusic();
5846 print_timestamp_time("ReinitializeMusic");
5848 print_timestamp_done("InitMusic");
5851 void InitNetworkServer()
5853 #if defined(NETWORK_AVALIABLE)
5857 if (!options.network)
5860 #if defined(NETWORK_AVALIABLE)
5861 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5863 if (!ConnectToServer(options.server_host, options.server_port))
5864 Error(ERR_EXIT, "cannot connect to network game server");
5866 SendToServer_PlayerName(setup.player_name);
5867 SendToServer_ProtocolVersion();
5870 SendToServer_NrWanted(nr_wanted);
5874 static boolean CheckArtworkConfigForCustomElements(char *filename)
5876 SetupFileHash *setup_file_hash;
5877 boolean redefined_ce_found = FALSE;
5879 /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */
5881 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5883 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5885 char *token = HASH_ITERATION_TOKEN(itr);
5887 if (strPrefix(token, "custom_"))
5889 redefined_ce_found = TRUE;
5894 END_HASH_ITERATION(setup_file_hash, itr)
5896 freeSetupFileHash(setup_file_hash);
5899 return redefined_ce_found;
5902 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5904 char *filename_base, *filename_local;
5905 boolean redefined_ce_found = FALSE;
5907 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5910 printf("::: leveldir_current->identifier == '%s'\n",
5911 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5912 printf("::: leveldir_current->graphics_path == '%s'\n",
5913 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5914 printf("::: leveldir_current->graphics_set == '%s'\n",
5915 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5916 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5917 leveldir_current == NULL ? "[NULL]" :
5918 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5921 /* first look for special artwork configured in level series config */
5922 filename_base = getCustomArtworkLevelConfigFilename(type);
5925 printf("::: filename_base == '%s'\n", filename_base);
5928 if (fileExists(filename_base))
5929 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5931 filename_local = getCustomArtworkConfigFilename(type);
5934 printf("::: filename_local == '%s'\n", filename_local);
5937 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5938 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5941 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5944 return redefined_ce_found;
5947 static void InitOverrideArtwork()
5949 boolean redefined_ce_found = FALSE;
5951 /* to check if this level set redefines any CEs, do not use overriding */
5952 gfx.override_level_graphics = FALSE;
5953 gfx.override_level_sounds = FALSE;
5954 gfx.override_level_music = FALSE;
5956 /* now check if this level set has definitions for custom elements */
5957 if (setup.override_level_graphics == AUTO ||
5958 setup.override_level_sounds == AUTO ||
5959 setup.override_level_music == AUTO)
5960 redefined_ce_found =
5961 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5962 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5963 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5966 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5969 if (redefined_ce_found)
5971 /* this level set has CE definitions: change "AUTO" to "FALSE" */
5972 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5973 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
5974 gfx.override_level_music = (setup.override_level_music == TRUE);
5978 /* this level set has no CE definitions: change "AUTO" to "TRUE" */
5979 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5980 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
5981 gfx.override_level_music = (setup.override_level_music != FALSE);
5985 printf("::: => %d, %d, %d\n",
5986 gfx.override_level_graphics,
5987 gfx.override_level_sounds,
5988 gfx.override_level_music);
5992 static char *getNewArtworkIdentifier(int type)
5994 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5995 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5996 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5997 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5998 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
6000 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
6002 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
6004 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
6005 char *leveldir_identifier = leveldir_current->identifier;
6007 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
6008 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
6010 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
6012 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
6013 char *artwork_current_identifier;
6014 char *artwork_new_identifier = NULL; /* default: nothing has changed */
6016 /* leveldir_current may be invalid (level group, parent link) */
6017 if (!validLevelSeries(leveldir_current))
6020 /* 1st step: determine artwork set to be activated in descending order:
6021 --------------------------------------------------------------------
6022 1. setup artwork (when configured to override everything else)
6023 2. artwork set configured in "levelinfo.conf" of current level set
6024 (artwork in level directory will have priority when loading later)
6025 3. artwork in level directory (stored in artwork sub-directory)
6026 4. setup artwork (currently configured in setup menu) */
6028 if (setup_override_artwork)
6029 artwork_current_identifier = setup_artwork_set;
6030 else if (leveldir_artwork_set != NULL)
6031 artwork_current_identifier = leveldir_artwork_set;
6032 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
6033 artwork_current_identifier = leveldir_identifier;
6035 artwork_current_identifier = setup_artwork_set;
6038 /* 2nd step: check if it is really needed to reload artwork set
6039 ------------------------------------------------------------ */
6042 if (type == ARTWORK_TYPE_GRAPHICS)
6043 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
6044 artwork_new_identifier,
6045 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
6046 artwork_current_identifier,
6047 leveldir_current->graphics_set,
6048 leveldir_current->identifier);
6051 /* ---------- reload if level set and also artwork set has changed ------- */
6052 if (leveldir_current_identifier[type] != leveldir_identifier &&
6053 (last_has_level_artwork_set[type] || has_level_artwork_set))
6054 artwork_new_identifier = artwork_current_identifier;
6056 leveldir_current_identifier[type] = leveldir_identifier;
6057 last_has_level_artwork_set[type] = has_level_artwork_set;
6060 if (type == ARTWORK_TYPE_GRAPHICS)
6061 printf("::: 1: '%s'\n", artwork_new_identifier);
6064 /* ---------- reload if "override artwork" setting has changed ----------- */
6065 if (last_override_level_artwork[type] != setup_override_artwork)
6066 artwork_new_identifier = artwork_current_identifier;
6068 last_override_level_artwork[type] = setup_override_artwork;
6071 if (type == ARTWORK_TYPE_GRAPHICS)
6072 printf("::: 2: '%s'\n", artwork_new_identifier);
6075 /* ---------- reload if current artwork identifier has changed ----------- */
6076 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
6077 artwork_current_identifier))
6078 artwork_new_identifier = artwork_current_identifier;
6080 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
6083 if (type == ARTWORK_TYPE_GRAPHICS)
6084 printf("::: 3: '%s'\n", artwork_new_identifier);
6087 /* ---------- do not reload directly after starting ---------------------- */
6088 if (!initialized[type])
6089 artwork_new_identifier = NULL;
6091 initialized[type] = TRUE;
6094 if (type == ARTWORK_TYPE_GRAPHICS)
6095 printf("::: 4: '%s'\n", artwork_new_identifier);
6099 if (type == ARTWORK_TYPE_GRAPHICS)
6100 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
6101 artwork.gfx_current_identifier, artwork_current_identifier,
6102 artwork.gfx_current->identifier, leveldir_current->graphics_set,
6103 artwork_new_identifier);
6106 return artwork_new_identifier;
6109 void ReloadCustomArtwork(int force_reload)
6111 int last_game_status = game_status; /* save current game status */
6112 char *gfx_new_identifier;
6113 char *snd_new_identifier;
6114 char *mus_new_identifier;
6115 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
6116 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
6117 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
6118 boolean reload_needed;
6120 InitOverrideArtwork();
6122 force_reload_gfx |= AdjustGraphicsForEMC();
6124 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
6125 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
6126 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
6128 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
6129 snd_new_identifier != NULL || force_reload_snd ||
6130 mus_new_identifier != NULL || force_reload_mus);
6135 print_timestamp_init("ReloadCustomArtwork");
6137 game_status = GAME_MODE_LOADING;
6139 FadeOut(REDRAW_ALL);
6142 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6144 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
6146 print_timestamp_time("ClearRectangle");
6149 printf("::: fading in ... %d\n", fading.fade_mode);
6153 printf("::: done\n");
6156 if (gfx_new_identifier != NULL || force_reload_gfx)
6159 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
6160 artwork.gfx_current_identifier,
6162 artwork.gfx_current->identifier,
6163 leveldir_current->graphics_set);
6167 print_timestamp_time("InitImages");
6170 if (snd_new_identifier != NULL || force_reload_snd)
6172 InitSound(snd_new_identifier);
6173 print_timestamp_time("InitSound");
6176 if (mus_new_identifier != NULL || force_reload_mus)
6178 InitMusic(mus_new_identifier);
6179 print_timestamp_time("InitMusic");
6182 game_status = last_game_status; /* restore current game status */
6184 init_last = init; /* switch to new busy animation */
6187 printf("::: ----------------DELAY 1 ...\n");
6192 printf("::: FadeOut @ ReloadCustomArtwork ...\n");
6194 FadeOut(REDRAW_ALL);
6196 printf("::: FadeOut @ ReloadCustomArtwork done\n");
6201 /* force redraw of (open or closed) door graphics */
6202 SetDoorState(DOOR_OPEN_ALL);
6203 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
6208 FadeSetEnterScreen();
6209 FadeSkipNextFadeOut();
6210 // FadeSetDisabled();
6215 fading = fading_none;
6220 redraw_mask = REDRAW_ALL;
6223 print_timestamp_done("ReloadCustomArtwork");
6225 LimitScreenUpdates(FALSE);
6228 void KeyboardAutoRepeatOffUnlessAutoplay()
6230 if (global.autoplay_leveldir == NULL)
6231 KeyboardAutoRepeatOff();
6234 void DisplayExitMessage(char *format, va_list ap)
6236 // check if draw buffer and fonts for exit message are already available
6237 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
6240 int font_1 = FC_RED;
6241 int font_2 = FC_YELLOW;
6242 int font_3 = FC_BLUE;
6243 int font_width = getFontWidth(font_2);
6244 int font_height = getFontHeight(font_2);
6247 int sxsize = WIN_XSIZE - 2 * sx;
6248 int sysize = WIN_YSIZE - 2 * sy;
6249 int line_length = sxsize / font_width;
6250 int max_lines = sysize / font_height;
6251 int num_lines_printed;
6255 gfx.sxsize = sxsize;
6256 gfx.sysize = sysize;
6260 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6262 DrawTextSCentered(sy, font_1, "Fatal error:");
6263 sy += 3 * font_height;;
6266 DrawTextBufferVA(sx, sy, format, ap, font_2,
6267 line_length, line_length, max_lines,
6268 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6269 sy += (num_lines_printed + 3) * font_height;
6271 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
6272 sy += 3 * font_height;
6275 DrawTextBuffer(sx, sy, program.error_filename, font_2,
6276 line_length, line_length, max_lines,
6277 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6279 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
6281 redraw_mask = REDRAW_ALL;
6285 /* deactivate toons on error message screen */
6286 setup.toons = FALSE;
6288 WaitForEventToContinue();
6292 /* ========================================================================= */
6294 /* ========================================================================= */
6298 print_timestamp_init("OpenAll");
6300 game_status = GAME_MODE_LOADING;
6306 InitGlobal(); /* initialize some global variables */
6308 print_timestamp_time("[init global stuff]");
6310 if (options.execute_command)
6311 Execute_Command(options.execute_command);
6313 if (options.serveronly)
6315 #if defined(PLATFORM_UNIX)
6316 NetworkServer(options.server_port, options.serveronly);
6318 Error(ERR_WARN, "networking only supported in Unix version");
6321 exit(0); /* never reached, server loops forever */
6326 print_timestamp_time("[init setup/config stuff (1)]");
6329 print_timestamp_time("[init setup/config stuff (2)]");
6331 print_timestamp_time("[init setup/config stuff (3)]");
6332 InitArtworkInfo(); /* needed before loading gfx, sound & music */
6333 print_timestamp_time("[init setup/config stuff (4)]");
6334 InitArtworkConfig(); /* needed before forking sound child process */
6335 print_timestamp_time("[init setup/config stuff (5)]");
6337 print_timestamp_time("[init setup/config stuff (6)]");
6343 InitRND(NEW_RANDOMIZE);
6344 InitSimpleRandom(NEW_RANDOMIZE);
6348 print_timestamp_time("[init setup/config stuff]");
6351 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
6353 InitEventFilter(FilterEvents);
6355 print_timestamp_time("[init video stuff]");
6357 InitElementPropertiesStatic();
6358 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
6359 InitElementPropertiesGfxElement();
6361 print_timestamp_time("[init element properties stuff]");
6365 print_timestamp_time("InitGfx");
6368 print_timestamp_time("InitLevelInfo");
6370 InitLevelArtworkInfo();
6371 print_timestamp_time("InitLevelArtworkInfo");
6373 InitOverrideArtwork(); /* needs to know current level directory */
6374 print_timestamp_time("InitOverrideArtwork");
6376 InitImages(); /* needs to know current level directory */
6377 print_timestamp_time("InitImages");
6379 InitSound(NULL); /* needs to know current level directory */
6380 print_timestamp_time("InitSound");
6382 InitMusic(NULL); /* needs to know current level directory */
6383 print_timestamp_time("InitMusic");
6385 InitGfxBackground();
6395 if (global.autoplay_leveldir)
6400 else if (global.convert_leveldir)
6405 else if (global.create_images_dir)
6407 CreateLevelSketchImages();
6411 game_status = GAME_MODE_MAIN;
6414 FadeSetEnterScreen();
6415 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
6416 FadeSkipNextFadeOut();
6417 // FadeSetDisabled();
6419 fading = fading_none;
6422 print_timestamp_time("[post-artwork]");
6424 print_timestamp_done("OpenAll");
6428 InitNetworkServer();
6431 Error(ERR_DEBUG, "::: SDL_GetBasePath() == '%s'",
6433 Error(ERR_DEBUG, "::: SDL_GetPrefPath() == '%s'",
6434 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
6435 #if defined(PLATFORM_ANDROID)
6436 Error(ERR_DEBUG, "::: SDL_AndroidGetInternalStoragePath() == '%s'",
6437 SDL_AndroidGetInternalStoragePath());
6438 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStoragePath() == '%s'",
6439 SDL_AndroidGetExternalStoragePath());
6440 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStorageState() == '%s'",
6441 (SDL_AndroidGetExternalStorageState() ==
6442 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "read" :
6443 SDL_AndroidGetExternalStorageState() ==
6444 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "write" : "not available"));
6449 void CloseAllAndExit(int exit_value)
6454 CloseAudio(); /* called after freeing sounds (needed for SDL) */
6466 #if defined(TARGET_SDL)
6467 #if defined(TARGET_SDL2)
6469 // set a flag to tell the network server thread to quit and wait for it
6470 // using SDL_WaitThread()
6472 if (network_server) /* terminate network server */
6473 SDL_KillThread(server_thread);
6477 CloseVideoDisplay();
6478 ClosePlatformDependentStuff();
6480 if (exit_value != 0)
6482 /* fall back to default level set (current set may have caused an error) */
6483 SaveLevelSetup_LastSeries_Deactivate();
6485 /* tell user where to find error log file which may contain more details */
6486 // (error notification now directly displayed on screen inside R'n'D
6487 // NotifyUserAboutErrorFile(); /* currently only works for Windows */