1 // ============================================================================
2 // Rocks'n'Diamonds - McDuffin Strikes Back!
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
7 // http://www.artsoft.org/
8 // ----------------------------------------------------------------------------
10 // ============================================================================
12 #include "libgame/libgame.h"
27 #include "conf_e2g.c" /* include auto-generated data structure definitions */
28 #include "conf_esg.c" /* include auto-generated data structure definitions */
29 #include "conf_e2s.c" /* include auto-generated data structure definitions */
30 #include "conf_fnt.c" /* include auto-generated data structure definitions */
31 #include "conf_g2s.c" /* include auto-generated data structure definitions */
32 #include "conf_g2m.c" /* include auto-generated data structure definitions */
33 #include "conf_act.c" /* include auto-generated data structure definitions */
36 #define CONFIG_TOKEN_FONT_INITIAL "font.initial"
37 #define CONFIG_TOKEN_GLOBAL_BUSY "global.busy"
40 static struct FontBitmapInfo font_initial[NUM_INITIAL_FONTS];
41 static struct GraphicInfo anim_initial;
43 static int copy_properties[][5] =
47 EL_BUG_LEFT, EL_BUG_RIGHT,
48 EL_BUG_UP, EL_BUG_DOWN
52 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
53 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
57 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
58 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
62 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
63 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
67 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
68 EL_PACMAN_UP, EL_PACMAN_DOWN
72 EL_YAMYAM_LEFT, EL_YAMYAM_RIGHT,
73 EL_YAMYAM_UP, EL_YAMYAM_DOWN
77 EL_MOLE_LEFT, EL_MOLE_RIGHT,
78 EL_MOLE_UP, EL_MOLE_DOWN
89 struct GraphicInfo *graphic_info_last = graphic_info;
91 static unsigned int action_delay = 0;
92 unsigned int action_delay_value = GameFrameDelay;
93 int sync_frame = FrameCounter;
96 if (game_status != GAME_MODE_LOADING)
99 if (anim_initial.bitmap == NULL || window == NULL)
102 if (!DelayReached(&action_delay, action_delay_value))
105 x = ALIGNED_TEXT_XPOS(&init_last.busy);
106 y = ALIGNED_TEXT_YPOS(&init_last.busy);
108 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
110 if (sync_frame % anim_initial.anim_delay == 0)
114 int width = graphic_info[graphic].width;
115 int height = graphic_info[graphic].height;
116 int frame = getGraphicAnimationFrame(graphic, sync_frame);
118 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
119 BlitBitmap(src_bitmap, window, src_x, src_y, width, height, x, y);
122 graphic_info = graphic_info_last;
129 FreeLevelEditorGadgets();
138 static boolean gadgets_initialized = FALSE;
140 if (gadgets_initialized)
143 CreateLevelEditorGadgets();
147 CreateScreenGadgets();
149 InitGadgetsSoundCallback(PlaySoundActivating, PlaySoundSelecting);
151 gadgets_initialized = TRUE;
154 inline void InitElementSmallImagesScaledUp(int graphic)
156 struct GraphicInfo *g = &graphic_info[graphic];
158 // create small and game tile sized bitmaps (and scale up, if needed)
159 CreateImageWithSmallImages(graphic, g->scale_up_factor, g->tile_size);
162 void InitElementSmallImages()
164 print_timestamp_init("InitElementSmallImages");
166 static int special_graphics[] =
168 IMG_EDITOR_ELEMENT_BORDER,
169 IMG_EDITOR_ELEMENT_BORDER_INPUT,
170 IMG_EDITOR_CASCADE_LIST,
171 IMG_EDITOR_CASCADE_LIST_ACTIVE,
174 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
175 int num_property_mappings = getImageListPropertyMappingSize();
178 print_timestamp_time("getImageListPropertyMapping/Size");
180 print_timestamp_init("InitElementSmallImagesScaledUp (1)");
181 /* initialize normal images from static configuration */
182 for (i = 0; element_to_graphic[i].element > -1; i++)
183 InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
184 print_timestamp_done("InitElementSmallImagesScaledUp (1)");
186 /* initialize special images from static configuration */
187 for (i = 0; element_to_special_graphic[i].element > -1; i++)
188 InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
189 print_timestamp_time("InitElementSmallImagesScaledUp (2)");
191 /* initialize images from dynamic configuration (may be elements or other) */
192 for (i = 0; i < num_property_mappings; i++)
193 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
194 print_timestamp_time("InitElementSmallImagesScaledUp (3)");
196 /* initialize special images from above list (non-element images) */
197 for (i = 0; special_graphics[i] > -1; i++)
198 InitElementSmallImagesScaledUp(special_graphics[i]);
199 print_timestamp_time("InitElementSmallImagesScaledUp (4)");
201 print_timestamp_done("InitElementSmallImages");
204 void InitScaledImages()
208 /* scale normal images from static configuration, if not already scaled */
209 for (i = 0; i < NUM_IMAGE_FILES; i++)
210 ScaleImage(i, graphic_info[i].scale_up_factor);
213 void InitBitmapPointers()
215 int num_images = getImageListSize();
218 // standard size bitmap may have changed -- update default bitmap pointer
219 for (i = 0; i < num_images; i++)
220 if (graphic_info[i].bitmaps)
221 graphic_info[i].bitmap = graphic_info[i].bitmaps[IMG_BITMAP_STANDARD];
225 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
226 void SetBitmaps_EM(Bitmap **em_bitmap)
228 em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
229 em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].bitmap;
234 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
235 void SetBitmaps_SP(Bitmap **sp_bitmap)
237 *sp_bitmap = graphic_info[IMG_SP_OBJECTS].bitmap;
241 static int getFontBitmapID(int font_nr)
245 /* (special case: do not use special font for GAME_MODE_LOADING) */
246 if (game_status >= GAME_MODE_TITLE_INITIAL &&
247 game_status <= GAME_MODE_PSEUDO_PREVIEW)
248 special = game_status;
249 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
250 special = GFX_SPECIAL_ARG_MAIN;
253 return font_info[font_nr].special_bitmap_id[special];
258 static int getFontFromToken(char *token)
260 char *value = getHashEntry(font_token_hash, token);
265 /* if font not found, use reliable default value */
266 return FONT_INITIAL_1;
269 void InitFontGraphicInfo()
271 static struct FontBitmapInfo *font_bitmap_info = NULL;
272 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
273 int num_property_mappings = getImageListPropertyMappingSize();
274 int num_font_bitmaps = NUM_FONTS;
277 if (graphic_info == NULL) /* still at startup phase */
279 InitFontInfo(font_initial, NUM_INITIAL_FONTS,
280 getFontBitmapID, getFontFromToken);
285 /* ---------- initialize font graphic definitions ---------- */
287 /* always start with reliable default values (normal font graphics) */
288 for (i = 0; i < NUM_FONTS; i++)
289 font_info[i].graphic = IMG_FONT_INITIAL_1;
291 /* initialize normal font/graphic mapping from static configuration */
292 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
294 int font_nr = font_to_graphic[i].font_nr;
295 int special = font_to_graphic[i].special;
296 int graphic = font_to_graphic[i].graphic;
301 font_info[font_nr].graphic = graphic;
304 /* always start with reliable default values (special font graphics) */
305 for (i = 0; i < NUM_FONTS; i++)
307 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
309 font_info[i].special_graphic[j] = font_info[i].graphic;
310 font_info[i].special_bitmap_id[j] = i;
314 /* initialize special font/graphic mapping from static configuration */
315 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
317 int font_nr = font_to_graphic[i].font_nr;
318 int special = font_to_graphic[i].special;
319 int graphic = font_to_graphic[i].graphic;
320 int base_graphic = font2baseimg(font_nr);
322 if (IS_SPECIAL_GFX_ARG(special))
324 boolean base_redefined =
325 getImageListEntryFromImageID(base_graphic)->redefined;
326 boolean special_redefined =
327 getImageListEntryFromImageID(graphic)->redefined;
328 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
330 /* if the base font ("font.title_1", for example) has been redefined,
331 but not the special font ("font.title_1.LEVELS", for example), do not
332 use an existing (in this case considered obsolete) special font
333 anymore, but use the automatically determined default font */
334 /* special case: cloned special fonts must be explicitly redefined,
335 but are not automatically redefined by redefining base font */
336 if (base_redefined && !special_redefined && !special_cloned)
339 font_info[font_nr].special_graphic[special] = graphic;
340 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
345 /* initialize special font/graphic mapping from dynamic configuration */
346 for (i = 0; i < num_property_mappings; i++)
348 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
349 int special = property_mapping[i].ext3_index;
350 int graphic = property_mapping[i].artwork_index;
355 if (IS_SPECIAL_GFX_ARG(special))
357 font_info[font_nr].special_graphic[special] = graphic;
358 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
363 /* correct special font/graphic mapping for cloned fonts for downwards
364 compatibility of PREVIEW fonts -- this is only needed for implicit
365 redefinition of special font by redefined base font, and only if other
366 fonts are cloned from this special font (like in the "Zelda" level set) */
367 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
369 int font_nr = font_to_graphic[i].font_nr;
370 int special = font_to_graphic[i].special;
371 int graphic = font_to_graphic[i].graphic;
373 if (IS_SPECIAL_GFX_ARG(special))
375 boolean special_redefined =
376 getImageListEntryFromImageID(graphic)->redefined;
377 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
379 if (special_cloned && !special_redefined)
383 for (j = 0; font_to_graphic[j].font_nr > -1; j++)
385 int font_nr2 = font_to_graphic[j].font_nr;
386 int special2 = font_to_graphic[j].special;
387 int graphic2 = font_to_graphic[j].graphic;
389 if (IS_SPECIAL_GFX_ARG(special2) &&
390 graphic2 == graphic_info[graphic].clone_from)
392 font_info[font_nr].special_graphic[special] =
393 font_info[font_nr2].special_graphic[special2];
394 font_info[font_nr].special_bitmap_id[special] =
395 font_info[font_nr2].special_bitmap_id[special2];
402 /* reset non-redefined ".active" font graphics if normal font is redefined */
403 /* (this different treatment is needed because normal and active fonts are
404 independently defined ("active" is not a property of font definitions!) */
405 for (i = 0; i < NUM_FONTS; i++)
407 int font_nr_base = i;
408 int font_nr_active = FONT_ACTIVE(font_nr_base);
410 /* check only those fonts with exist as normal and ".active" variant */
411 if (font_nr_base != font_nr_active)
413 int base_graphic = font_info[font_nr_base].graphic;
414 int active_graphic = font_info[font_nr_active].graphic;
415 boolean base_redefined =
416 getImageListEntryFromImageID(base_graphic)->redefined;
417 boolean active_redefined =
418 getImageListEntryFromImageID(active_graphic)->redefined;
420 /* if the base font ("font.menu_1", for example) has been redefined,
421 but not the active font ("font.menu_1.active", for example), do not
422 use an existing (in this case considered obsolete) active font
423 anymore, but use the automatically determined default font */
424 if (base_redefined && !active_redefined)
425 font_info[font_nr_active].graphic = base_graphic;
427 /* now also check each "special" font (which may be the same as above) */
428 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
430 int base_graphic = font_info[font_nr_base].special_graphic[j];
431 int active_graphic = font_info[font_nr_active].special_graphic[j];
432 boolean base_redefined =
433 getImageListEntryFromImageID(base_graphic)->redefined;
434 boolean active_redefined =
435 getImageListEntryFromImageID(active_graphic)->redefined;
437 /* same as above, but check special graphic definitions, for example:
438 redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN" */
439 if (base_redefined && !active_redefined)
441 font_info[font_nr_active].special_graphic[j] =
442 font_info[font_nr_base].special_graphic[j];
443 font_info[font_nr_active].special_bitmap_id[j] =
444 font_info[font_nr_base].special_bitmap_id[j];
450 /* ---------- initialize font bitmap array ---------- */
452 if (font_bitmap_info != NULL)
453 FreeFontInfo(font_bitmap_info);
456 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
458 /* ---------- initialize font bitmap definitions ---------- */
460 for (i = 0; i < NUM_FONTS; i++)
462 if (i < NUM_INITIAL_FONTS)
464 font_bitmap_info[i] = font_initial[i];
468 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
470 int font_bitmap_id = font_info[i].special_bitmap_id[j];
471 int graphic = font_info[i].special_graphic[j];
473 /* set 'graphic_info' for font entries, if uninitialized (guessed) */
474 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
476 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
477 graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
480 /* copy font relevant information from graphics information */
481 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
482 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
483 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
484 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
485 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
487 font_bitmap_info[font_bitmap_id].draw_xoffset =
488 graphic_info[graphic].draw_xoffset;
489 font_bitmap_info[font_bitmap_id].draw_yoffset =
490 graphic_info[graphic].draw_yoffset;
492 font_bitmap_info[font_bitmap_id].num_chars =
493 graphic_info[graphic].anim_frames;
494 font_bitmap_info[font_bitmap_id].num_chars_per_line =
495 graphic_info[graphic].anim_frames_per_line;
499 InitFontInfo(font_bitmap_info, num_font_bitmaps,
500 getFontBitmapID, getFontFromToken);
503 void InitElementGraphicInfo()
505 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
506 int num_property_mappings = getImageListPropertyMappingSize();
509 if (graphic_info == NULL) /* still at startup phase */
512 /* set values to -1 to identify later as "uninitialized" values */
513 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
515 for (act = 0; act < NUM_ACTIONS; act++)
517 element_info[i].graphic[act] = -1;
518 element_info[i].crumbled[act] = -1;
520 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
522 element_info[i].direction_graphic[act][dir] = -1;
523 element_info[i].direction_crumbled[act][dir] = -1;
530 /* initialize normal element/graphic mapping from static configuration */
531 for (i = 0; element_to_graphic[i].element > -1; i++)
533 int element = element_to_graphic[i].element;
534 int action = element_to_graphic[i].action;
535 int direction = element_to_graphic[i].direction;
536 boolean crumbled = element_to_graphic[i].crumbled;
537 int graphic = element_to_graphic[i].graphic;
538 int base_graphic = el2baseimg(element);
540 if (graphic_info[graphic].bitmap == NULL)
543 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
546 boolean base_redefined =
547 getImageListEntryFromImageID(base_graphic)->redefined;
548 boolean act_dir_redefined =
549 getImageListEntryFromImageID(graphic)->redefined;
551 /* if the base graphic ("emerald", for example) has been redefined,
552 but not the action graphic ("emerald.falling", for example), do not
553 use an existing (in this case considered obsolete) action graphic
554 anymore, but use the automatically determined default graphic */
555 if (base_redefined && !act_dir_redefined)
560 action = ACTION_DEFAULT;
565 element_info[element].direction_crumbled[action][direction] = graphic;
567 element_info[element].crumbled[action] = graphic;
572 element_info[element].direction_graphic[action][direction] = graphic;
574 element_info[element].graphic[action] = graphic;
578 /* initialize normal element/graphic mapping from dynamic configuration */
579 for (i = 0; i < num_property_mappings; i++)
581 int element = property_mapping[i].base_index;
582 int action = property_mapping[i].ext1_index;
583 int direction = property_mapping[i].ext2_index;
584 int special = property_mapping[i].ext3_index;
585 int graphic = property_mapping[i].artwork_index;
586 boolean crumbled = FALSE;
588 if (special == GFX_SPECIAL_ARG_CRUMBLED)
594 if (graphic_info[graphic].bitmap == NULL)
597 if (element >= MAX_NUM_ELEMENTS || special != -1)
601 action = ACTION_DEFAULT;
606 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
607 element_info[element].direction_crumbled[action][dir] = -1;
610 element_info[element].direction_crumbled[action][direction] = graphic;
612 element_info[element].crumbled[action] = graphic;
617 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
618 element_info[element].direction_graphic[action][dir] = -1;
621 element_info[element].direction_graphic[action][direction] = graphic;
623 element_info[element].graphic[action] = graphic;
627 /* now copy all graphics that are defined to be cloned from other graphics */
628 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
630 int graphic = element_info[i].graphic[ACTION_DEFAULT];
631 int crumbled_like, diggable_like;
636 crumbled_like = graphic_info[graphic].crumbled_like;
637 diggable_like = graphic_info[graphic].diggable_like;
639 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
641 for (act = 0; act < NUM_ACTIONS; act++)
642 element_info[i].crumbled[act] =
643 element_info[crumbled_like].crumbled[act];
644 for (act = 0; act < NUM_ACTIONS; act++)
645 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
646 element_info[i].direction_crumbled[act][dir] =
647 element_info[crumbled_like].direction_crumbled[act][dir];
650 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
652 element_info[i].graphic[ACTION_DIGGING] =
653 element_info[diggable_like].graphic[ACTION_DIGGING];
654 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
655 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
656 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
660 /* set hardcoded definitions for some runtime elements without graphic */
661 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
663 /* set hardcoded definitions for some internal elements without graphic */
664 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
666 if (IS_EDITOR_CASCADE_INACTIVE(i))
667 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
668 else if (IS_EDITOR_CASCADE_ACTIVE(i))
669 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
672 /* now set all undefined/invalid graphics to -1 to set to default after it */
673 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
675 for (act = 0; act < NUM_ACTIONS; act++)
679 graphic = element_info[i].graphic[act];
680 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
681 element_info[i].graphic[act] = -1;
683 graphic = element_info[i].crumbled[act];
684 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
685 element_info[i].crumbled[act] = -1;
687 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
689 graphic = element_info[i].direction_graphic[act][dir];
690 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
691 element_info[i].direction_graphic[act][dir] = -1;
693 graphic = element_info[i].direction_crumbled[act][dir];
694 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
695 element_info[i].direction_crumbled[act][dir] = -1;
702 /* adjust graphics with 2nd tile for movement according to direction
703 (do this before correcting '-1' values to minimize calculations) */
704 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
706 for (act = 0; act < NUM_ACTIONS; act++)
708 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
710 int graphic = element_info[i].direction_graphic[act][dir];
711 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
713 if (act == ACTION_FALLING) /* special case */
714 graphic = element_info[i].graphic[act];
717 graphic_info[graphic].double_movement &&
718 graphic_info[graphic].swap_double_tiles != 0)
720 struct GraphicInfo *g = &graphic_info[graphic];
721 int src_x_front = g->src_x;
722 int src_y_front = g->src_y;
723 int src_x_back = g->src_x + g->offset2_x;
724 int src_y_back = g->src_y + g->offset2_y;
725 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
727 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
728 src_y_front < src_y_back);
729 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
730 boolean swap_movement_tiles_autodetected =
731 (!frames_are_ordered_diagonally &&
732 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
733 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
734 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
735 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
738 /* swap frontside and backside graphic tile coordinates, if needed */
739 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
741 /* get current (wrong) backside tile coordinates */
742 getFixedGraphicSourceExt(graphic, 0, &dummy,
743 &src_x_back, &src_y_back, TRUE);
745 /* set frontside tile coordinates to backside tile coordinates */
746 g->src_x = src_x_back;
747 g->src_y = src_y_back;
749 /* invert tile offset to point to new backside tile coordinates */
753 /* do not swap front and backside tiles again after correction */
754 g->swap_double_tiles = 0;
763 /* now set all '-1' values to element specific default values */
764 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
766 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
767 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
768 int default_direction_graphic[NUM_DIRECTIONS_FULL];
769 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
771 if (default_graphic == -1)
772 default_graphic = IMG_UNKNOWN;
774 if (default_crumbled == -1)
775 default_crumbled = default_graphic;
777 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
779 default_direction_graphic[dir] =
780 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
781 default_direction_crumbled[dir] =
782 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
784 if (default_direction_graphic[dir] == -1)
785 default_direction_graphic[dir] = default_graphic;
787 if (default_direction_crumbled[dir] == -1)
788 default_direction_crumbled[dir] = default_direction_graphic[dir];
791 for (act = 0; act < NUM_ACTIONS; act++)
793 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
794 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
795 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
796 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
797 act == ACTION_TURNING_FROM_RIGHT ||
798 act == ACTION_TURNING_FROM_UP ||
799 act == ACTION_TURNING_FROM_DOWN);
801 /* generic default action graphic (defined by "[default]" directive) */
802 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
803 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
804 int default_remove_graphic = IMG_EMPTY;
806 if (act_remove && default_action_graphic != -1)
807 default_remove_graphic = default_action_graphic;
809 /* look for special default action graphic (classic game specific) */
810 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
811 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
812 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
813 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
814 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
815 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
817 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
818 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
819 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
820 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
821 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
822 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
824 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
825 /* !!! make this better !!! */
826 if (i == EL_EMPTY_SPACE)
828 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
829 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
832 if (default_action_graphic == -1)
833 default_action_graphic = default_graphic;
835 if (default_action_crumbled == -1)
836 default_action_crumbled = default_action_graphic;
838 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
840 /* use action graphic as the default direction graphic, if undefined */
841 int default_action_direction_graphic = element_info[i].graphic[act];
842 int default_action_direction_crumbled = element_info[i].crumbled[act];
844 /* no graphic for current action -- use default direction graphic */
845 if (default_action_direction_graphic == -1)
846 default_action_direction_graphic =
847 (act_remove ? default_remove_graphic :
849 element_info[i].direction_graphic[ACTION_TURNING][dir] :
850 default_action_graphic != default_graphic ?
851 default_action_graphic :
852 default_direction_graphic[dir]);
854 if (element_info[i].direction_graphic[act][dir] == -1)
855 element_info[i].direction_graphic[act][dir] =
856 default_action_direction_graphic;
858 if (default_action_direction_crumbled == -1)
859 default_action_direction_crumbled =
860 element_info[i].direction_graphic[act][dir];
862 if (element_info[i].direction_crumbled[act][dir] == -1)
863 element_info[i].direction_crumbled[act][dir] =
864 default_action_direction_crumbled;
867 /* no graphic for this specific action -- use default action graphic */
868 if (element_info[i].graphic[act] == -1)
869 element_info[i].graphic[act] =
870 (act_remove ? default_remove_graphic :
871 act_turning ? element_info[i].graphic[ACTION_TURNING] :
872 default_action_graphic);
874 if (element_info[i].crumbled[act] == -1)
875 element_info[i].crumbled[act] = element_info[i].graphic[act];
882 void InitElementSpecialGraphicInfo()
884 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
885 int num_property_mappings = getImageListPropertyMappingSize();
888 /* always start with reliable default values */
889 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
890 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
891 element_info[i].special_graphic[j] =
892 element_info[i].graphic[ACTION_DEFAULT];
894 /* initialize special element/graphic mapping from static configuration */
895 for (i = 0; element_to_special_graphic[i].element > -1; i++)
897 int element = element_to_special_graphic[i].element;
898 int special = element_to_special_graphic[i].special;
899 int graphic = element_to_special_graphic[i].graphic;
900 int base_graphic = el2baseimg(element);
901 boolean base_redefined =
902 getImageListEntryFromImageID(base_graphic)->redefined;
903 boolean special_redefined =
904 getImageListEntryFromImageID(graphic)->redefined;
906 /* if the base graphic ("emerald", for example) has been redefined,
907 but not the special graphic ("emerald.EDITOR", for example), do not
908 use an existing (in this case considered obsolete) special graphic
909 anymore, but use the automatically created (down-scaled) graphic */
910 if (base_redefined && !special_redefined)
913 element_info[element].special_graphic[special] = graphic;
916 /* initialize special element/graphic mapping from dynamic configuration */
917 for (i = 0; i < num_property_mappings; i++)
919 int element = property_mapping[i].base_index;
920 int action = property_mapping[i].ext1_index;
921 int direction = property_mapping[i].ext2_index;
922 int special = property_mapping[i].ext3_index;
923 int graphic = property_mapping[i].artwork_index;
925 /* for action ".active", replace element with active element, if exists */
926 if (action == ACTION_ACTIVE && element != ELEMENT_ACTIVE(element))
928 element = ELEMENT_ACTIVE(element);
932 if (element >= MAX_NUM_ELEMENTS)
935 /* do not change special graphic if action or direction was specified */
936 if (action != -1 || direction != -1)
939 if (IS_SPECIAL_GFX_ARG(special))
940 element_info[element].special_graphic[special] = graphic;
943 /* now set all undefined/invalid graphics to default */
944 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
945 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
946 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
947 element_info[i].special_graphic[j] =
948 element_info[i].graphic[ACTION_DEFAULT];
951 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
953 if (type != TYPE_ELEMENT && type != TYPE_GRAPHIC)
954 return get_parameter_value(value_raw, suffix, type);
956 if (strEqual(value_raw, ARG_UNDEFINED))
957 return ARG_UNDEFINED_VALUE;
959 if (type == TYPE_ELEMENT)
961 char *value = getHashEntry(element_token_hash, value_raw);
965 Error(ERR_INFO_LINE, "-");
966 Error(ERR_INFO, "warning: error found in config file:");
967 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
968 Error(ERR_INFO, "error: invalid element token '%s'", value_raw);
969 Error(ERR_INFO, "custom graphic rejected for this element/action");
970 Error(ERR_INFO, "fallback done to undefined element for this graphic");
971 Error(ERR_INFO_LINE, "-");
974 return (value != NULL ? atoi(value) : EL_UNDEFINED);
976 else if (type == TYPE_GRAPHIC)
978 char *value = getHashEntry(graphic_token_hash, value_raw);
979 int fallback_graphic = IMG_CHAR_EXCLAM;
983 Error(ERR_INFO_LINE, "-");
984 Error(ERR_INFO, "warning: error found in config file:");
985 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
986 Error(ERR_INFO, "error: invalid graphic token '%s'", value_raw);
987 Error(ERR_INFO, "custom graphic rejected for this element/action");
988 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
989 Error(ERR_INFO_LINE, "-");
992 return (value != NULL ? atoi(value) : fallback_graphic);
998 static int get_scaled_graphic_width(int graphic)
1000 int original_width = getOriginalImageWidthFromImageID(graphic);
1001 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1003 return original_width * scale_up_factor;
1006 static int get_scaled_graphic_height(int graphic)
1008 int original_height = getOriginalImageHeightFromImageID(graphic);
1009 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1011 return original_height * scale_up_factor;
1014 static void set_graphic_parameters_ext(int graphic, int *parameter,
1015 Bitmap **src_bitmaps)
1017 struct GraphicInfo *g = &graphic_info[graphic];
1018 Bitmap *src_bitmap = (src_bitmaps ? src_bitmaps[IMG_BITMAP_STANDARD] : NULL);
1019 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1020 int anim_frames_per_line = 1;
1022 /* always start with reliable default values */
1023 g->src_image_width = 0;
1024 g->src_image_height = 0;
1027 g->width = TILEX; /* default for element graphics */
1028 g->height = TILEY; /* default for element graphics */
1029 g->offset_x = 0; /* one or both of these values ... */
1030 g->offset_y = 0; /* ... will be corrected later */
1031 g->offset2_x = 0; /* one or both of these values ... */
1032 g->offset2_y = 0; /* ... will be corrected later */
1033 g->swap_double_tiles = -1; /* auto-detect tile swapping */
1034 g->crumbled_like = -1; /* do not use clone element */
1035 g->diggable_like = -1; /* do not use clone element */
1036 g->border_size = TILEX / 8; /* "CRUMBLED" border size */
1037 g->scale_up_factor = 1; /* default: no scaling up */
1038 g->tile_size = TILESIZE; /* default: standard tile size */
1039 g->clone_from = -1; /* do not use clone graphic */
1040 g->anim_delay_fixed = 0;
1041 g->anim_delay_random = 0;
1042 g->post_delay_fixed = 0;
1043 g->post_delay_random = 0;
1044 g->fade_mode = FADE_MODE_DEFAULT;
1048 g->align = ALIGN_CENTER; /* default for title screens */
1049 g->valign = VALIGN_MIDDLE; /* default for title screens */
1050 g->sort_priority = 0; /* default for title screens */
1052 g->style = STYLE_DEFAULT;
1054 g->bitmaps = src_bitmaps;
1055 g->bitmap = src_bitmap;
1057 /* optional zoom factor for scaling up the image to a larger size */
1058 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1059 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1060 if (g->scale_up_factor < 1)
1061 g->scale_up_factor = 1; /* no scaling */
1063 /* optional tile size for using non-standard image size */
1064 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1066 g->tile_size = parameter[GFX_ARG_TILE_SIZE];
1069 // CHECK: should tile sizes less than standard tile size be allowed?
1070 if (g->tile_size < TILESIZE)
1071 g->tile_size = TILESIZE; /* standard tile size */
1075 // CHECK: when setting tile size, should this set width and height?
1076 g->width = g->tile_size;
1077 g->height = g->tile_size;
1081 if (g->use_image_size)
1083 /* set new default bitmap size (with scaling, but without small images) */
1084 g->width = get_scaled_graphic_width(graphic);
1085 g->height = get_scaled_graphic_height(graphic);
1088 /* optional width and height of each animation frame */
1089 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1090 g->width = parameter[GFX_ARG_WIDTH];
1091 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1092 g->height = parameter[GFX_ARG_HEIGHT];
1094 /* optional x and y tile position of animation frame sequence */
1095 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1096 g->src_x = parameter[GFX_ARG_XPOS] * g->width;
1097 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1098 g->src_y = parameter[GFX_ARG_YPOS] * g->height;
1100 /* optional x and y pixel position of animation frame sequence */
1101 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1102 g->src_x = parameter[GFX_ARG_X];
1103 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1104 g->src_y = parameter[GFX_ARG_Y];
1110 Error(ERR_INFO_LINE, "-");
1111 Error(ERR_WARN, "invalid value %d for '%s.width' (fallback done to %d)",
1112 g->width, getTokenFromImageID(graphic), TILEX);
1113 Error(ERR_INFO_LINE, "-");
1115 g->width = TILEX; /* will be checked to be inside bitmap later */
1120 Error(ERR_INFO_LINE, "-");
1121 Error(ERR_WARN, "invalid value %d for '%s.height' (fallback done to %d)",
1122 g->height, getTokenFromImageID(graphic), TILEY);
1123 Error(ERR_INFO_LINE, "-");
1125 g->height = TILEY; /* will be checked to be inside bitmap later */
1131 /* get final bitmap size (with scaling, but without small images) */
1132 int src_image_width = get_scaled_graphic_width(graphic);
1133 int src_image_height = get_scaled_graphic_height(graphic);
1135 if (src_image_width == 0 || src_image_height == 0)
1137 /* only happens when loaded outside artwork system (like "global.busy") */
1138 src_image_width = src_bitmap->width;
1139 src_image_height = src_bitmap->height;
1142 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1144 anim_frames_per_row = src_image_width / g->tile_size;
1145 anim_frames_per_col = src_image_height / g->tile_size;
1149 anim_frames_per_row = src_image_width / g->width;
1150 anim_frames_per_col = src_image_height / g->height;
1153 g->src_image_width = src_image_width;
1154 g->src_image_height = src_image_height;
1157 /* correct x or y offset dependent of vertical or horizontal frame order */
1158 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1160 g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1161 parameter[GFX_ARG_OFFSET] : g->height);
1162 anim_frames_per_line = anim_frames_per_col;
1164 else /* frames are ordered horizontally */
1166 g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1167 parameter[GFX_ARG_OFFSET] : g->width);
1168 anim_frames_per_line = anim_frames_per_row;
1171 /* optionally, the x and y offset of frames can be specified directly */
1172 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1173 g->offset_x = parameter[GFX_ARG_XOFFSET];
1174 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1175 g->offset_y = parameter[GFX_ARG_YOFFSET];
1177 /* optionally, moving animations may have separate start and end graphics */
1178 g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1180 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1181 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1183 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1184 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1185 g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1186 parameter[GFX_ARG_2ND_OFFSET] : g->height);
1187 else /* frames are ordered horizontally */
1188 g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1189 parameter[GFX_ARG_2ND_OFFSET] : g->width);
1191 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1192 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1193 g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1194 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1195 g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1197 /* optionally, the second movement tile can be specified as start tile */
1198 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1199 g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1201 /* automatically determine correct number of frames, if not defined */
1202 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1203 g->anim_frames = parameter[GFX_ARG_FRAMES];
1204 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1205 g->anim_frames = anim_frames_per_row;
1206 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1207 g->anim_frames = anim_frames_per_col;
1211 if (g->anim_frames == 0) /* frames must be at least 1 */
1214 g->anim_frames_per_line =
1215 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1216 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1218 g->anim_delay = parameter[GFX_ARG_DELAY];
1219 if (g->anim_delay == 0) /* delay must be at least 1 */
1222 g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1224 /* automatically determine correct start frame, if not defined */
1225 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1226 g->anim_start_frame = 0;
1227 else if (g->anim_mode & ANIM_REVERSE)
1228 g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1230 g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1232 /* animation synchronized with global frame counter, not move position */
1233 g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1235 /* optional element for cloning crumble graphics */
1236 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1237 g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1239 /* optional element for cloning digging graphics */
1240 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1241 g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1243 /* optional border size for "crumbling" diggable graphics */
1244 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1245 g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1247 /* this is only used for player "boring" and "sleeping" actions */
1248 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1249 g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1250 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1251 g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1252 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1253 g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1254 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1255 g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1257 /* this is only used for toon animations */
1258 g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1259 g->step_delay = parameter[GFX_ARG_STEP_DELAY];
1261 /* this is only used for drawing font characters */
1262 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1263 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1265 /* this is only used for drawing envelope graphics */
1266 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1268 /* optional graphic for cloning all graphics settings */
1269 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1270 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1272 /* optional settings for drawing title screens and title messages */
1273 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1274 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1275 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1276 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1277 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1278 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1279 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1280 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1281 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1282 g->align = parameter[GFX_ARG_ALIGN];
1283 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1284 g->valign = parameter[GFX_ARG_VALIGN];
1285 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1286 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1288 if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
1289 g->class = parameter[GFX_ARG_CLASS];
1290 if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
1291 g->style = parameter[GFX_ARG_STYLE];
1293 /* this is only used for drawing menu buttons and text */
1294 g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
1295 g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
1296 g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
1297 g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
1300 static void set_graphic_parameters(int graphic)
1302 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1303 char **parameter_raw = image->parameter;
1304 Bitmap **src_bitmaps = getBitmapsFromImageID(graphic);
1305 int parameter[NUM_GFX_ARGS];
1308 /* if fallback to default artwork is done, also use the default parameters */
1309 if (image->fallback_to_default)
1310 parameter_raw = image->default_parameter;
1312 /* get integer values from string parameters */
1313 for (i = 0; i < NUM_GFX_ARGS; i++)
1314 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1315 image_config_suffix[i].token,
1316 image_config_suffix[i].type);
1318 set_graphic_parameters_ext(graphic, parameter, src_bitmaps);
1320 UPDATE_BUSY_STATE();
1323 static void set_cloned_graphic_parameters(int graphic)
1325 int fallback_graphic = IMG_CHAR_EXCLAM;
1326 int max_num_images = getImageListSize();
1327 int clone_graphic = graphic_info[graphic].clone_from;
1328 int num_references_followed = 1;
1330 while (graphic_info[clone_graphic].clone_from != -1 &&
1331 num_references_followed < max_num_images)
1333 clone_graphic = graphic_info[clone_graphic].clone_from;
1335 num_references_followed++;
1338 if (num_references_followed >= max_num_images)
1340 Error(ERR_INFO_LINE, "-");
1341 Error(ERR_INFO, "warning: error found in config file:");
1342 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1343 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1344 Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1345 Error(ERR_INFO, "custom graphic rejected for this element/action");
1347 if (graphic == fallback_graphic)
1348 Error(ERR_EXIT, "no fallback graphic available");
1350 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1351 Error(ERR_INFO_LINE, "-");
1353 graphic_info[graphic] = graphic_info[fallback_graphic];
1357 graphic_info[graphic] = graphic_info[clone_graphic];
1358 graphic_info[graphic].clone_from = clone_graphic;
1362 static void InitGraphicInfo()
1364 int fallback_graphic = IMG_CHAR_EXCLAM;
1365 int num_images = getImageListSize();
1368 /* use image size as default values for width and height for these images */
1369 static int full_size_graphics[] =
1374 IMG_BACKGROUND_ENVELOPE_1,
1375 IMG_BACKGROUND_ENVELOPE_2,
1376 IMG_BACKGROUND_ENVELOPE_3,
1377 IMG_BACKGROUND_ENVELOPE_4,
1378 IMG_BACKGROUND_REQUEST,
1381 IMG_BACKGROUND_TITLE_INITIAL,
1382 IMG_BACKGROUND_TITLE,
1383 IMG_BACKGROUND_MAIN,
1384 IMG_BACKGROUND_LEVELS,
1385 IMG_BACKGROUND_LEVELNR,
1386 IMG_BACKGROUND_SCORES,
1387 IMG_BACKGROUND_EDITOR,
1388 IMG_BACKGROUND_INFO,
1389 IMG_BACKGROUND_INFO_ELEMENTS,
1390 IMG_BACKGROUND_INFO_MUSIC,
1391 IMG_BACKGROUND_INFO_CREDITS,
1392 IMG_BACKGROUND_INFO_PROGRAM,
1393 IMG_BACKGROUND_INFO_VERSION,
1394 IMG_BACKGROUND_INFO_LEVELSET,
1395 IMG_BACKGROUND_SETUP,
1396 IMG_BACKGROUND_PLAYING,
1397 IMG_BACKGROUND_DOOR,
1398 IMG_BACKGROUND_TAPE,
1399 IMG_BACKGROUND_PANEL,
1400 IMG_BACKGROUND_PALETTE,
1401 IMG_BACKGROUND_TOOLBOX,
1403 IMG_TITLESCREEN_INITIAL_1,
1404 IMG_TITLESCREEN_INITIAL_2,
1405 IMG_TITLESCREEN_INITIAL_3,
1406 IMG_TITLESCREEN_INITIAL_4,
1407 IMG_TITLESCREEN_INITIAL_5,
1414 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1,
1415 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2,
1416 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3,
1417 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4,
1418 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5,
1419 IMG_BACKGROUND_TITLEMESSAGE_1,
1420 IMG_BACKGROUND_TITLEMESSAGE_2,
1421 IMG_BACKGROUND_TITLEMESSAGE_3,
1422 IMG_BACKGROUND_TITLEMESSAGE_4,
1423 IMG_BACKGROUND_TITLEMESSAGE_5,
1428 checked_free(graphic_info);
1430 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1432 /* initialize "use_image_size" flag with default value */
1433 for (i = 0; i < num_images; i++)
1434 graphic_info[i].use_image_size = FALSE;
1436 /* initialize "use_image_size" flag from static configuration above */
1437 for (i = 0; full_size_graphics[i] != -1; i++)
1438 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1440 /* first set all graphic paramaters ... */
1441 for (i = 0; i < num_images; i++)
1442 set_graphic_parameters(i);
1444 /* ... then copy these parameters for cloned graphics */
1445 for (i = 0; i < num_images; i++)
1446 if (graphic_info[i].clone_from != -1)
1447 set_cloned_graphic_parameters(i);
1449 for (i = 0; i < num_images; i++)
1454 int first_frame, last_frame;
1455 int src_bitmap_width, src_bitmap_height;
1457 /* now check if no animation frames are outside of the loaded image */
1459 if (graphic_info[i].bitmap == NULL)
1460 continue; /* skip check for optional images that are undefined */
1462 /* get image size (this can differ from the standard element tile size!) */
1463 width = graphic_info[i].width;
1464 height = graphic_info[i].height;
1466 /* get final bitmap size (with scaling, but without small images) */
1467 src_bitmap_width = graphic_info[i].src_image_width;
1468 src_bitmap_height = graphic_info[i].src_image_height;
1470 /* check if first animation frame is inside specified bitmap */
1473 getFixedGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1475 /* this avoids calculating wrong start position for out-of-bounds frame */
1476 src_x = graphic_info[i].src_x;
1477 src_y = graphic_info[i].src_y;
1479 if (src_x < 0 || src_y < 0 ||
1480 src_x + width > src_bitmap_width ||
1481 src_y + height > src_bitmap_height)
1483 Error(ERR_INFO_LINE, "-");
1484 Error(ERR_INFO, "warning: error found in config file:");
1485 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1486 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1487 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1489 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1490 src_x, src_y, src_bitmap_width, src_bitmap_height);
1491 Error(ERR_INFO, "custom graphic rejected for this element/action");
1493 if (i == fallback_graphic)
1494 Error(ERR_EXIT, "no fallback graphic available");
1496 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1497 Error(ERR_INFO_LINE, "-");
1499 graphic_info[i] = graphic_info[fallback_graphic];
1502 /* check if last animation frame is inside specified bitmap */
1504 last_frame = graphic_info[i].anim_frames - 1;
1505 getFixedGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1507 if (src_x < 0 || src_y < 0 ||
1508 src_x + width > src_bitmap_width ||
1509 src_y + height > src_bitmap_height)
1511 Error(ERR_INFO_LINE, "-");
1512 Error(ERR_INFO, "warning: error found in config file:");
1513 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1514 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1515 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1517 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1518 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1519 Error(ERR_INFO, "::: %d, %d", width, height);
1520 Error(ERR_INFO, "custom graphic rejected for this element/action");
1522 if (i == fallback_graphic)
1523 Error(ERR_EXIT, "no fallback graphic available");
1525 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1526 Error(ERR_INFO_LINE, "-");
1528 graphic_info[i] = graphic_info[fallback_graphic];
1533 static void InitGraphicCompatibilityInfo()
1535 struct FileInfo *fi_global_door =
1536 getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1537 int num_images = getImageListSize();
1540 /* the following compatibility handling is needed for the following case:
1541 versions up to 3.3.0.0 used one large bitmap "global.door" for various
1542 graphics mainly used for door and panel graphics, like editor, tape and
1543 in-game buttons with hard-coded bitmap positions and button sizes; as
1544 these graphics now have individual definitions, redefining "global.door"
1545 to change all these graphics at once like before does not work anymore
1546 (because all those individual definitions still have their default values);
1547 to solve this, remap all those individual definitions that are not
1548 redefined to the new bitmap of "global.door" if it was redefined */
1550 /* special compatibility handling if image "global.door" was redefined */
1551 if (fi_global_door->redefined)
1553 for (i = 0; i < num_images; i++)
1555 struct FileInfo *fi = getImageListEntryFromImageID(i);
1557 /* process only those images that still use the default settings */
1560 /* process all images which default to same image as "global.door" */
1561 if (strEqual(fi->default_filename, fi_global_door->default_filename))
1563 // printf("::: special treatment needed for token '%s'\n", fi->token);
1565 graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
1571 InitGraphicCompatibilityInfo_Doors();
1574 static void InitElementSoundInfo()
1576 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1577 int num_property_mappings = getSoundListPropertyMappingSize();
1580 /* set values to -1 to identify later as "uninitialized" values */
1581 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1582 for (act = 0; act < NUM_ACTIONS; act++)
1583 element_info[i].sound[act] = -1;
1585 /* initialize element/sound mapping from static configuration */
1586 for (i = 0; element_to_sound[i].element > -1; i++)
1588 int element = element_to_sound[i].element;
1589 int action = element_to_sound[i].action;
1590 int sound = element_to_sound[i].sound;
1591 boolean is_class = element_to_sound[i].is_class;
1594 action = ACTION_DEFAULT;
1597 element_info[element].sound[action] = sound;
1599 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1600 if (strEqual(element_info[j].class_name,
1601 element_info[element].class_name))
1602 element_info[j].sound[action] = sound;
1605 /* initialize element class/sound mapping from dynamic configuration */
1606 for (i = 0; i < num_property_mappings; i++)
1608 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1609 int action = property_mapping[i].ext1_index;
1610 int sound = property_mapping[i].artwork_index;
1612 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1616 action = ACTION_DEFAULT;
1618 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1619 if (strEqual(element_info[j].class_name,
1620 element_info[element_class].class_name))
1621 element_info[j].sound[action] = sound;
1624 /* initialize element/sound mapping from dynamic configuration */
1625 for (i = 0; i < num_property_mappings; i++)
1627 int element = property_mapping[i].base_index;
1628 int action = property_mapping[i].ext1_index;
1629 int sound = property_mapping[i].artwork_index;
1631 if (element >= MAX_NUM_ELEMENTS)
1635 action = ACTION_DEFAULT;
1637 element_info[element].sound[action] = sound;
1640 /* now set all '-1' values to element specific default values */
1641 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1643 for (act = 0; act < NUM_ACTIONS; act++)
1645 /* generic default action sound (defined by "[default]" directive) */
1646 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1648 /* look for special default action sound (classic game specific) */
1649 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1650 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1651 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1652 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1653 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1654 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1656 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1657 /* !!! make this better !!! */
1658 if (i == EL_EMPTY_SPACE)
1659 default_action_sound = element_info[EL_DEFAULT].sound[act];
1661 /* no sound for this specific action -- use default action sound */
1662 if (element_info[i].sound[act] == -1)
1663 element_info[i].sound[act] = default_action_sound;
1667 /* copy sound settings to some elements that are only stored in level file
1668 in native R'n'D levels, but are used by game engine in native EM levels */
1669 for (i = 0; copy_properties[i][0] != -1; i++)
1670 for (j = 1; j <= 4; j++)
1671 for (act = 0; act < NUM_ACTIONS; act++)
1672 element_info[copy_properties[i][j]].sound[act] =
1673 element_info[copy_properties[i][0]].sound[act];
1676 static void InitGameModeSoundInfo()
1680 /* set values to -1 to identify later as "uninitialized" values */
1681 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1684 /* initialize gamemode/sound mapping from static configuration */
1685 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1687 int gamemode = gamemode_to_sound[i].gamemode;
1688 int sound = gamemode_to_sound[i].sound;
1691 gamemode = GAME_MODE_DEFAULT;
1693 menu.sound[gamemode] = sound;
1696 /* now set all '-1' values to levelset specific default values */
1697 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1698 if (menu.sound[i] == -1)
1699 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1702 static void set_sound_parameters(int sound, char **parameter_raw)
1704 int parameter[NUM_SND_ARGS];
1707 /* get integer values from string parameters */
1708 for (i = 0; i < NUM_SND_ARGS; i++)
1710 get_parameter_value(parameter_raw[i],
1711 sound_config_suffix[i].token,
1712 sound_config_suffix[i].type);
1714 /* explicit loop mode setting in configuration overrides default value */
1715 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1716 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1718 /* sound volume to change the original volume when loading the sound file */
1719 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1721 /* sound priority to give certain sounds a higher or lower priority */
1722 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
1725 static void InitSoundInfo()
1727 int *sound_effect_properties;
1728 int num_sounds = getSoundListSize();
1731 checked_free(sound_info);
1733 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1734 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1736 /* initialize sound effect for all elements to "no sound" */
1737 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1738 for (j = 0; j < NUM_ACTIONS; j++)
1739 element_info[i].sound[j] = SND_UNDEFINED;
1741 for (i = 0; i < num_sounds; i++)
1743 struct FileInfo *sound = getSoundListEntry(i);
1744 int len_effect_text = strlen(sound->token);
1746 sound_effect_properties[i] = ACTION_OTHER;
1747 sound_info[i].loop = FALSE; /* default: play sound only once */
1749 /* determine all loop sounds and identify certain sound classes */
1751 for (j = 0; element_action_info[j].suffix; j++)
1753 int len_action_text = strlen(element_action_info[j].suffix);
1755 if (len_action_text < len_effect_text &&
1756 strEqual(&sound->token[len_effect_text - len_action_text],
1757 element_action_info[j].suffix))
1759 sound_effect_properties[i] = element_action_info[j].value;
1760 sound_info[i].loop = element_action_info[j].is_loop_sound;
1766 /* associate elements and some selected sound actions */
1768 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1770 if (element_info[j].class_name)
1772 int len_class_text = strlen(element_info[j].class_name);
1774 if (len_class_text + 1 < len_effect_text &&
1775 strncmp(sound->token,
1776 element_info[j].class_name, len_class_text) == 0 &&
1777 sound->token[len_class_text] == '.')
1779 int sound_action_value = sound_effect_properties[i];
1781 element_info[j].sound[sound_action_value] = i;
1786 set_sound_parameters(i, sound->parameter);
1789 free(sound_effect_properties);
1792 static void InitGameModeMusicInfo()
1794 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1795 int num_property_mappings = getMusicListPropertyMappingSize();
1796 int default_levelset_music = -1;
1799 /* set values to -1 to identify later as "uninitialized" values */
1800 for (i = 0; i < MAX_LEVELS; i++)
1801 levelset.music[i] = -1;
1802 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1805 /* initialize gamemode/music mapping from static configuration */
1806 for (i = 0; gamemode_to_music[i].music > -1; i++)
1808 int gamemode = gamemode_to_music[i].gamemode;
1809 int music = gamemode_to_music[i].music;
1812 gamemode = GAME_MODE_DEFAULT;
1814 menu.music[gamemode] = music;
1817 /* initialize gamemode/music mapping from dynamic configuration */
1818 for (i = 0; i < num_property_mappings; i++)
1820 int prefix = property_mapping[i].base_index;
1821 int gamemode = property_mapping[i].ext1_index;
1822 int level = property_mapping[i].ext2_index;
1823 int music = property_mapping[i].artwork_index;
1825 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1829 gamemode = GAME_MODE_DEFAULT;
1831 /* level specific music only allowed for in-game music */
1832 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1833 gamemode = GAME_MODE_PLAYING;
1838 default_levelset_music = music;
1841 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1842 levelset.music[level] = music;
1843 if (gamemode != GAME_MODE_PLAYING)
1844 menu.music[gamemode] = music;
1847 /* now set all '-1' values to menu specific default values */
1848 /* (undefined values of "levelset.music[]" might stay at "-1" to
1849 allow dynamic selection of music files from music directory!) */
1850 for (i = 0; i < MAX_LEVELS; i++)
1851 if (levelset.music[i] == -1)
1852 levelset.music[i] = default_levelset_music;
1853 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1854 if (menu.music[i] == -1)
1855 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1858 static void set_music_parameters(int music, char **parameter_raw)
1860 int parameter[NUM_MUS_ARGS];
1863 /* get integer values from string parameters */
1864 for (i = 0; i < NUM_MUS_ARGS; i++)
1866 get_parameter_value(parameter_raw[i],
1867 music_config_suffix[i].token,
1868 music_config_suffix[i].type);
1870 /* explicit loop mode setting in configuration overrides default value */
1871 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1872 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1875 static void InitMusicInfo()
1877 int num_music = getMusicListSize();
1880 checked_free(music_info);
1882 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1884 for (i = 0; i < num_music; i++)
1886 struct FileInfo *music = getMusicListEntry(i);
1887 int len_music_text = strlen(music->token);
1889 music_info[i].loop = TRUE; /* default: play music in loop mode */
1891 /* determine all loop music */
1893 for (j = 0; music_prefix_info[j].prefix; j++)
1895 int len_prefix_text = strlen(music_prefix_info[j].prefix);
1897 if (len_prefix_text < len_music_text &&
1898 strncmp(music->token,
1899 music_prefix_info[j].prefix, len_prefix_text) == 0)
1901 music_info[i].loop = music_prefix_info[j].is_loop_music;
1907 set_music_parameters(i, music->parameter);
1911 static void ReinitializeGraphics()
1913 print_timestamp_init("ReinitializeGraphics");
1915 InitGfxTileSizeInfo(game.tile_size, TILESIZE);
1917 InitGraphicInfo(); /* graphic properties mapping */
1918 print_timestamp_time("InitGraphicInfo");
1919 InitElementGraphicInfo(); /* element game graphic mapping */
1920 print_timestamp_time("InitElementGraphicInfo");
1921 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
1922 print_timestamp_time("InitElementSpecialGraphicInfo");
1924 InitElementSmallImages(); /* scale elements to all needed sizes */
1925 print_timestamp_time("InitElementSmallImages");
1926 InitScaledImages(); /* scale all other images, if needed */
1927 print_timestamp_time("InitScaledImages");
1928 InitBitmapPointers(); /* set standard size bitmap pointers */
1929 print_timestamp_time("InitBitmapPointers");
1930 InitFontGraphicInfo(); /* initialize text drawing functions */
1931 print_timestamp_time("InitFontGraphicInfo");
1933 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
1934 print_timestamp_time("InitGraphicInfo_EM");
1936 InitGraphicCompatibilityInfo();
1937 print_timestamp_time("InitGraphicCompatibilityInfo");
1939 SetMainBackgroundImage(IMG_BACKGROUND);
1940 print_timestamp_time("SetMainBackgroundImage");
1941 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1942 print_timestamp_time("SetDoorBackgroundImage");
1945 print_timestamp_time("InitGadgets");
1947 print_timestamp_time("InitToons");
1949 print_timestamp_time("InitDoors");
1951 print_timestamp_done("ReinitializeGraphics");
1954 static void ReinitializeSounds()
1956 InitSoundInfo(); /* sound properties mapping */
1957 InitElementSoundInfo(); /* element game sound mapping */
1958 InitGameModeSoundInfo(); /* game mode sound mapping */
1960 InitPlayLevelSound(); /* internal game sound settings */
1963 static void ReinitializeMusic()
1965 InitMusicInfo(); /* music properties mapping */
1966 InitGameModeMusicInfo(); /* game mode music mapping */
1969 static int get_special_property_bit(int element, int property_bit_nr)
1971 struct PropertyBitInfo
1977 static struct PropertyBitInfo pb_can_move_into_acid[] =
1979 /* the player may be able fall into acid when gravity is activated */
1984 { EL_SP_MURPHY, 0 },
1985 { EL_SOKOBAN_FIELD_PLAYER, 0 },
1987 /* all elements that can move may be able to also move into acid */
1990 { EL_BUG_RIGHT, 1 },
1993 { EL_SPACESHIP, 2 },
1994 { EL_SPACESHIP_LEFT, 2 },
1995 { EL_SPACESHIP_RIGHT, 2 },
1996 { EL_SPACESHIP_UP, 2 },
1997 { EL_SPACESHIP_DOWN, 2 },
1998 { EL_BD_BUTTERFLY, 3 },
1999 { EL_BD_BUTTERFLY_LEFT, 3 },
2000 { EL_BD_BUTTERFLY_RIGHT, 3 },
2001 { EL_BD_BUTTERFLY_UP, 3 },
2002 { EL_BD_BUTTERFLY_DOWN, 3 },
2003 { EL_BD_FIREFLY, 4 },
2004 { EL_BD_FIREFLY_LEFT, 4 },
2005 { EL_BD_FIREFLY_RIGHT, 4 },
2006 { EL_BD_FIREFLY_UP, 4 },
2007 { EL_BD_FIREFLY_DOWN, 4 },
2009 { EL_YAMYAM_LEFT, 5 },
2010 { EL_YAMYAM_RIGHT, 5 },
2011 { EL_YAMYAM_UP, 5 },
2012 { EL_YAMYAM_DOWN, 5 },
2013 { EL_DARK_YAMYAM, 6 },
2016 { EL_PACMAN_LEFT, 8 },
2017 { EL_PACMAN_RIGHT, 8 },
2018 { EL_PACMAN_UP, 8 },
2019 { EL_PACMAN_DOWN, 8 },
2021 { EL_MOLE_LEFT, 9 },
2022 { EL_MOLE_RIGHT, 9 },
2024 { EL_MOLE_DOWN, 9 },
2028 { EL_SATELLITE, 13 },
2029 { EL_SP_SNIKSNAK, 14 },
2030 { EL_SP_ELECTRON, 15 },
2033 { EL_EMC_ANDROID, 18 },
2038 static struct PropertyBitInfo pb_dont_collide_with[] =
2040 { EL_SP_SNIKSNAK, 0 },
2041 { EL_SP_ELECTRON, 1 },
2049 struct PropertyBitInfo *pb_info;
2052 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2053 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2058 struct PropertyBitInfo *pb_info = NULL;
2061 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2062 if (pb_definition[i].bit_nr == property_bit_nr)
2063 pb_info = pb_definition[i].pb_info;
2065 if (pb_info == NULL)
2068 for (i = 0; pb_info[i].element != -1; i++)
2069 if (pb_info[i].element == element)
2070 return pb_info[i].bit_nr;
2075 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2076 boolean property_value)
2078 int bit_nr = get_special_property_bit(element, property_bit_nr);
2083 *bitfield |= (1 << bit_nr);
2085 *bitfield &= ~(1 << bit_nr);
2089 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2091 int bit_nr = get_special_property_bit(element, property_bit_nr);
2094 return ((*bitfield & (1 << bit_nr)) != 0);
2099 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2101 static int group_nr;
2102 static struct ElementGroupInfo *group;
2103 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2106 if (actual_group == NULL) /* not yet initialized */
2109 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
2111 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2112 group_element - EL_GROUP_START + 1);
2114 /* replace element which caused too deep recursion by question mark */
2115 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2120 if (recursion_depth == 0) /* initialization */
2122 group = actual_group;
2123 group_nr = GROUP_NR(group_element);
2125 group->num_elements_resolved = 0;
2126 group->choice_pos = 0;
2128 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2129 element_info[i].in_group[group_nr] = FALSE;
2132 for (i = 0; i < actual_group->num_elements; i++)
2134 int element = actual_group->element[i];
2136 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2139 if (IS_GROUP_ELEMENT(element))
2140 ResolveGroupElementExt(element, recursion_depth + 1);
2143 group->element_resolved[group->num_elements_resolved++] = element;
2144 element_info[element].in_group[group_nr] = TRUE;
2149 void ResolveGroupElement(int group_element)
2151 ResolveGroupElementExt(group_element, 0);
2154 void InitElementPropertiesStatic()
2156 static boolean clipboard_elements_initialized = FALSE;
2158 static int ep_diggable[] =
2163 EL_SP_BUGGY_BASE_ACTIVATING,
2166 EL_INVISIBLE_SAND_ACTIVE,
2169 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2170 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2175 EL_SP_BUGGY_BASE_ACTIVE,
2182 static int ep_collectible_only[] =
2204 EL_DYNABOMB_INCREASE_NUMBER,
2205 EL_DYNABOMB_INCREASE_SIZE,
2206 EL_DYNABOMB_INCREASE_POWER,
2224 /* !!! handle separately !!! */
2225 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2231 static int ep_dont_run_into[] =
2233 /* same elements as in 'ep_dont_touch' */
2239 /* same elements as in 'ep_dont_collide_with' */
2251 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2256 EL_SP_BUGGY_BASE_ACTIVE,
2263 static int ep_dont_collide_with[] =
2265 /* same elements as in 'ep_dont_touch' */
2282 static int ep_dont_touch[] =
2292 static int ep_indestructible[] =
2296 EL_ACID_POOL_TOPLEFT,
2297 EL_ACID_POOL_TOPRIGHT,
2298 EL_ACID_POOL_BOTTOMLEFT,
2299 EL_ACID_POOL_BOTTOM,
2300 EL_ACID_POOL_BOTTOMRIGHT,
2301 EL_SP_HARDWARE_GRAY,
2302 EL_SP_HARDWARE_GREEN,
2303 EL_SP_HARDWARE_BLUE,
2305 EL_SP_HARDWARE_YELLOW,
2306 EL_SP_HARDWARE_BASE_1,
2307 EL_SP_HARDWARE_BASE_2,
2308 EL_SP_HARDWARE_BASE_3,
2309 EL_SP_HARDWARE_BASE_4,
2310 EL_SP_HARDWARE_BASE_5,
2311 EL_SP_HARDWARE_BASE_6,
2312 EL_INVISIBLE_STEELWALL,
2313 EL_INVISIBLE_STEELWALL_ACTIVE,
2314 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2315 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2316 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2317 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2318 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2319 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2320 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2321 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2322 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2323 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2324 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2325 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2327 EL_LIGHT_SWITCH_ACTIVE,
2328 EL_SIGN_EXCLAMATION,
2329 EL_SIGN_RADIOACTIVITY,
2336 EL_SIGN_ENTRY_FORBIDDEN,
2337 EL_SIGN_EMERGENCY_EXIT,
2345 EL_STEEL_EXIT_CLOSED,
2347 EL_STEEL_EXIT_OPENING,
2348 EL_STEEL_EXIT_CLOSING,
2349 EL_EM_STEEL_EXIT_CLOSED,
2350 EL_EM_STEEL_EXIT_OPEN,
2351 EL_EM_STEEL_EXIT_OPENING,
2352 EL_EM_STEEL_EXIT_CLOSING,
2353 EL_DC_STEELWALL_1_LEFT,
2354 EL_DC_STEELWALL_1_RIGHT,
2355 EL_DC_STEELWALL_1_TOP,
2356 EL_DC_STEELWALL_1_BOTTOM,
2357 EL_DC_STEELWALL_1_HORIZONTAL,
2358 EL_DC_STEELWALL_1_VERTICAL,
2359 EL_DC_STEELWALL_1_TOPLEFT,
2360 EL_DC_STEELWALL_1_TOPRIGHT,
2361 EL_DC_STEELWALL_1_BOTTOMLEFT,
2362 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2363 EL_DC_STEELWALL_1_TOPLEFT_2,
2364 EL_DC_STEELWALL_1_TOPRIGHT_2,
2365 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2366 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2367 EL_DC_STEELWALL_2_LEFT,
2368 EL_DC_STEELWALL_2_RIGHT,
2369 EL_DC_STEELWALL_2_TOP,
2370 EL_DC_STEELWALL_2_BOTTOM,
2371 EL_DC_STEELWALL_2_HORIZONTAL,
2372 EL_DC_STEELWALL_2_VERTICAL,
2373 EL_DC_STEELWALL_2_MIDDLE,
2374 EL_DC_STEELWALL_2_SINGLE,
2375 EL_STEELWALL_SLIPPERY,
2389 EL_GATE_1_GRAY_ACTIVE,
2390 EL_GATE_2_GRAY_ACTIVE,
2391 EL_GATE_3_GRAY_ACTIVE,
2392 EL_GATE_4_GRAY_ACTIVE,
2401 EL_EM_GATE_1_GRAY_ACTIVE,
2402 EL_EM_GATE_2_GRAY_ACTIVE,
2403 EL_EM_GATE_3_GRAY_ACTIVE,
2404 EL_EM_GATE_4_GRAY_ACTIVE,
2413 EL_EMC_GATE_5_GRAY_ACTIVE,
2414 EL_EMC_GATE_6_GRAY_ACTIVE,
2415 EL_EMC_GATE_7_GRAY_ACTIVE,
2416 EL_EMC_GATE_8_GRAY_ACTIVE,
2418 EL_DC_GATE_WHITE_GRAY,
2419 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2420 EL_DC_GATE_FAKE_GRAY,
2422 EL_SWITCHGATE_OPENING,
2423 EL_SWITCHGATE_CLOSED,
2424 EL_SWITCHGATE_CLOSING,
2425 EL_DC_SWITCHGATE_SWITCH_UP,
2426 EL_DC_SWITCHGATE_SWITCH_DOWN,
2428 EL_TIMEGATE_OPENING,
2430 EL_TIMEGATE_CLOSING,
2431 EL_DC_TIMEGATE_SWITCH,
2432 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2436 EL_TUBE_VERTICAL_LEFT,
2437 EL_TUBE_VERTICAL_RIGHT,
2438 EL_TUBE_HORIZONTAL_UP,
2439 EL_TUBE_HORIZONTAL_DOWN,
2444 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2445 EL_EXPANDABLE_STEELWALL_VERTICAL,
2446 EL_EXPANDABLE_STEELWALL_ANY,
2451 static int ep_slippery[] =
2465 EL_ROBOT_WHEEL_ACTIVE,
2471 EL_ACID_POOL_TOPLEFT,
2472 EL_ACID_POOL_TOPRIGHT,
2482 EL_STEELWALL_SLIPPERY,
2485 EL_EMC_WALL_SLIPPERY_1,
2486 EL_EMC_WALL_SLIPPERY_2,
2487 EL_EMC_WALL_SLIPPERY_3,
2488 EL_EMC_WALL_SLIPPERY_4,
2490 EL_EMC_MAGIC_BALL_ACTIVE,
2495 static int ep_can_change[] =
2500 static int ep_can_move[] =
2502 /* same elements as in 'pb_can_move_into_acid' */
2525 static int ep_can_fall[] =
2539 EL_QUICKSAND_FAST_FULL,
2541 EL_BD_MAGIC_WALL_FULL,
2542 EL_DC_MAGIC_WALL_FULL,
2556 static int ep_can_smash_player[] =
2582 static int ep_can_smash_enemies[] =
2591 static int ep_can_smash_everything[] =
2600 static int ep_explodes_by_fire[] =
2602 /* same elements as in 'ep_explodes_impact' */
2607 /* same elements as in 'ep_explodes_smashed' */
2617 EL_EM_DYNAMITE_ACTIVE,
2618 EL_DYNABOMB_PLAYER_1_ACTIVE,
2619 EL_DYNABOMB_PLAYER_2_ACTIVE,
2620 EL_DYNABOMB_PLAYER_3_ACTIVE,
2621 EL_DYNABOMB_PLAYER_4_ACTIVE,
2622 EL_DYNABOMB_INCREASE_NUMBER,
2623 EL_DYNABOMB_INCREASE_SIZE,
2624 EL_DYNABOMB_INCREASE_POWER,
2625 EL_SP_DISK_RED_ACTIVE,
2639 static int ep_explodes_smashed[] =
2641 /* same elements as in 'ep_explodes_impact' */
2655 static int ep_explodes_impact[] =
2664 static int ep_walkable_over[] =
2668 EL_SOKOBAN_FIELD_EMPTY,
2675 EL_EM_STEEL_EXIT_OPEN,
2676 EL_EM_STEEL_EXIT_OPENING,
2685 EL_GATE_1_GRAY_ACTIVE,
2686 EL_GATE_2_GRAY_ACTIVE,
2687 EL_GATE_3_GRAY_ACTIVE,
2688 EL_GATE_4_GRAY_ACTIVE,
2696 static int ep_walkable_inside[] =
2701 EL_TUBE_VERTICAL_LEFT,
2702 EL_TUBE_VERTICAL_RIGHT,
2703 EL_TUBE_HORIZONTAL_UP,
2704 EL_TUBE_HORIZONTAL_DOWN,
2713 static int ep_walkable_under[] =
2718 static int ep_passable_over[] =
2728 EL_EM_GATE_1_GRAY_ACTIVE,
2729 EL_EM_GATE_2_GRAY_ACTIVE,
2730 EL_EM_GATE_3_GRAY_ACTIVE,
2731 EL_EM_GATE_4_GRAY_ACTIVE,
2740 EL_EMC_GATE_5_GRAY_ACTIVE,
2741 EL_EMC_GATE_6_GRAY_ACTIVE,
2742 EL_EMC_GATE_7_GRAY_ACTIVE,
2743 EL_EMC_GATE_8_GRAY_ACTIVE,
2745 EL_DC_GATE_WHITE_GRAY,
2746 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2753 static int ep_passable_inside[] =
2759 EL_SP_PORT_HORIZONTAL,
2760 EL_SP_PORT_VERTICAL,
2762 EL_SP_GRAVITY_PORT_LEFT,
2763 EL_SP_GRAVITY_PORT_RIGHT,
2764 EL_SP_GRAVITY_PORT_UP,
2765 EL_SP_GRAVITY_PORT_DOWN,
2766 EL_SP_GRAVITY_ON_PORT_LEFT,
2767 EL_SP_GRAVITY_ON_PORT_RIGHT,
2768 EL_SP_GRAVITY_ON_PORT_UP,
2769 EL_SP_GRAVITY_ON_PORT_DOWN,
2770 EL_SP_GRAVITY_OFF_PORT_LEFT,
2771 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2772 EL_SP_GRAVITY_OFF_PORT_UP,
2773 EL_SP_GRAVITY_OFF_PORT_DOWN,
2778 static int ep_passable_under[] =
2783 static int ep_droppable[] =
2788 static int ep_explodes_1x1_old[] =
2793 static int ep_pushable[] =
2805 EL_SOKOBAN_FIELD_FULL,
2814 static int ep_explodes_cross_old[] =
2819 static int ep_protected[] =
2821 /* same elements as in 'ep_walkable_inside' */
2825 EL_TUBE_VERTICAL_LEFT,
2826 EL_TUBE_VERTICAL_RIGHT,
2827 EL_TUBE_HORIZONTAL_UP,
2828 EL_TUBE_HORIZONTAL_DOWN,
2834 /* same elements as in 'ep_passable_over' */
2843 EL_EM_GATE_1_GRAY_ACTIVE,
2844 EL_EM_GATE_2_GRAY_ACTIVE,
2845 EL_EM_GATE_3_GRAY_ACTIVE,
2846 EL_EM_GATE_4_GRAY_ACTIVE,
2855 EL_EMC_GATE_5_GRAY_ACTIVE,
2856 EL_EMC_GATE_6_GRAY_ACTIVE,
2857 EL_EMC_GATE_7_GRAY_ACTIVE,
2858 EL_EMC_GATE_8_GRAY_ACTIVE,
2860 EL_DC_GATE_WHITE_GRAY,
2861 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2865 /* same elements as in 'ep_passable_inside' */
2870 EL_SP_PORT_HORIZONTAL,
2871 EL_SP_PORT_VERTICAL,
2873 EL_SP_GRAVITY_PORT_LEFT,
2874 EL_SP_GRAVITY_PORT_RIGHT,
2875 EL_SP_GRAVITY_PORT_UP,
2876 EL_SP_GRAVITY_PORT_DOWN,
2877 EL_SP_GRAVITY_ON_PORT_LEFT,
2878 EL_SP_GRAVITY_ON_PORT_RIGHT,
2879 EL_SP_GRAVITY_ON_PORT_UP,
2880 EL_SP_GRAVITY_ON_PORT_DOWN,
2881 EL_SP_GRAVITY_OFF_PORT_LEFT,
2882 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2883 EL_SP_GRAVITY_OFF_PORT_UP,
2884 EL_SP_GRAVITY_OFF_PORT_DOWN,
2889 static int ep_throwable[] =
2894 static int ep_can_explode[] =
2896 /* same elements as in 'ep_explodes_impact' */
2901 /* same elements as in 'ep_explodes_smashed' */
2907 /* elements that can explode by explosion or by dragonfire */
2911 EL_EM_DYNAMITE_ACTIVE,
2912 EL_DYNABOMB_PLAYER_1_ACTIVE,
2913 EL_DYNABOMB_PLAYER_2_ACTIVE,
2914 EL_DYNABOMB_PLAYER_3_ACTIVE,
2915 EL_DYNABOMB_PLAYER_4_ACTIVE,
2916 EL_DYNABOMB_INCREASE_NUMBER,
2917 EL_DYNABOMB_INCREASE_SIZE,
2918 EL_DYNABOMB_INCREASE_POWER,
2919 EL_SP_DISK_RED_ACTIVE,
2927 /* elements that can explode only by explosion */
2933 static int ep_gravity_reachable[] =
2939 EL_INVISIBLE_SAND_ACTIVE,
2944 EL_SP_PORT_HORIZONTAL,
2945 EL_SP_PORT_VERTICAL,
2947 EL_SP_GRAVITY_PORT_LEFT,
2948 EL_SP_GRAVITY_PORT_RIGHT,
2949 EL_SP_GRAVITY_PORT_UP,
2950 EL_SP_GRAVITY_PORT_DOWN,
2951 EL_SP_GRAVITY_ON_PORT_LEFT,
2952 EL_SP_GRAVITY_ON_PORT_RIGHT,
2953 EL_SP_GRAVITY_ON_PORT_UP,
2954 EL_SP_GRAVITY_ON_PORT_DOWN,
2955 EL_SP_GRAVITY_OFF_PORT_LEFT,
2956 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2957 EL_SP_GRAVITY_OFF_PORT_UP,
2958 EL_SP_GRAVITY_OFF_PORT_DOWN,
2964 static int ep_player[] =
2971 EL_SOKOBAN_FIELD_PLAYER,
2977 static int ep_can_pass_magic_wall[] =
2991 static int ep_can_pass_dc_magic_wall[] =
3007 static int ep_switchable[] =
3011 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3012 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3013 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3014 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3015 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3016 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3017 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3018 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3019 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3020 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3021 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3022 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3023 EL_SWITCHGATE_SWITCH_UP,
3024 EL_SWITCHGATE_SWITCH_DOWN,
3025 EL_DC_SWITCHGATE_SWITCH_UP,
3026 EL_DC_SWITCHGATE_SWITCH_DOWN,
3028 EL_LIGHT_SWITCH_ACTIVE,
3030 EL_DC_TIMEGATE_SWITCH,
3031 EL_BALLOON_SWITCH_LEFT,
3032 EL_BALLOON_SWITCH_RIGHT,
3033 EL_BALLOON_SWITCH_UP,
3034 EL_BALLOON_SWITCH_DOWN,
3035 EL_BALLOON_SWITCH_ANY,
3036 EL_BALLOON_SWITCH_NONE,
3039 EL_EMC_MAGIC_BALL_SWITCH,
3040 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3045 static int ep_bd_element[] =
3079 static int ep_sp_element[] =
3081 /* should always be valid */
3084 /* standard classic Supaplex elements */
3091 EL_SP_HARDWARE_GRAY,
3099 EL_SP_GRAVITY_PORT_RIGHT,
3100 EL_SP_GRAVITY_PORT_DOWN,
3101 EL_SP_GRAVITY_PORT_LEFT,
3102 EL_SP_GRAVITY_PORT_UP,
3107 EL_SP_PORT_VERTICAL,
3108 EL_SP_PORT_HORIZONTAL,
3114 EL_SP_HARDWARE_BASE_1,
3115 EL_SP_HARDWARE_GREEN,
3116 EL_SP_HARDWARE_BLUE,
3118 EL_SP_HARDWARE_YELLOW,
3119 EL_SP_HARDWARE_BASE_2,
3120 EL_SP_HARDWARE_BASE_3,
3121 EL_SP_HARDWARE_BASE_4,
3122 EL_SP_HARDWARE_BASE_5,
3123 EL_SP_HARDWARE_BASE_6,
3127 /* additional elements that appeared in newer Supaplex levels */
3130 /* additional gravity port elements (not switching, but setting gravity) */
3131 EL_SP_GRAVITY_ON_PORT_LEFT,
3132 EL_SP_GRAVITY_ON_PORT_RIGHT,
3133 EL_SP_GRAVITY_ON_PORT_UP,
3134 EL_SP_GRAVITY_ON_PORT_DOWN,
3135 EL_SP_GRAVITY_OFF_PORT_LEFT,
3136 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3137 EL_SP_GRAVITY_OFF_PORT_UP,
3138 EL_SP_GRAVITY_OFF_PORT_DOWN,
3140 /* more than one Murphy in a level results in an inactive clone */
3143 /* runtime Supaplex elements */
3144 EL_SP_DISK_RED_ACTIVE,
3145 EL_SP_TERMINAL_ACTIVE,
3146 EL_SP_BUGGY_BASE_ACTIVATING,
3147 EL_SP_BUGGY_BASE_ACTIVE,
3154 static int ep_sb_element[] =
3159 EL_SOKOBAN_FIELD_EMPTY,
3160 EL_SOKOBAN_FIELD_FULL,
3161 EL_SOKOBAN_FIELD_PLAYER,
3166 EL_INVISIBLE_STEELWALL,
3171 static int ep_gem[] =
3183 static int ep_food_dark_yamyam[] =
3211 static int ep_food_penguin[] =
3225 static int ep_food_pig[] =
3237 static int ep_historic_wall[] =
3248 EL_GATE_1_GRAY_ACTIVE,
3249 EL_GATE_2_GRAY_ACTIVE,
3250 EL_GATE_3_GRAY_ACTIVE,
3251 EL_GATE_4_GRAY_ACTIVE,
3260 EL_EM_GATE_1_GRAY_ACTIVE,
3261 EL_EM_GATE_2_GRAY_ACTIVE,
3262 EL_EM_GATE_3_GRAY_ACTIVE,
3263 EL_EM_GATE_4_GRAY_ACTIVE,
3270 EL_EXPANDABLE_WALL_HORIZONTAL,
3271 EL_EXPANDABLE_WALL_VERTICAL,
3272 EL_EXPANDABLE_WALL_ANY,
3273 EL_EXPANDABLE_WALL_GROWING,
3274 EL_BD_EXPANDABLE_WALL,
3281 EL_SP_HARDWARE_GRAY,
3282 EL_SP_HARDWARE_GREEN,
3283 EL_SP_HARDWARE_BLUE,
3285 EL_SP_HARDWARE_YELLOW,
3286 EL_SP_HARDWARE_BASE_1,
3287 EL_SP_HARDWARE_BASE_2,
3288 EL_SP_HARDWARE_BASE_3,
3289 EL_SP_HARDWARE_BASE_4,
3290 EL_SP_HARDWARE_BASE_5,
3291 EL_SP_HARDWARE_BASE_6,
3293 EL_SP_TERMINAL_ACTIVE,
3296 EL_INVISIBLE_STEELWALL,
3297 EL_INVISIBLE_STEELWALL_ACTIVE,
3299 EL_INVISIBLE_WALL_ACTIVE,
3300 EL_STEELWALL_SLIPPERY,
3317 static int ep_historic_solid[] =
3321 EL_EXPANDABLE_WALL_HORIZONTAL,
3322 EL_EXPANDABLE_WALL_VERTICAL,
3323 EL_EXPANDABLE_WALL_ANY,
3324 EL_BD_EXPANDABLE_WALL,
3337 EL_QUICKSAND_FILLING,
3338 EL_QUICKSAND_EMPTYING,
3340 EL_MAGIC_WALL_ACTIVE,
3341 EL_MAGIC_WALL_EMPTYING,
3342 EL_MAGIC_WALL_FILLING,
3346 EL_BD_MAGIC_WALL_ACTIVE,
3347 EL_BD_MAGIC_WALL_EMPTYING,
3348 EL_BD_MAGIC_WALL_FULL,
3349 EL_BD_MAGIC_WALL_FILLING,
3350 EL_BD_MAGIC_WALL_DEAD,
3359 EL_SP_TERMINAL_ACTIVE,
3363 EL_INVISIBLE_WALL_ACTIVE,
3364 EL_SWITCHGATE_SWITCH_UP,
3365 EL_SWITCHGATE_SWITCH_DOWN,
3366 EL_DC_SWITCHGATE_SWITCH_UP,
3367 EL_DC_SWITCHGATE_SWITCH_DOWN,
3369 EL_TIMEGATE_SWITCH_ACTIVE,
3370 EL_DC_TIMEGATE_SWITCH,
3371 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3383 /* the following elements are a direct copy of "indestructible" elements,
3384 except "EL_ACID", which is "indestructible", but not "solid"! */
3389 EL_ACID_POOL_TOPLEFT,
3390 EL_ACID_POOL_TOPRIGHT,
3391 EL_ACID_POOL_BOTTOMLEFT,
3392 EL_ACID_POOL_BOTTOM,
3393 EL_ACID_POOL_BOTTOMRIGHT,
3394 EL_SP_HARDWARE_GRAY,
3395 EL_SP_HARDWARE_GREEN,
3396 EL_SP_HARDWARE_BLUE,
3398 EL_SP_HARDWARE_YELLOW,
3399 EL_SP_HARDWARE_BASE_1,
3400 EL_SP_HARDWARE_BASE_2,
3401 EL_SP_HARDWARE_BASE_3,
3402 EL_SP_HARDWARE_BASE_4,
3403 EL_SP_HARDWARE_BASE_5,
3404 EL_SP_HARDWARE_BASE_6,
3405 EL_INVISIBLE_STEELWALL,
3406 EL_INVISIBLE_STEELWALL_ACTIVE,
3407 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3408 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3409 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3410 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3411 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3412 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3413 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3414 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3415 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3416 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3417 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3418 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3420 EL_LIGHT_SWITCH_ACTIVE,
3421 EL_SIGN_EXCLAMATION,
3422 EL_SIGN_RADIOACTIVITY,
3429 EL_SIGN_ENTRY_FORBIDDEN,
3430 EL_SIGN_EMERGENCY_EXIT,
3438 EL_STEEL_EXIT_CLOSED,
3440 EL_DC_STEELWALL_1_LEFT,
3441 EL_DC_STEELWALL_1_RIGHT,
3442 EL_DC_STEELWALL_1_TOP,
3443 EL_DC_STEELWALL_1_BOTTOM,
3444 EL_DC_STEELWALL_1_HORIZONTAL,
3445 EL_DC_STEELWALL_1_VERTICAL,
3446 EL_DC_STEELWALL_1_TOPLEFT,
3447 EL_DC_STEELWALL_1_TOPRIGHT,
3448 EL_DC_STEELWALL_1_BOTTOMLEFT,
3449 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3450 EL_DC_STEELWALL_1_TOPLEFT_2,
3451 EL_DC_STEELWALL_1_TOPRIGHT_2,
3452 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3453 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3454 EL_DC_STEELWALL_2_LEFT,
3455 EL_DC_STEELWALL_2_RIGHT,
3456 EL_DC_STEELWALL_2_TOP,
3457 EL_DC_STEELWALL_2_BOTTOM,
3458 EL_DC_STEELWALL_2_HORIZONTAL,
3459 EL_DC_STEELWALL_2_VERTICAL,
3460 EL_DC_STEELWALL_2_MIDDLE,
3461 EL_DC_STEELWALL_2_SINGLE,
3462 EL_STEELWALL_SLIPPERY,
3476 EL_GATE_1_GRAY_ACTIVE,
3477 EL_GATE_2_GRAY_ACTIVE,
3478 EL_GATE_3_GRAY_ACTIVE,
3479 EL_GATE_4_GRAY_ACTIVE,
3488 EL_EM_GATE_1_GRAY_ACTIVE,
3489 EL_EM_GATE_2_GRAY_ACTIVE,
3490 EL_EM_GATE_3_GRAY_ACTIVE,
3491 EL_EM_GATE_4_GRAY_ACTIVE,
3493 EL_SWITCHGATE_OPENING,
3494 EL_SWITCHGATE_CLOSED,
3495 EL_SWITCHGATE_CLOSING,
3497 EL_TIMEGATE_OPENING,
3499 EL_TIMEGATE_CLOSING,
3503 EL_TUBE_VERTICAL_LEFT,
3504 EL_TUBE_VERTICAL_RIGHT,
3505 EL_TUBE_HORIZONTAL_UP,
3506 EL_TUBE_HORIZONTAL_DOWN,
3515 static int ep_classic_enemy[] =
3532 static int ep_belt[] =
3534 EL_CONVEYOR_BELT_1_LEFT,
3535 EL_CONVEYOR_BELT_1_MIDDLE,
3536 EL_CONVEYOR_BELT_1_RIGHT,
3537 EL_CONVEYOR_BELT_2_LEFT,
3538 EL_CONVEYOR_BELT_2_MIDDLE,
3539 EL_CONVEYOR_BELT_2_RIGHT,
3540 EL_CONVEYOR_BELT_3_LEFT,
3541 EL_CONVEYOR_BELT_3_MIDDLE,
3542 EL_CONVEYOR_BELT_3_RIGHT,
3543 EL_CONVEYOR_BELT_4_LEFT,
3544 EL_CONVEYOR_BELT_4_MIDDLE,
3545 EL_CONVEYOR_BELT_4_RIGHT,
3550 static int ep_belt_active[] =
3552 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3553 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3554 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3555 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3556 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3557 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3558 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3559 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3560 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3561 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3562 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3563 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3568 static int ep_belt_switch[] =
3570 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3571 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3572 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3573 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3574 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3575 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3576 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3577 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3578 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3579 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3580 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3581 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3586 static int ep_tube[] =
3593 EL_TUBE_HORIZONTAL_UP,
3594 EL_TUBE_HORIZONTAL_DOWN,
3596 EL_TUBE_VERTICAL_LEFT,
3597 EL_TUBE_VERTICAL_RIGHT,
3603 static int ep_acid_pool[] =
3605 EL_ACID_POOL_TOPLEFT,
3606 EL_ACID_POOL_TOPRIGHT,
3607 EL_ACID_POOL_BOTTOMLEFT,
3608 EL_ACID_POOL_BOTTOM,
3609 EL_ACID_POOL_BOTTOMRIGHT,
3614 static int ep_keygate[] =
3624 EL_GATE_1_GRAY_ACTIVE,
3625 EL_GATE_2_GRAY_ACTIVE,
3626 EL_GATE_3_GRAY_ACTIVE,
3627 EL_GATE_4_GRAY_ACTIVE,
3636 EL_EM_GATE_1_GRAY_ACTIVE,
3637 EL_EM_GATE_2_GRAY_ACTIVE,
3638 EL_EM_GATE_3_GRAY_ACTIVE,
3639 EL_EM_GATE_4_GRAY_ACTIVE,
3648 EL_EMC_GATE_5_GRAY_ACTIVE,
3649 EL_EMC_GATE_6_GRAY_ACTIVE,
3650 EL_EMC_GATE_7_GRAY_ACTIVE,
3651 EL_EMC_GATE_8_GRAY_ACTIVE,
3653 EL_DC_GATE_WHITE_GRAY,
3654 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3659 static int ep_amoeboid[] =
3671 static int ep_amoebalive[] =
3682 static int ep_has_editor_content[] =
3688 EL_SOKOBAN_FIELD_PLAYER,
3705 static int ep_can_turn_each_move[] =
3707 /* !!! do something with this one !!! */
3711 static int ep_can_grow[] =
3725 static int ep_active_bomb[] =
3728 EL_EM_DYNAMITE_ACTIVE,
3729 EL_DYNABOMB_PLAYER_1_ACTIVE,
3730 EL_DYNABOMB_PLAYER_2_ACTIVE,
3731 EL_DYNABOMB_PLAYER_3_ACTIVE,
3732 EL_DYNABOMB_PLAYER_4_ACTIVE,
3733 EL_SP_DISK_RED_ACTIVE,
3738 static int ep_inactive[] =
3748 EL_QUICKSAND_FAST_EMPTY,
3771 EL_GATE_1_GRAY_ACTIVE,
3772 EL_GATE_2_GRAY_ACTIVE,
3773 EL_GATE_3_GRAY_ACTIVE,
3774 EL_GATE_4_GRAY_ACTIVE,
3783 EL_EM_GATE_1_GRAY_ACTIVE,
3784 EL_EM_GATE_2_GRAY_ACTIVE,
3785 EL_EM_GATE_3_GRAY_ACTIVE,
3786 EL_EM_GATE_4_GRAY_ACTIVE,
3795 EL_EMC_GATE_5_GRAY_ACTIVE,
3796 EL_EMC_GATE_6_GRAY_ACTIVE,
3797 EL_EMC_GATE_7_GRAY_ACTIVE,
3798 EL_EMC_GATE_8_GRAY_ACTIVE,
3800 EL_DC_GATE_WHITE_GRAY,
3801 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3802 EL_DC_GATE_FAKE_GRAY,
3805 EL_INVISIBLE_STEELWALL,
3813 EL_WALL_EMERALD_YELLOW,
3814 EL_DYNABOMB_INCREASE_NUMBER,
3815 EL_DYNABOMB_INCREASE_SIZE,
3816 EL_DYNABOMB_INCREASE_POWER,
3820 EL_SOKOBAN_FIELD_EMPTY,
3821 EL_SOKOBAN_FIELD_FULL,
3822 EL_WALL_EMERALD_RED,
3823 EL_WALL_EMERALD_PURPLE,
3824 EL_ACID_POOL_TOPLEFT,
3825 EL_ACID_POOL_TOPRIGHT,
3826 EL_ACID_POOL_BOTTOMLEFT,
3827 EL_ACID_POOL_BOTTOM,
3828 EL_ACID_POOL_BOTTOMRIGHT,
3832 EL_BD_MAGIC_WALL_DEAD,
3834 EL_DC_MAGIC_WALL_DEAD,
3835 EL_AMOEBA_TO_DIAMOND,
3843 EL_SP_GRAVITY_PORT_RIGHT,
3844 EL_SP_GRAVITY_PORT_DOWN,
3845 EL_SP_GRAVITY_PORT_LEFT,
3846 EL_SP_GRAVITY_PORT_UP,
3847 EL_SP_PORT_HORIZONTAL,
3848 EL_SP_PORT_VERTICAL,
3859 EL_SP_HARDWARE_GRAY,
3860 EL_SP_HARDWARE_GREEN,
3861 EL_SP_HARDWARE_BLUE,
3863 EL_SP_HARDWARE_YELLOW,
3864 EL_SP_HARDWARE_BASE_1,
3865 EL_SP_HARDWARE_BASE_2,
3866 EL_SP_HARDWARE_BASE_3,
3867 EL_SP_HARDWARE_BASE_4,
3868 EL_SP_HARDWARE_BASE_5,
3869 EL_SP_HARDWARE_BASE_6,
3870 EL_SP_GRAVITY_ON_PORT_LEFT,
3871 EL_SP_GRAVITY_ON_PORT_RIGHT,
3872 EL_SP_GRAVITY_ON_PORT_UP,
3873 EL_SP_GRAVITY_ON_PORT_DOWN,
3874 EL_SP_GRAVITY_OFF_PORT_LEFT,
3875 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3876 EL_SP_GRAVITY_OFF_PORT_UP,
3877 EL_SP_GRAVITY_OFF_PORT_DOWN,
3878 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3879 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3880 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3881 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3882 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3883 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3884 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3885 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3886 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3887 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3888 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3889 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3890 EL_SIGN_EXCLAMATION,
3891 EL_SIGN_RADIOACTIVITY,
3898 EL_SIGN_ENTRY_FORBIDDEN,
3899 EL_SIGN_EMERGENCY_EXIT,
3907 EL_DC_STEELWALL_1_LEFT,
3908 EL_DC_STEELWALL_1_RIGHT,
3909 EL_DC_STEELWALL_1_TOP,
3910 EL_DC_STEELWALL_1_BOTTOM,
3911 EL_DC_STEELWALL_1_HORIZONTAL,
3912 EL_DC_STEELWALL_1_VERTICAL,
3913 EL_DC_STEELWALL_1_TOPLEFT,
3914 EL_DC_STEELWALL_1_TOPRIGHT,
3915 EL_DC_STEELWALL_1_BOTTOMLEFT,
3916 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3917 EL_DC_STEELWALL_1_TOPLEFT_2,
3918 EL_DC_STEELWALL_1_TOPRIGHT_2,
3919 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3920 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3921 EL_DC_STEELWALL_2_LEFT,
3922 EL_DC_STEELWALL_2_RIGHT,
3923 EL_DC_STEELWALL_2_TOP,
3924 EL_DC_STEELWALL_2_BOTTOM,
3925 EL_DC_STEELWALL_2_HORIZONTAL,
3926 EL_DC_STEELWALL_2_VERTICAL,
3927 EL_DC_STEELWALL_2_MIDDLE,
3928 EL_DC_STEELWALL_2_SINGLE,
3929 EL_STEELWALL_SLIPPERY,
3934 EL_EMC_WALL_SLIPPERY_1,
3935 EL_EMC_WALL_SLIPPERY_2,
3936 EL_EMC_WALL_SLIPPERY_3,
3937 EL_EMC_WALL_SLIPPERY_4,
3958 static int ep_em_slippery_wall[] =
3963 static int ep_gfx_crumbled[] =
3974 static int ep_editor_cascade_active[] =
3976 EL_INTERNAL_CASCADE_BD_ACTIVE,
3977 EL_INTERNAL_CASCADE_EM_ACTIVE,
3978 EL_INTERNAL_CASCADE_EMC_ACTIVE,
3979 EL_INTERNAL_CASCADE_RND_ACTIVE,
3980 EL_INTERNAL_CASCADE_SB_ACTIVE,
3981 EL_INTERNAL_CASCADE_SP_ACTIVE,
3982 EL_INTERNAL_CASCADE_DC_ACTIVE,
3983 EL_INTERNAL_CASCADE_DX_ACTIVE,
3984 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
3985 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
3986 EL_INTERNAL_CASCADE_CE_ACTIVE,
3987 EL_INTERNAL_CASCADE_GE_ACTIVE,
3988 EL_INTERNAL_CASCADE_REF_ACTIVE,
3989 EL_INTERNAL_CASCADE_USER_ACTIVE,
3990 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
3995 static int ep_editor_cascade_inactive[] =
3997 EL_INTERNAL_CASCADE_BD,
3998 EL_INTERNAL_CASCADE_EM,
3999 EL_INTERNAL_CASCADE_EMC,
4000 EL_INTERNAL_CASCADE_RND,
4001 EL_INTERNAL_CASCADE_SB,
4002 EL_INTERNAL_CASCADE_SP,
4003 EL_INTERNAL_CASCADE_DC,
4004 EL_INTERNAL_CASCADE_DX,
4005 EL_INTERNAL_CASCADE_CHARS,
4006 EL_INTERNAL_CASCADE_STEEL_CHARS,
4007 EL_INTERNAL_CASCADE_CE,
4008 EL_INTERNAL_CASCADE_GE,
4009 EL_INTERNAL_CASCADE_REF,
4010 EL_INTERNAL_CASCADE_USER,
4011 EL_INTERNAL_CASCADE_DYNAMIC,
4016 static int ep_obsolete[] =
4020 EL_EM_KEY_1_FILE_OBSOLETE,
4021 EL_EM_KEY_2_FILE_OBSOLETE,
4022 EL_EM_KEY_3_FILE_OBSOLETE,
4023 EL_EM_KEY_4_FILE_OBSOLETE,
4024 EL_ENVELOPE_OBSOLETE,
4033 } element_properties[] =
4035 { ep_diggable, EP_DIGGABLE },
4036 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4037 { ep_dont_run_into, EP_DONT_RUN_INTO },
4038 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4039 { ep_dont_touch, EP_DONT_TOUCH },
4040 { ep_indestructible, EP_INDESTRUCTIBLE },
4041 { ep_slippery, EP_SLIPPERY },
4042 { ep_can_change, EP_CAN_CHANGE },
4043 { ep_can_move, EP_CAN_MOVE },
4044 { ep_can_fall, EP_CAN_FALL },
4045 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4046 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4047 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4048 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4049 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4050 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4051 { ep_walkable_over, EP_WALKABLE_OVER },
4052 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4053 { ep_walkable_under, EP_WALKABLE_UNDER },
4054 { ep_passable_over, EP_PASSABLE_OVER },
4055 { ep_passable_inside, EP_PASSABLE_INSIDE },
4056 { ep_passable_under, EP_PASSABLE_UNDER },
4057 { ep_droppable, EP_DROPPABLE },
4058 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4059 { ep_pushable, EP_PUSHABLE },
4060 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4061 { ep_protected, EP_PROTECTED },
4062 { ep_throwable, EP_THROWABLE },
4063 { ep_can_explode, EP_CAN_EXPLODE },
4064 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4066 { ep_player, EP_PLAYER },
4067 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4068 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4069 { ep_switchable, EP_SWITCHABLE },
4070 { ep_bd_element, EP_BD_ELEMENT },
4071 { ep_sp_element, EP_SP_ELEMENT },
4072 { ep_sb_element, EP_SB_ELEMENT },
4074 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4075 { ep_food_penguin, EP_FOOD_PENGUIN },
4076 { ep_food_pig, EP_FOOD_PIG },
4077 { ep_historic_wall, EP_HISTORIC_WALL },
4078 { ep_historic_solid, EP_HISTORIC_SOLID },
4079 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4080 { ep_belt, EP_BELT },
4081 { ep_belt_active, EP_BELT_ACTIVE },
4082 { ep_belt_switch, EP_BELT_SWITCH },
4083 { ep_tube, EP_TUBE },
4084 { ep_acid_pool, EP_ACID_POOL },
4085 { ep_keygate, EP_KEYGATE },
4086 { ep_amoeboid, EP_AMOEBOID },
4087 { ep_amoebalive, EP_AMOEBALIVE },
4088 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4089 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4090 { ep_can_grow, EP_CAN_GROW },
4091 { ep_active_bomb, EP_ACTIVE_BOMB },
4092 { ep_inactive, EP_INACTIVE },
4094 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4096 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4098 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4099 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4101 { ep_obsolete, EP_OBSOLETE },
4108 /* always start with reliable default values (element has no properties) */
4109 /* (but never initialize clipboard elements after the very first time) */
4110 /* (to be able to use clipboard elements between several levels) */
4111 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4112 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4113 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4114 SET_PROPERTY(i, j, FALSE);
4116 /* set all base element properties from above array definitions */
4117 for (i = 0; element_properties[i].elements != NULL; i++)
4118 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4119 SET_PROPERTY((element_properties[i].elements)[j],
4120 element_properties[i].property, TRUE);
4122 /* copy properties to some elements that are only stored in level file */
4123 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4124 for (j = 0; copy_properties[j][0] != -1; j++)
4125 if (HAS_PROPERTY(copy_properties[j][0], i))
4126 for (k = 1; k <= 4; k++)
4127 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4129 /* set static element properties that are not listed in array definitions */
4130 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4131 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4133 clipboard_elements_initialized = TRUE;
4136 void InitElementPropertiesEngine(int engine_version)
4138 static int no_wall_properties[] =
4141 EP_COLLECTIBLE_ONLY,
4143 EP_DONT_COLLIDE_WITH,
4146 EP_CAN_SMASH_PLAYER,
4147 EP_CAN_SMASH_ENEMIES,
4148 EP_CAN_SMASH_EVERYTHING,
4153 EP_FOOD_DARK_YAMYAM,
4169 /* important: after initialization in InitElementPropertiesStatic(), the
4170 elements are not again initialized to a default value; therefore all
4171 changes have to make sure that they leave the element with a defined
4172 property (which means that conditional property changes must be set to
4173 a reliable default value before) */
4175 /* resolve group elements */
4176 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4177 ResolveGroupElement(EL_GROUP_START + i);
4179 /* set all special, combined or engine dependent element properties */
4180 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4182 /* do not change (already initialized) clipboard elements here */
4183 if (IS_CLIPBOARD_ELEMENT(i))
4186 /* ---------- INACTIVE ------------------------------------------------- */
4187 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4188 i <= EL_CHAR_END) ||
4189 (i >= EL_STEEL_CHAR_START &&
4190 i <= EL_STEEL_CHAR_END)));
4192 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4193 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4194 IS_WALKABLE_INSIDE(i) ||
4195 IS_WALKABLE_UNDER(i)));
4197 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4198 IS_PASSABLE_INSIDE(i) ||
4199 IS_PASSABLE_UNDER(i)));
4201 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4202 IS_PASSABLE_OVER(i)));
4204 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4205 IS_PASSABLE_INSIDE(i)));
4207 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4208 IS_PASSABLE_UNDER(i)));
4210 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4213 /* ---------- COLLECTIBLE ---------------------------------------------- */
4214 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4218 /* ---------- SNAPPABLE ------------------------------------------------ */
4219 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4220 IS_COLLECTIBLE(i) ||
4224 /* ---------- WALL ----------------------------------------------------- */
4225 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4227 for (j = 0; no_wall_properties[j] != -1; j++)
4228 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4229 i >= EL_FIRST_RUNTIME_UNREAL)
4230 SET_PROPERTY(i, EP_WALL, FALSE);
4232 if (IS_HISTORIC_WALL(i))
4233 SET_PROPERTY(i, EP_WALL, TRUE);
4235 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4236 if (engine_version < VERSION_IDENT(2,2,0,0))
4237 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4239 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4241 !IS_COLLECTIBLE(i)));
4243 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4244 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4245 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4247 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4248 IS_INDESTRUCTIBLE(i)));
4250 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4252 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4253 else if (engine_version < VERSION_IDENT(2,2,0,0))
4254 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4256 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4260 if (IS_CUSTOM_ELEMENT(i))
4262 /* these are additional properties which are initially false when set */
4264 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4266 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4267 if (DONT_COLLIDE_WITH(i))
4268 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4270 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4271 if (CAN_SMASH_EVERYTHING(i))
4272 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4273 if (CAN_SMASH_ENEMIES(i))
4274 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4277 /* ---------- CAN_SMASH ------------------------------------------------ */
4278 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4279 CAN_SMASH_ENEMIES(i) ||
4280 CAN_SMASH_EVERYTHING(i)));
4282 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4283 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4284 EXPLODES_BY_FIRE(i)));
4286 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4287 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4288 EXPLODES_SMASHED(i)));
4290 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4291 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4292 EXPLODES_IMPACT(i)));
4294 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4295 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4297 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4298 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4299 i == EL_BLACK_ORB));
4301 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4302 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4304 IS_CUSTOM_ELEMENT(i)));
4306 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4307 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4308 i == EL_SP_ELECTRON));
4310 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4311 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4312 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4313 getMoveIntoAcidProperty(&level, i));
4315 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4316 if (MAYBE_DONT_COLLIDE_WITH(i))
4317 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4318 getDontCollideWithProperty(&level, i));
4320 /* ---------- SP_PORT -------------------------------------------------- */
4321 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4322 IS_PASSABLE_INSIDE(i)));
4324 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4325 for (j = 0; j < level.num_android_clone_elements; j++)
4326 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4328 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4330 /* ---------- CAN_CHANGE ----------------------------------------------- */
4331 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4332 for (j = 0; j < element_info[i].num_change_pages; j++)
4333 if (element_info[i].change_page[j].can_change)
4334 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4336 /* ---------- HAS_ACTION ----------------------------------------------- */
4337 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4338 for (j = 0; j < element_info[i].num_change_pages; j++)
4339 if (element_info[i].change_page[j].has_action)
4340 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4342 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4343 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4346 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4347 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4348 element_info[i].crumbled[ACTION_DEFAULT] !=
4349 element_info[i].graphic[ACTION_DEFAULT]);
4351 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4352 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4353 IS_EDITOR_CASCADE_INACTIVE(i)));
4356 /* dynamically adjust element properties according to game engine version */
4358 static int ep_em_slippery_wall[] =
4363 EL_EXPANDABLE_WALL_HORIZONTAL,
4364 EL_EXPANDABLE_WALL_VERTICAL,
4365 EL_EXPANDABLE_WALL_ANY,
4366 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4367 EL_EXPANDABLE_STEELWALL_VERTICAL,
4368 EL_EXPANDABLE_STEELWALL_ANY,
4369 EL_EXPANDABLE_STEELWALL_GROWING,
4373 static int ep_em_explodes_by_fire[] =
4376 EL_EM_DYNAMITE_ACTIVE,
4381 /* special EM style gems behaviour */
4382 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4383 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4384 level.em_slippery_gems);
4386 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4387 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4388 (level.em_slippery_gems &&
4389 engine_version > VERSION_IDENT(2,0,1,0)));
4391 /* special EM style explosion behaviour regarding chain reactions */
4392 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4393 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4394 level.em_explodes_by_fire);
4397 /* this is needed because some graphics depend on element properties */
4398 if (game_status == GAME_MODE_PLAYING)
4399 InitElementGraphicInfo();
4402 void InitElementPropertiesAfterLoading(int engine_version)
4406 /* set some other uninitialized values of custom elements in older levels */
4407 if (engine_version < VERSION_IDENT(3,1,0,0))
4409 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4411 int element = EL_CUSTOM_START + i;
4413 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4415 element_info[element].explosion_delay = 17;
4416 element_info[element].ignition_delay = 8;
4421 void InitElementPropertiesGfxElement()
4425 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4427 struct ElementInfo *ei = &element_info[i];
4429 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4433 static void InitGlobal()
4438 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4440 /* check if element_name_info entry defined for each element in "main.h" */
4441 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4442 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4444 element_info[i].token_name = element_name_info[i].token_name;
4445 element_info[i].class_name = element_name_info[i].class_name;
4446 element_info[i].editor_description= element_name_info[i].editor_description;
4449 /* create hash from image config list */
4450 image_config_hash = newSetupFileHash();
4451 for (i = 0; image_config[i].token != NULL; i++)
4452 setHashEntry(image_config_hash,
4453 image_config[i].token,
4454 image_config[i].value);
4456 /* create hash from element token list */
4457 element_token_hash = newSetupFileHash();
4458 for (i = 0; element_name_info[i].token_name != NULL; i++)
4459 setHashEntry(element_token_hash,
4460 element_name_info[i].token_name,
4463 /* create hash from graphic token list */
4464 graphic_token_hash = newSetupFileHash();
4465 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4466 if (strSuffix(image_config[i].value, ".png") ||
4467 strSuffix(image_config[i].value, ".pcx") ||
4468 strSuffix(image_config[i].value, ".wav") ||
4469 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4470 setHashEntry(graphic_token_hash,
4471 image_config[i].token,
4472 int2str(graphic++, 0));
4474 /* create hash from font token list */
4475 font_token_hash = newSetupFileHash();
4476 for (i = 0; font_info[i].token_name != NULL; i++)
4477 setHashEntry(font_token_hash,
4478 font_info[i].token_name,
4481 /* set default filenames for all cloned graphics in static configuration */
4482 for (i = 0; image_config[i].token != NULL; i++)
4484 if (strEqual(image_config[i].value, UNDEFINED_FILENAME))
4486 char *token = image_config[i].token;
4487 char *token_clone_from = getStringCat2(token, ".clone_from");
4488 char *token_cloned = getHashEntry(image_config_hash, token_clone_from);
4490 if (token_cloned != NULL)
4492 char *value_cloned = getHashEntry(image_config_hash, token_cloned);
4494 if (value_cloned != NULL)
4496 /* set default filename in static configuration */
4497 image_config[i].value = value_cloned;
4499 /* set default filename in image config hash */
4500 setHashEntry(image_config_hash, token, value_cloned);
4504 free(token_clone_from);
4508 /* always start with reliable default values (all elements) */
4509 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4510 ActiveElement[i] = i;
4512 /* now add all entries that have an active state (active elements) */
4513 for (i = 0; element_with_active_state[i].element != -1; i++)
4515 int element = element_with_active_state[i].element;
4516 int element_active = element_with_active_state[i].element_active;
4518 ActiveElement[element] = element_active;
4521 /* always start with reliable default values (all buttons) */
4522 for (i = 0; i < NUM_IMAGE_FILES; i++)
4523 ActiveButton[i] = i;
4525 /* now add all entries that have an active state (active buttons) */
4526 for (i = 0; button_with_active_state[i].button != -1; i++)
4528 int button = button_with_active_state[i].button;
4529 int button_active = button_with_active_state[i].button_active;
4531 ActiveButton[button] = button_active;
4534 /* always start with reliable default values (all fonts) */
4535 for (i = 0; i < NUM_FONTS; i++)
4538 /* now add all entries that have an active state (active fonts) */
4539 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4541 int font = font_with_active_state[i].font_nr;
4542 int font_active = font_with_active_state[i].font_nr_active;
4544 ActiveFont[font] = font_active;
4547 global.autoplay_leveldir = NULL;
4548 global.convert_leveldir = NULL;
4549 global.create_images_dir = NULL;
4551 global.frames_per_second = 0;
4552 global.fps_slowdown = FALSE;
4553 global.fps_slowdown_factor = 1;
4555 global.border_status = GAME_MODE_MAIN;
4557 global.use_envelope_request = FALSE;
4560 void Execute_Command(char *command)
4564 if (strEqual(command, "print graphicsinfo.conf"))
4566 printf("# You can configure additional/alternative image files here.\n");
4567 printf("# (The entries below are default and therefore commented out.)\n");
4569 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4571 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4574 for (i = 0; image_config[i].token != NULL; i++)
4575 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
4576 image_config[i].value));
4580 else if (strEqual(command, "print soundsinfo.conf"))
4582 printf("# You can configure additional/alternative sound files here.\n");
4583 printf("# (The entries below are default and therefore commented out.)\n");
4585 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4587 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4590 for (i = 0; sound_config[i].token != NULL; i++)
4591 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4592 sound_config[i].value));
4596 else if (strEqual(command, "print musicinfo.conf"))
4598 printf("# You can configure additional/alternative music files here.\n");
4599 printf("# (The entries below are default and therefore commented out.)\n");
4601 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4603 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4606 for (i = 0; music_config[i].token != NULL; i++)
4607 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
4608 music_config[i].value));
4612 else if (strEqual(command, "print editorsetup.conf"))
4614 printf("# You can configure your personal editor element list here.\n");
4615 printf("# (The entries below are default and therefore commented out.)\n");
4618 /* this is needed to be able to check element list for cascade elements */
4619 InitElementPropertiesStatic();
4620 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4622 PrintEditorElementList();
4626 else if (strEqual(command, "print helpanim.conf"))
4628 printf("# You can configure different element help animations here.\n");
4629 printf("# (The entries below are default and therefore commented out.)\n");
4632 for (i = 0; helpanim_config[i].token != NULL; i++)
4634 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4635 helpanim_config[i].value));
4637 if (strEqual(helpanim_config[i].token, "end"))
4643 else if (strEqual(command, "print helptext.conf"))
4645 printf("# You can configure different element help text here.\n");
4646 printf("# (The entries below are default and therefore commented out.)\n");
4649 for (i = 0; helptext_config[i].token != NULL; i++)
4650 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4651 helptext_config[i].value));
4655 else if (strPrefix(command, "dump level "))
4657 char *filename = &command[11];
4659 if (!fileExists(filename))
4660 Error(ERR_EXIT, "cannot open file '%s'", filename);
4662 LoadLevelFromFilename(&level, filename);
4667 else if (strPrefix(command, "dump tape "))
4669 char *filename = &command[10];
4671 if (!fileExists(filename))
4672 Error(ERR_EXIT, "cannot open file '%s'", filename);
4674 LoadTapeFromFilename(filename);
4679 else if (strPrefix(command, "autoplay "))
4681 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
4683 while (*str_ptr != '\0') /* continue parsing string */
4685 /* cut leading whitespace from string, replace it by string terminator */
4686 while (*str_ptr == ' ' || *str_ptr == '\t')
4689 if (*str_ptr == '\0') /* end of string reached */
4692 if (global.autoplay_leveldir == NULL) /* read level set string */
4694 global.autoplay_leveldir = str_ptr;
4695 global.autoplay_all = TRUE; /* default: play all tapes */
4697 for (i = 0; i < MAX_TAPES_PER_SET; i++)
4698 global.autoplay_level[i] = FALSE;
4700 else /* read level number string */
4702 int level_nr = atoi(str_ptr); /* get level_nr value */
4704 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
4705 global.autoplay_level[level_nr] = TRUE;
4707 global.autoplay_all = FALSE;
4710 /* advance string pointer to the next whitespace (or end of string) */
4711 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
4715 else if (strPrefix(command, "convert "))
4717 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
4718 char *str_ptr = strchr(str_copy, ' ');
4720 global.convert_leveldir = str_copy;
4721 global.convert_level_nr = -1;
4723 if (str_ptr != NULL) /* level number follows */
4725 *str_ptr++ = '\0'; /* terminate leveldir string */
4726 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
4729 else if (strPrefix(command, "create images "))
4731 global.create_images_dir = getStringCopy(&command[14]);
4733 if (access(global.create_images_dir, W_OK) != 0)
4734 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
4735 global.create_images_dir);
4737 else if (strPrefix(command, "create CE image "))
4739 CreateCustomElementImages(&command[16]);
4745 #if defined(TARGET_SDL2)
4746 else if (strEqual(command, "SDL_ListModes"))
4748 SDL_Init(SDL_INIT_VIDEO);
4750 int num_displays = SDL_GetNumVideoDisplays();
4752 // check if there are any displays available
4753 if (num_displays < 0)
4755 printf("No displays available: %s\n", SDL_GetError());
4760 for (i = 0; i < num_displays; i++)
4762 int num_modes = SDL_GetNumDisplayModes(i);
4765 printf("Available display modes for display %d:\n", i);
4767 // check if there are any display modes available for this display
4770 printf("No display modes available for display %d: %s\n",
4776 for (j = 0; j < num_modes; j++)
4778 SDL_DisplayMode mode;
4780 if (SDL_GetDisplayMode(i, j, &mode) < 0)
4782 printf("Cannot get display mode %d for display %d: %s\n",
4783 j, i, SDL_GetError());
4788 printf("- %d x %d\n", mode.w, mode.h);
4794 #elif defined(TARGET_SDL)
4795 else if (strEqual(command, "SDL_ListModes"))
4800 SDL_Init(SDL_INIT_VIDEO);
4802 /* get available fullscreen/hardware modes */
4803 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
4805 /* check if there are any modes available */
4808 printf("No modes available!\n");
4813 /* check if our resolution is restricted */
4814 if (modes == (SDL_Rect **)-1)
4816 printf("All resolutions available.\n");
4820 printf("Available display modes:\n");
4822 for (i = 0; modes[i]; i++)
4823 printf("- %d x %d\n", modes[i]->w, modes[i]->h);
4833 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4837 static void InitSetup()
4839 LoadSetup(); /* global setup info */
4841 /* set some options from setup file */
4843 if (setup.options.verbose)
4844 options.verbose = TRUE;
4847 static void InitGameInfo()
4849 game.restart_level = FALSE;
4852 static void InitPlayerInfo()
4856 /* choose default local player */
4857 local_player = &stored_player[0];
4859 for (i = 0; i < MAX_PLAYERS; i++)
4860 stored_player[i].connected = FALSE;
4862 local_player->connected = TRUE;
4865 static void InitArtworkInfo()
4870 static char *get_string_in_brackets(char *string)
4872 char *string_in_brackets = checked_malloc(strlen(string) + 3);
4874 sprintf(string_in_brackets, "[%s]", string);
4876 return string_in_brackets;
4879 static char *get_level_id_suffix(int id_nr)
4881 char *id_suffix = checked_malloc(1 + 3 + 1);
4883 if (id_nr < 0 || id_nr > 999)
4886 sprintf(id_suffix, ".%03d", id_nr);
4891 static void InitArtworkConfig()
4893 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
4894 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
4895 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
4896 static char *action_id_suffix[NUM_ACTIONS + 1];
4897 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
4898 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
4899 static char *level_id_suffix[MAX_LEVELS + 1];
4900 static char *dummy[1] = { NULL };
4901 static char *ignore_generic_tokens[] =
4907 static char **ignore_image_tokens;
4908 static char **ignore_sound_tokens;
4909 static char **ignore_music_tokens;
4910 int num_ignore_generic_tokens;
4911 int num_ignore_image_tokens;
4912 int num_ignore_sound_tokens;
4913 int num_ignore_music_tokens;
4916 /* dynamically determine list of generic tokens to be ignored */
4917 num_ignore_generic_tokens = 0;
4918 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
4919 num_ignore_generic_tokens++;
4921 /* dynamically determine list of image tokens to be ignored */
4922 num_ignore_image_tokens = num_ignore_generic_tokens;
4923 for (i = 0; image_config_vars[i].token != NULL; i++)
4924 num_ignore_image_tokens++;
4925 ignore_image_tokens =
4926 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
4927 for (i = 0; i < num_ignore_generic_tokens; i++)
4928 ignore_image_tokens[i] = ignore_generic_tokens[i];
4929 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
4930 ignore_image_tokens[num_ignore_generic_tokens + i] =
4931 image_config_vars[i].token;
4932 ignore_image_tokens[num_ignore_image_tokens] = NULL;
4934 /* dynamically determine list of sound tokens to be ignored */
4935 num_ignore_sound_tokens = num_ignore_generic_tokens;
4936 ignore_sound_tokens =
4937 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
4938 for (i = 0; i < num_ignore_generic_tokens; i++)
4939 ignore_sound_tokens[i] = ignore_generic_tokens[i];
4940 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
4942 /* dynamically determine list of music tokens to be ignored */
4943 num_ignore_music_tokens = num_ignore_generic_tokens;
4944 ignore_music_tokens =
4945 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
4946 for (i = 0; i < num_ignore_generic_tokens; i++)
4947 ignore_music_tokens[i] = ignore_generic_tokens[i];
4948 ignore_music_tokens[num_ignore_music_tokens] = NULL;
4950 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4951 image_id_prefix[i] = element_info[i].token_name;
4952 for (i = 0; i < NUM_FONTS; i++)
4953 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
4954 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
4956 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4957 sound_id_prefix[i] = element_info[i].token_name;
4958 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4959 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
4960 get_string_in_brackets(element_info[i].class_name);
4961 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
4963 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
4964 music_id_prefix[i] = music_prefix_info[i].prefix;
4965 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
4967 for (i = 0; i < NUM_ACTIONS; i++)
4968 action_id_suffix[i] = element_action_info[i].suffix;
4969 action_id_suffix[NUM_ACTIONS] = NULL;
4971 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
4972 direction_id_suffix[i] = element_direction_info[i].suffix;
4973 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
4975 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
4976 special_id_suffix[i] = special_suffix_info[i].suffix;
4977 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
4979 for (i = 0; i < MAX_LEVELS; i++)
4980 level_id_suffix[i] = get_level_id_suffix(i);
4981 level_id_suffix[MAX_LEVELS] = NULL;
4983 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
4984 image_id_prefix, action_id_suffix, direction_id_suffix,
4985 special_id_suffix, ignore_image_tokens);
4986 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
4987 sound_id_prefix, action_id_suffix, dummy,
4988 special_id_suffix, ignore_sound_tokens);
4989 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
4990 music_id_prefix, special_id_suffix, level_id_suffix,
4991 dummy, ignore_music_tokens);
4994 static void InitMixer()
5001 void InitGfxBuffers()
5003 /* create additional image buffers for double-buffering and cross-fading */
5004 ReCreateBitmap(&bitmap_db_store, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5005 ReCreateBitmap(&bitmap_db_cross, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5006 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE, DEFAULT_DEPTH);
5007 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE, DEFAULT_DEPTH);
5008 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE, DEFAULT_DEPTH);
5009 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE, DEFAULT_DEPTH);
5010 ReCreateBitmap(&bitmap_db_toons, FULL_SXSIZE, FULL_SYSIZE, DEFAULT_DEPTH);
5012 /* initialize screen properties */
5013 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5014 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5016 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5017 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5018 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5019 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5020 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5021 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5023 /* required if door size definitions have changed */
5024 InitGraphicCompatibilityInfo_Doors();
5026 InitGfxBuffers_EM();
5027 InitGfxBuffers_SP();
5032 struct GraphicInfo *graphic_info_last = graphic_info;
5033 char *filename_font_initial = NULL;
5034 char *filename_anim_initial = NULL;
5035 Bitmap *bitmap_font_initial = NULL;
5039 /* determine settings for initial font (for displaying startup messages) */
5040 for (i = 0; image_config[i].token != NULL; i++)
5042 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5044 char font_token[128];
5047 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5048 len_font_token = strlen(font_token);
5050 if (strEqual(image_config[i].token, font_token))
5051 filename_font_initial = image_config[i].value;
5052 else if (strlen(image_config[i].token) > len_font_token &&
5053 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5055 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5056 font_initial[j].src_x = atoi(image_config[i].value);
5057 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5058 font_initial[j].src_y = atoi(image_config[i].value);
5059 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5060 font_initial[j].width = atoi(image_config[i].value);
5061 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5062 font_initial[j].height = atoi(image_config[i].value);
5067 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5069 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5070 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5073 if (filename_font_initial == NULL) /* should not happen */
5074 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5077 InitGfxCustomArtworkInfo();
5079 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5081 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5082 font_initial[j].bitmap = bitmap_font_initial;
5084 InitFontGraphicInfo();
5086 font_height = getFontHeight(FC_RED);
5088 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
5089 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
5090 DrawInitText(PROGRAM_WEBSITE_STRING, WIN_YSIZE - 20 - font_height, FC_RED);
5092 DrawInitText("Loading graphics", 120, FC_GREEN);
5094 /* initialize busy animation with default values */
5095 int parameter[NUM_GFX_ARGS];
5096 for (i = 0; i < NUM_GFX_ARGS; i++)
5097 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5098 image_config_suffix[i].token,
5099 image_config_suffix[i].type);
5101 /* determine settings for busy animation (when displaying startup messages) */
5102 for (i = 0; image_config[i].token != NULL; i++)
5104 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5105 int len_anim_token = strlen(anim_token);
5107 if (strEqual(image_config[i].token, anim_token))
5108 filename_anim_initial = image_config[i].value;
5109 else if (strlen(image_config[i].token) > len_anim_token &&
5110 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5112 for (j = 0; image_config_suffix[j].token != NULL; j++)
5114 if (strEqual(&image_config[i].token[len_anim_token],
5115 image_config_suffix[j].token))
5117 get_graphic_parameter_value(image_config[i].value,
5118 image_config_suffix[j].token,
5119 image_config_suffix[j].type);
5124 #if defined(CREATE_SPECIAL_EDITION_RND_JUE)
5125 filename_anim_initial = "loading.pcx";
5127 parameter[GFX_ARG_X] = 0;
5128 parameter[GFX_ARG_Y] = 0;
5129 parameter[GFX_ARG_WIDTH] = 128;
5130 parameter[GFX_ARG_HEIGHT] = 40;
5131 parameter[GFX_ARG_FRAMES] = 32;
5132 parameter[GFX_ARG_DELAY] = 4;
5133 parameter[GFX_ARG_FRAMES_PER_LINE] = ARG_UNDEFINED_VALUE;
5136 if (filename_anim_initial == NULL) /* should not happen */
5137 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5139 anim_initial.bitmaps =
5140 checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5142 anim_initial.bitmaps[IMG_BITMAP_STANDARD] =
5143 LoadCustomImage(filename_anim_initial);
5145 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
5147 set_graphic_parameters_ext(0, parameter, anim_initial.bitmaps);
5149 graphic_info = graphic_info_last;
5151 init.busy.width = anim_initial.width;
5152 init.busy.height = anim_initial.height;
5154 InitMenuDesignSettings_Static();
5155 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5157 /* use copy of busy animation to prevent change while reloading artwork */
5161 void RedrawBackground()
5163 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
5164 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
5166 redraw_mask = REDRAW_ALL;
5169 void InitGfxBackground()
5173 fieldbuffer = bitmap_db_field;
5174 SetDrawtoField(DRAW_BACKBUFFER);
5176 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5178 for (x = 0; x < MAX_BUF_XSIZE; x++)
5179 for (y = 0; y < MAX_BUF_YSIZE; y++)
5182 redraw_mask = REDRAW_ALL;
5185 static void InitLevelInfo()
5187 LoadLevelInfo(); /* global level info */
5188 LoadLevelSetup_LastSeries(); /* last played series info */
5189 LoadLevelSetup_SeriesInfo(); /* last played level info */
5192 static void InitLevelArtworkInfo()
5194 LoadLevelArtworkInfo();
5197 static void InitImages()
5199 print_timestamp_init("InitImages");
5202 printf("::: leveldir_current->identifier == '%s'\n",
5203 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5204 printf("::: leveldir_current->graphics_path == '%s'\n",
5205 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5206 printf("::: leveldir_current->graphics_set == '%s'\n",
5207 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5208 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5209 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5212 setLevelArtworkDir(artwork.gfx_first);
5215 printf("::: leveldir_current->identifier == '%s'\n",
5216 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5217 printf("::: leveldir_current->graphics_path == '%s'\n",
5218 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5219 printf("::: leveldir_current->graphics_set == '%s'\n",
5220 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5221 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5222 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5226 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5227 leveldir_current->identifier,
5228 artwork.gfx_current_identifier,
5229 artwork.gfx_current->identifier,
5230 leveldir_current->graphics_set,
5231 leveldir_current->graphics_path);
5234 UPDATE_BUSY_STATE();
5236 ReloadCustomImages();
5237 print_timestamp_time("ReloadCustomImages");
5239 UPDATE_BUSY_STATE();
5241 LoadCustomElementDescriptions();
5242 print_timestamp_time("LoadCustomElementDescriptions");
5244 UPDATE_BUSY_STATE();
5246 LoadMenuDesignSettings();
5247 print_timestamp_time("LoadMenuDesignSettings");
5249 UPDATE_BUSY_STATE();
5251 ReinitializeGraphics();
5252 print_timestamp_time("ReinitializeGraphics");
5254 UPDATE_BUSY_STATE();
5256 print_timestamp_done("InitImages");
5259 static void InitSound(char *identifier)
5261 print_timestamp_init("InitSound");
5263 if (identifier == NULL)
5264 identifier = artwork.snd_current->identifier;
5266 /* set artwork path to send it to the sound server process */
5267 setLevelArtworkDir(artwork.snd_first);
5269 InitReloadCustomSounds(identifier);
5270 print_timestamp_time("InitReloadCustomSounds");
5272 ReinitializeSounds();
5273 print_timestamp_time("ReinitializeSounds");
5275 print_timestamp_done("InitSound");
5278 static void InitMusic(char *identifier)
5280 print_timestamp_init("InitMusic");
5282 if (identifier == NULL)
5283 identifier = artwork.mus_current->identifier;
5285 /* set artwork path to send it to the sound server process */
5286 setLevelArtworkDir(artwork.mus_first);
5288 InitReloadCustomMusic(identifier);
5289 print_timestamp_time("InitReloadCustomMusic");
5291 ReinitializeMusic();
5292 print_timestamp_time("ReinitializeMusic");
5294 print_timestamp_done("InitMusic");
5297 void InitNetworkServer()
5299 #if defined(NETWORK_AVALIABLE)
5303 if (!options.network)
5306 #if defined(NETWORK_AVALIABLE)
5307 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5309 if (!ConnectToServer(options.server_host, options.server_port))
5310 Error(ERR_EXIT, "cannot connect to network game server");
5312 SendToServer_PlayerName(setup.player_name);
5313 SendToServer_ProtocolVersion();
5316 SendToServer_NrWanted(nr_wanted);
5320 static boolean CheckArtworkConfigForCustomElements(char *filename)
5322 SetupFileHash *setup_file_hash;
5323 boolean redefined_ce_found = FALSE;
5325 /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */
5327 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5329 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5331 char *token = HASH_ITERATION_TOKEN(itr);
5333 if (strPrefix(token, "custom_"))
5335 redefined_ce_found = TRUE;
5340 END_HASH_ITERATION(setup_file_hash, itr)
5342 freeSetupFileHash(setup_file_hash);
5345 return redefined_ce_found;
5348 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5350 char *filename_base, *filename_local;
5351 boolean redefined_ce_found = FALSE;
5353 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5356 printf("::: leveldir_current->identifier == '%s'\n",
5357 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5358 printf("::: leveldir_current->graphics_path == '%s'\n",
5359 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5360 printf("::: leveldir_current->graphics_set == '%s'\n",
5361 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5362 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5363 leveldir_current == NULL ? "[NULL]" :
5364 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5367 /* first look for special artwork configured in level series config */
5368 filename_base = getCustomArtworkLevelConfigFilename(type);
5371 printf("::: filename_base == '%s'\n", filename_base);
5374 if (fileExists(filename_base))
5375 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5377 filename_local = getCustomArtworkConfigFilename(type);
5380 printf("::: filename_local == '%s'\n", filename_local);
5383 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5384 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5387 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5390 return redefined_ce_found;
5393 static void InitOverrideArtwork()
5395 boolean redefined_ce_found = FALSE;
5397 /* to check if this level set redefines any CEs, do not use overriding */
5398 gfx.override_level_graphics = FALSE;
5399 gfx.override_level_sounds = FALSE;
5400 gfx.override_level_music = FALSE;
5402 /* now check if this level set has definitions for custom elements */
5403 if (setup.override_level_graphics == AUTO ||
5404 setup.override_level_sounds == AUTO ||
5405 setup.override_level_music == AUTO)
5406 redefined_ce_found =
5407 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5408 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5409 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5412 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5415 if (redefined_ce_found)
5417 /* this level set has CE definitions: change "AUTO" to "FALSE" */
5418 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5419 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
5420 gfx.override_level_music = (setup.override_level_music == TRUE);
5424 /* this level set has no CE definitions: change "AUTO" to "TRUE" */
5425 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5426 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
5427 gfx.override_level_music = (setup.override_level_music != FALSE);
5431 printf("::: => %d, %d, %d\n",
5432 gfx.override_level_graphics,
5433 gfx.override_level_sounds,
5434 gfx.override_level_music);
5438 static char *getNewArtworkIdentifier(int type)
5440 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5441 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5442 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5443 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5444 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5445 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5446 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5447 char *leveldir_identifier = leveldir_current->identifier;
5448 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
5449 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5450 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5451 char *artwork_current_identifier;
5452 char *artwork_new_identifier = NULL; /* default: nothing has changed */
5454 /* leveldir_current may be invalid (level group, parent link) */
5455 if (!validLevelSeries(leveldir_current))
5458 /* 1st step: determine artwork set to be activated in descending order:
5459 --------------------------------------------------------------------
5460 1. setup artwork (when configured to override everything else)
5461 2. artwork set configured in "levelinfo.conf" of current level set
5462 (artwork in level directory will have priority when loading later)
5463 3. artwork in level directory (stored in artwork sub-directory)
5464 4. setup artwork (currently configured in setup menu) */
5466 if (setup_override_artwork)
5467 artwork_current_identifier = setup_artwork_set;
5468 else if (leveldir_artwork_set != NULL)
5469 artwork_current_identifier = leveldir_artwork_set;
5470 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5471 artwork_current_identifier = leveldir_identifier;
5473 artwork_current_identifier = setup_artwork_set;
5476 /* 2nd step: check if it is really needed to reload artwork set
5477 ------------------------------------------------------------ */
5479 /* ---------- reload if level set and also artwork set has changed ------- */
5480 if (leveldir_current_identifier[type] != leveldir_identifier &&
5481 (last_has_level_artwork_set[type] || has_level_artwork_set))
5482 artwork_new_identifier = artwork_current_identifier;
5484 leveldir_current_identifier[type] = leveldir_identifier;
5485 last_has_level_artwork_set[type] = has_level_artwork_set;
5487 /* ---------- reload if "override artwork" setting has changed ----------- */
5488 if (last_override_level_artwork[type] != setup_override_artwork)
5489 artwork_new_identifier = artwork_current_identifier;
5491 last_override_level_artwork[type] = setup_override_artwork;
5493 /* ---------- reload if current artwork identifier has changed ----------- */
5494 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5495 artwork_current_identifier))
5496 artwork_new_identifier = artwork_current_identifier;
5498 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5500 /* ---------- do not reload directly after starting ---------------------- */
5501 if (!initialized[type])
5502 artwork_new_identifier = NULL;
5504 initialized[type] = TRUE;
5506 return artwork_new_identifier;
5509 void ReloadCustomArtwork(int force_reload)
5511 int last_game_status = game_status; /* save current game status */
5512 char *gfx_new_identifier;
5513 char *snd_new_identifier;
5514 char *mus_new_identifier;
5515 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5516 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5517 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5518 boolean reload_needed;
5520 InitOverrideArtwork();
5522 force_reload_gfx |= AdjustGraphicsForEMC();
5524 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5525 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5526 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5528 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
5529 snd_new_identifier != NULL || force_reload_snd ||
5530 mus_new_identifier != NULL || force_reload_mus);
5535 print_timestamp_init("ReloadCustomArtwork");
5537 game_status = GAME_MODE_LOADING;
5539 FadeOut(REDRAW_ALL);
5541 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5542 print_timestamp_time("ClearRectangle");
5546 if (gfx_new_identifier != NULL || force_reload_gfx)
5549 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5550 artwork.gfx_current_identifier,
5552 artwork.gfx_current->identifier,
5553 leveldir_current->graphics_set);
5557 print_timestamp_time("InitImages");
5560 if (snd_new_identifier != NULL || force_reload_snd)
5562 InitSound(snd_new_identifier);
5563 print_timestamp_time("InitSound");
5566 if (mus_new_identifier != NULL || force_reload_mus)
5568 InitMusic(mus_new_identifier);
5569 print_timestamp_time("InitMusic");
5572 game_status = last_game_status; /* restore current game status */
5574 init_last = init; /* switch to new busy animation */
5576 FadeOut(REDRAW_ALL);
5580 /* force redraw of (open or closed) door graphics */
5581 SetDoorState(DOOR_OPEN_ALL);
5582 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5584 FadeSetEnterScreen();
5585 FadeSkipNextFadeOut();
5587 print_timestamp_done("ReloadCustomArtwork");
5589 LimitScreenUpdates(FALSE);
5592 void KeyboardAutoRepeatOffUnlessAutoplay()
5594 if (global.autoplay_leveldir == NULL)
5595 KeyboardAutoRepeatOff();
5598 void DisplayExitMessage(char *format, va_list ap)
5600 // check if draw buffer and fonts for exit message are already available
5601 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
5604 int font_1 = FC_RED;
5605 int font_2 = FC_YELLOW;
5606 int font_3 = FC_BLUE;
5607 int font_width = getFontWidth(font_2);
5608 int font_height = getFontHeight(font_2);
5611 int sxsize = WIN_XSIZE - 2 * sx;
5612 int sysize = WIN_YSIZE - 2 * sy;
5613 int line_length = sxsize / font_width;
5614 int max_lines = sysize / font_height;
5615 int num_lines_printed;
5619 gfx.sxsize = sxsize;
5620 gfx.sysize = sysize;
5624 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5626 DrawTextSCentered(sy, font_1, "Fatal error:");
5627 sy += 3 * font_height;;
5630 DrawTextBufferVA(sx, sy, format, ap, font_2,
5631 line_length, line_length, max_lines,
5632 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5633 sy += (num_lines_printed + 3) * font_height;
5635 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
5636 sy += 3 * font_height;
5639 DrawTextBuffer(sx, sy, program.error_filename, font_2,
5640 line_length, line_length, max_lines,
5641 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5643 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
5645 redraw_mask = REDRAW_ALL;
5647 /* force drawing exit message even if screen updates are currently limited */
5648 LimitScreenUpdates(FALSE);
5652 /* deactivate toons on error message screen */
5653 setup.toons = FALSE;
5655 WaitForEventToContinue();
5659 /* ========================================================================= */
5661 /* ========================================================================= */
5665 print_timestamp_init("OpenAll");
5667 game_status = GAME_MODE_LOADING;
5671 InitGlobal(); /* initialize some global variables */
5673 print_timestamp_time("[init global stuff]");
5675 if (options.execute_command)
5676 Execute_Command(options.execute_command);
5678 if (options.serveronly)
5680 #if defined(PLATFORM_UNIX)
5681 NetworkServer(options.server_port, options.serveronly);
5683 Error(ERR_WARN, "networking only supported in Unix version");
5686 exit(0); /* never reached, server loops forever */
5691 print_timestamp_time("[init setup/config stuff (1)]");
5694 print_timestamp_time("[init setup/config stuff (2)]");
5696 print_timestamp_time("[init setup/config stuff (3)]");
5697 InitArtworkInfo(); /* needed before loading gfx, sound & music */
5698 print_timestamp_time("[init setup/config stuff (4)]");
5699 InitArtworkConfig(); /* needed before forking sound child process */
5700 print_timestamp_time("[init setup/config stuff (5)]");
5702 print_timestamp_time("[init setup/config stuff (6)]");
5704 InitRND(NEW_RANDOMIZE);
5705 InitSimpleRandom(NEW_RANDOMIZE);
5709 print_timestamp_time("[init setup/config stuff]");
5712 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
5714 InitEventFilter(FilterEvents);
5716 print_timestamp_time("[init video stuff]");
5718 InitElementPropertiesStatic();
5719 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5720 InitElementPropertiesGfxElement();
5722 print_timestamp_time("[init element properties stuff]");
5726 print_timestamp_time("InitGfx");
5729 print_timestamp_time("InitLevelInfo");
5731 InitLevelArtworkInfo();
5732 print_timestamp_time("InitLevelArtworkInfo");
5734 InitOverrideArtwork(); /* needs to know current level directory */
5735 print_timestamp_time("InitOverrideArtwork");
5737 InitImages(); /* needs to know current level directory */
5738 print_timestamp_time("InitImages");
5740 InitSound(NULL); /* needs to know current level directory */
5741 print_timestamp_time("InitSound");
5743 InitMusic(NULL); /* needs to know current level directory */
5744 print_timestamp_time("InitMusic");
5746 InitGfxBackground();
5751 if (global.autoplay_leveldir)
5756 else if (global.convert_leveldir)
5761 else if (global.create_images_dir)
5763 CreateLevelSketchImages();
5767 game_status = GAME_MODE_MAIN;
5769 FadeSetEnterScreen();
5770 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
5771 FadeSkipNextFadeOut();
5773 print_timestamp_time("[post-artwork]");
5775 print_timestamp_done("OpenAll");
5779 InitNetworkServer();
5782 Error(ERR_DEBUG, "::: SDL_GetBasePath() == '%s'",
5784 Error(ERR_DEBUG, "::: SDL_GetPrefPath() == '%s'",
5785 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
5786 #if defined(PLATFORM_ANDROID)
5787 Error(ERR_DEBUG, "::: SDL_AndroidGetInternalStoragePath() == '%s'",
5788 SDL_AndroidGetInternalStoragePath());
5789 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStoragePath() == '%s'",
5790 SDL_AndroidGetExternalStoragePath());
5791 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStorageState() == '%s'",
5792 (SDL_AndroidGetExternalStorageState() ==
5793 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "read" :
5794 SDL_AndroidGetExternalStorageState() ==
5795 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "write" : "not available"));
5800 void CloseAllAndExit(int exit_value)
5805 CloseAudio(); /* called after freeing sounds (needed for SDL) */
5812 #if defined(TARGET_SDL)
5813 #if defined(TARGET_SDL2)
5815 // set a flag to tell the network server thread to quit and wait for it
5816 // using SDL_WaitThread()
5818 if (network_server) /* terminate network server */
5819 SDL_KillThread(server_thread);
5823 CloseVideoDisplay();
5824 ClosePlatformDependentStuff();
5826 if (exit_value != 0)
5828 /* fall back to default level set (current set may have caused an error) */
5829 SaveLevelSetup_LastSeries_Deactivate();
5831 /* tell user where to find error log file which may contain more details */
5832 // (error notification now directly displayed on screen inside R'n'D
5833 // NotifyUserAboutErrorFile(); /* currently only works for Windows */