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);
161 // default (standard sized) bitmap may have changed now -- update it
163 g->bitmap = g->bitmaps[IMG_BITMAP_STANDARD];
166 void InitElementSmallImages()
168 print_timestamp_init("InitElementSmallImages");
170 static int special_graphics[] =
172 IMG_EDITOR_ELEMENT_BORDER,
173 IMG_EDITOR_ELEMENT_BORDER_INPUT,
174 IMG_EDITOR_CASCADE_LIST,
175 IMG_EDITOR_CASCADE_LIST_ACTIVE,
178 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
179 int num_property_mappings = getImageListPropertyMappingSize();
182 print_timestamp_time("getImageListPropertyMapping/Size");
184 print_timestamp_init("InitElementSmallImagesScaledUp (1)");
185 /* initialize normal images from static configuration */
186 for (i = 0; element_to_graphic[i].element > -1; i++)
187 InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
188 print_timestamp_done("InitElementSmallImagesScaledUp (1)");
190 /* initialize special images from static configuration */
191 for (i = 0; element_to_special_graphic[i].element > -1; i++)
192 InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
193 print_timestamp_time("InitElementSmallImagesScaledUp (2)");
195 /* initialize images from dynamic configuration (may be elements or other) */
196 for (i = 0; i < num_property_mappings; i++)
197 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
198 print_timestamp_time("InitElementSmallImagesScaledUp (3)");
200 /* initialize special images from above list (non-element images) */
201 for (i = 0; special_graphics[i] > -1; i++)
202 InitElementSmallImagesScaledUp(special_graphics[i]);
203 print_timestamp_time("InitElementSmallImagesScaledUp (4)");
205 print_timestamp_done("InitElementSmallImages");
208 void InitScaledImages()
212 /* scale normal images from static configuration, if not already scaled */
213 for (i = 0; i < NUM_IMAGE_FILES; i++)
214 ScaleImage(i, graphic_info[i].scale_up_factor);
218 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
219 void SetBitmaps_EM(Bitmap **em_bitmap)
221 em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
222 em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].bitmap;
227 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
228 void SetBitmaps_SP(Bitmap **sp_bitmap)
230 *sp_bitmap = graphic_info[IMG_SP_OBJECTS].bitmap;
234 static int getFontBitmapID(int font_nr)
238 /* (special case: do not use special font for GAME_MODE_LOADING) */
239 if (game_status >= GAME_MODE_TITLE_INITIAL &&
240 game_status <= GAME_MODE_PSEUDO_PREVIEW)
241 special = game_status;
242 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
243 special = GFX_SPECIAL_ARG_MAIN;
246 return font_info[font_nr].special_bitmap_id[special];
251 static int getFontFromToken(char *token)
253 char *value = getHashEntry(font_token_hash, token);
258 /* if font not found, use reliable default value */
259 return FONT_INITIAL_1;
262 void InitFontGraphicInfo()
264 static struct FontBitmapInfo *font_bitmap_info = NULL;
265 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
266 int num_property_mappings = getImageListPropertyMappingSize();
267 int num_font_bitmaps = NUM_FONTS;
270 if (graphic_info == NULL) /* still at startup phase */
272 InitFontInfo(font_initial, NUM_INITIAL_FONTS,
273 getFontBitmapID, getFontFromToken);
278 /* ---------- initialize font graphic definitions ---------- */
280 /* always start with reliable default values (normal font graphics) */
281 for (i = 0; i < NUM_FONTS; i++)
282 font_info[i].graphic = IMG_FONT_INITIAL_1;
284 /* initialize normal font/graphic mapping from static configuration */
285 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
287 int font_nr = font_to_graphic[i].font_nr;
288 int special = font_to_graphic[i].special;
289 int graphic = font_to_graphic[i].graphic;
294 font_info[font_nr].graphic = graphic;
297 /* always start with reliable default values (special font graphics) */
298 for (i = 0; i < NUM_FONTS; i++)
300 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
302 font_info[i].special_graphic[j] = font_info[i].graphic;
303 font_info[i].special_bitmap_id[j] = i;
307 /* initialize special font/graphic mapping from static configuration */
308 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
310 int font_nr = font_to_graphic[i].font_nr;
311 int special = font_to_graphic[i].special;
312 int graphic = font_to_graphic[i].graphic;
313 int base_graphic = font2baseimg(font_nr);
315 if (IS_SPECIAL_GFX_ARG(special))
317 boolean base_redefined =
318 getImageListEntryFromImageID(base_graphic)->redefined;
319 boolean special_redefined =
320 getImageListEntryFromImageID(graphic)->redefined;
321 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
323 /* if the base font ("font.title_1", for example) has been redefined,
324 but not the special font ("font.title_1.LEVELS", for example), do not
325 use an existing (in this case considered obsolete) special font
326 anymore, but use the automatically determined default font */
327 /* special case: cloned special fonts must be explicitly redefined,
328 but are not automatically redefined by redefining base font */
329 if (base_redefined && !special_redefined && !special_cloned)
332 font_info[font_nr].special_graphic[special] = graphic;
333 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
338 /* initialize special font/graphic mapping from dynamic configuration */
339 for (i = 0; i < num_property_mappings; i++)
341 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
342 int special = property_mapping[i].ext3_index;
343 int graphic = property_mapping[i].artwork_index;
348 if (IS_SPECIAL_GFX_ARG(special))
350 font_info[font_nr].special_graphic[special] = graphic;
351 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
356 /* correct special font/graphic mapping for cloned fonts for downwards
357 compatibility of PREVIEW fonts -- this is only needed for implicit
358 redefinition of special font by redefined base font, and only if other
359 fonts are cloned from this special font (like in the "Zelda" level set) */
360 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
362 int font_nr = font_to_graphic[i].font_nr;
363 int special = font_to_graphic[i].special;
364 int graphic = font_to_graphic[i].graphic;
366 if (IS_SPECIAL_GFX_ARG(special))
368 boolean special_redefined =
369 getImageListEntryFromImageID(graphic)->redefined;
370 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
372 if (special_cloned && !special_redefined)
376 for (j = 0; font_to_graphic[j].font_nr > -1; j++)
378 int font_nr2 = font_to_graphic[j].font_nr;
379 int special2 = font_to_graphic[j].special;
380 int graphic2 = font_to_graphic[j].graphic;
382 if (IS_SPECIAL_GFX_ARG(special2) &&
383 graphic2 == graphic_info[graphic].clone_from)
385 font_info[font_nr].special_graphic[special] =
386 font_info[font_nr2].special_graphic[special2];
387 font_info[font_nr].special_bitmap_id[special] =
388 font_info[font_nr2].special_bitmap_id[special2];
395 /* reset non-redefined ".active" font graphics if normal font is redefined */
396 /* (this different treatment is needed because normal and active fonts are
397 independently defined ("active" is not a property of font definitions!) */
398 for (i = 0; i < NUM_FONTS; i++)
400 int font_nr_base = i;
401 int font_nr_active = FONT_ACTIVE(font_nr_base);
403 /* check only those fonts with exist as normal and ".active" variant */
404 if (font_nr_base != font_nr_active)
406 int base_graphic = font_info[font_nr_base].graphic;
407 int active_graphic = font_info[font_nr_active].graphic;
408 boolean base_redefined =
409 getImageListEntryFromImageID(base_graphic)->redefined;
410 boolean active_redefined =
411 getImageListEntryFromImageID(active_graphic)->redefined;
413 /* if the base font ("font.menu_1", for example) has been redefined,
414 but not the active font ("font.menu_1.active", for example), do not
415 use an existing (in this case considered obsolete) active font
416 anymore, but use the automatically determined default font */
417 if (base_redefined && !active_redefined)
418 font_info[font_nr_active].graphic = base_graphic;
420 /* now also check each "special" font (which may be the same as above) */
421 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
423 int base_graphic = font_info[font_nr_base].special_graphic[j];
424 int active_graphic = font_info[font_nr_active].special_graphic[j];
425 boolean base_redefined =
426 getImageListEntryFromImageID(base_graphic)->redefined;
427 boolean active_redefined =
428 getImageListEntryFromImageID(active_graphic)->redefined;
430 /* same as above, but check special graphic definitions, for example:
431 redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN" */
432 if (base_redefined && !active_redefined)
434 font_info[font_nr_active].special_graphic[j] =
435 font_info[font_nr_base].special_graphic[j];
436 font_info[font_nr_active].special_bitmap_id[j] =
437 font_info[font_nr_base].special_bitmap_id[j];
443 /* ---------- initialize font bitmap array ---------- */
445 if (font_bitmap_info != NULL)
446 FreeFontInfo(font_bitmap_info);
449 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
451 /* ---------- initialize font bitmap definitions ---------- */
453 for (i = 0; i < NUM_FONTS; i++)
455 if (i < NUM_INITIAL_FONTS)
457 font_bitmap_info[i] = font_initial[i];
461 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
463 int font_bitmap_id = font_info[i].special_bitmap_id[j];
464 int graphic = font_info[i].special_graphic[j];
466 /* set 'graphic_info' for font entries, if uninitialized (guessed) */
467 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
469 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
470 graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
473 /* copy font relevant information from graphics information */
474 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
475 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
476 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
477 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
478 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
480 font_bitmap_info[font_bitmap_id].draw_xoffset =
481 graphic_info[graphic].draw_xoffset;
482 font_bitmap_info[font_bitmap_id].draw_yoffset =
483 graphic_info[graphic].draw_yoffset;
485 font_bitmap_info[font_bitmap_id].num_chars =
486 graphic_info[graphic].anim_frames;
487 font_bitmap_info[font_bitmap_id].num_chars_per_line =
488 graphic_info[graphic].anim_frames_per_line;
492 InitFontInfo(font_bitmap_info, num_font_bitmaps,
493 getFontBitmapID, getFontFromToken);
496 void InitElementGraphicInfo()
498 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
499 int num_property_mappings = getImageListPropertyMappingSize();
502 if (graphic_info == NULL) /* still at startup phase */
505 /* set values to -1 to identify later as "uninitialized" values */
506 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
508 for (act = 0; act < NUM_ACTIONS; act++)
510 element_info[i].graphic[act] = -1;
511 element_info[i].crumbled[act] = -1;
513 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
515 element_info[i].direction_graphic[act][dir] = -1;
516 element_info[i].direction_crumbled[act][dir] = -1;
523 /* initialize normal element/graphic mapping from static configuration */
524 for (i = 0; element_to_graphic[i].element > -1; i++)
526 int element = element_to_graphic[i].element;
527 int action = element_to_graphic[i].action;
528 int direction = element_to_graphic[i].direction;
529 boolean crumbled = element_to_graphic[i].crumbled;
530 int graphic = element_to_graphic[i].graphic;
531 int base_graphic = el2baseimg(element);
533 if (graphic_info[graphic].bitmap == NULL)
536 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
539 boolean base_redefined =
540 getImageListEntryFromImageID(base_graphic)->redefined;
541 boolean act_dir_redefined =
542 getImageListEntryFromImageID(graphic)->redefined;
544 /* if the base graphic ("emerald", for example) has been redefined,
545 but not the action graphic ("emerald.falling", for example), do not
546 use an existing (in this case considered obsolete) action graphic
547 anymore, but use the automatically determined default graphic */
548 if (base_redefined && !act_dir_redefined)
553 action = ACTION_DEFAULT;
558 element_info[element].direction_crumbled[action][direction] = graphic;
560 element_info[element].crumbled[action] = graphic;
565 element_info[element].direction_graphic[action][direction] = graphic;
567 element_info[element].graphic[action] = graphic;
571 /* initialize normal element/graphic mapping from dynamic configuration */
572 for (i = 0; i < num_property_mappings; i++)
574 int element = property_mapping[i].base_index;
575 int action = property_mapping[i].ext1_index;
576 int direction = property_mapping[i].ext2_index;
577 int special = property_mapping[i].ext3_index;
578 int graphic = property_mapping[i].artwork_index;
579 boolean crumbled = FALSE;
581 if (special == GFX_SPECIAL_ARG_CRUMBLED)
587 if (graphic_info[graphic].bitmap == NULL)
590 if (element >= MAX_NUM_ELEMENTS || special != -1)
594 action = ACTION_DEFAULT;
599 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
600 element_info[element].direction_crumbled[action][dir] = -1;
603 element_info[element].direction_crumbled[action][direction] = graphic;
605 element_info[element].crumbled[action] = graphic;
610 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
611 element_info[element].direction_graphic[action][dir] = -1;
614 element_info[element].direction_graphic[action][direction] = graphic;
616 element_info[element].graphic[action] = graphic;
620 /* now copy all graphics that are defined to be cloned from other graphics */
621 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
623 int graphic = element_info[i].graphic[ACTION_DEFAULT];
624 int crumbled_like, diggable_like;
629 crumbled_like = graphic_info[graphic].crumbled_like;
630 diggable_like = graphic_info[graphic].diggable_like;
632 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
634 for (act = 0; act < NUM_ACTIONS; act++)
635 element_info[i].crumbled[act] =
636 element_info[crumbled_like].crumbled[act];
637 for (act = 0; act < NUM_ACTIONS; act++)
638 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
639 element_info[i].direction_crumbled[act][dir] =
640 element_info[crumbled_like].direction_crumbled[act][dir];
643 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
645 element_info[i].graphic[ACTION_DIGGING] =
646 element_info[diggable_like].graphic[ACTION_DIGGING];
647 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
648 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
649 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
653 /* set hardcoded definitions for some runtime elements without graphic */
654 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
656 /* set hardcoded definitions for some internal elements without graphic */
657 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
659 if (IS_EDITOR_CASCADE_INACTIVE(i))
660 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
661 else if (IS_EDITOR_CASCADE_ACTIVE(i))
662 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
665 /* now set all undefined/invalid graphics to -1 to set to default after it */
666 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
668 for (act = 0; act < NUM_ACTIONS; act++)
672 graphic = element_info[i].graphic[act];
673 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
674 element_info[i].graphic[act] = -1;
676 graphic = element_info[i].crumbled[act];
677 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
678 element_info[i].crumbled[act] = -1;
680 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
682 graphic = element_info[i].direction_graphic[act][dir];
683 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
684 element_info[i].direction_graphic[act][dir] = -1;
686 graphic = element_info[i].direction_crumbled[act][dir];
687 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
688 element_info[i].direction_crumbled[act][dir] = -1;
695 /* adjust graphics with 2nd tile for movement according to direction
696 (do this before correcting '-1' values to minimize calculations) */
697 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
699 for (act = 0; act < NUM_ACTIONS; act++)
701 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
703 int graphic = element_info[i].direction_graphic[act][dir];
704 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
706 if (act == ACTION_FALLING) /* special case */
707 graphic = element_info[i].graphic[act];
710 graphic_info[graphic].double_movement &&
711 graphic_info[graphic].swap_double_tiles != 0)
713 struct GraphicInfo *g = &graphic_info[graphic];
714 int src_x_front = g->src_x;
715 int src_y_front = g->src_y;
716 int src_x_back = g->src_x + g->offset2_x;
717 int src_y_back = g->src_y + g->offset2_y;
718 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
720 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
721 src_y_front < src_y_back);
722 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
723 boolean swap_movement_tiles_autodetected =
724 (!frames_are_ordered_diagonally &&
725 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
726 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
727 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
728 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
731 /* swap frontside and backside graphic tile coordinates, if needed */
732 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
734 /* get current (wrong) backside tile coordinates */
735 getFixedGraphicSourceExt(graphic, 0, &dummy,
736 &src_x_back, &src_y_back, TRUE);
738 /* set frontside tile coordinates to backside tile coordinates */
739 g->src_x = src_x_back;
740 g->src_y = src_y_back;
742 /* invert tile offset to point to new backside tile coordinates */
746 /* do not swap front and backside tiles again after correction */
747 g->swap_double_tiles = 0;
756 /* now set all '-1' values to element specific default values */
757 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
759 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
760 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
761 int default_direction_graphic[NUM_DIRECTIONS_FULL];
762 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
764 if (default_graphic == -1)
765 default_graphic = IMG_UNKNOWN;
767 if (default_crumbled == -1)
768 default_crumbled = default_graphic;
770 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
772 default_direction_graphic[dir] =
773 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
774 default_direction_crumbled[dir] =
775 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
777 if (default_direction_graphic[dir] == -1)
778 default_direction_graphic[dir] = default_graphic;
780 if (default_direction_crumbled[dir] == -1)
781 default_direction_crumbled[dir] = default_direction_graphic[dir];
784 for (act = 0; act < NUM_ACTIONS; act++)
786 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
787 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
788 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
789 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
790 act == ACTION_TURNING_FROM_RIGHT ||
791 act == ACTION_TURNING_FROM_UP ||
792 act == ACTION_TURNING_FROM_DOWN);
794 /* generic default action graphic (defined by "[default]" directive) */
795 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
796 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
797 int default_remove_graphic = IMG_EMPTY;
799 if (act_remove && default_action_graphic != -1)
800 default_remove_graphic = default_action_graphic;
802 /* look for special default action graphic (classic game specific) */
803 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
804 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
805 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
806 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
807 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
808 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
810 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
811 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
812 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
813 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
814 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
815 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
817 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
818 /* !!! make this better !!! */
819 if (i == EL_EMPTY_SPACE)
821 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
822 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
825 if (default_action_graphic == -1)
826 default_action_graphic = default_graphic;
828 if (default_action_crumbled == -1)
829 default_action_crumbled = default_action_graphic;
831 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
833 /* use action graphic as the default direction graphic, if undefined */
834 int default_action_direction_graphic = element_info[i].graphic[act];
835 int default_action_direction_crumbled = element_info[i].crumbled[act];
837 /* no graphic for current action -- use default direction graphic */
838 if (default_action_direction_graphic == -1)
839 default_action_direction_graphic =
840 (act_remove ? default_remove_graphic :
842 element_info[i].direction_graphic[ACTION_TURNING][dir] :
843 default_action_graphic != default_graphic ?
844 default_action_graphic :
845 default_direction_graphic[dir]);
847 if (element_info[i].direction_graphic[act][dir] == -1)
848 element_info[i].direction_graphic[act][dir] =
849 default_action_direction_graphic;
851 if (default_action_direction_crumbled == -1)
852 default_action_direction_crumbled =
853 element_info[i].direction_graphic[act][dir];
855 if (element_info[i].direction_crumbled[act][dir] == -1)
856 element_info[i].direction_crumbled[act][dir] =
857 default_action_direction_crumbled;
860 /* no graphic for this specific action -- use default action graphic */
861 if (element_info[i].graphic[act] == -1)
862 element_info[i].graphic[act] =
863 (act_remove ? default_remove_graphic :
864 act_turning ? element_info[i].graphic[ACTION_TURNING] :
865 default_action_graphic);
867 if (element_info[i].crumbled[act] == -1)
868 element_info[i].crumbled[act] = element_info[i].graphic[act];
875 void InitElementSpecialGraphicInfo()
877 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
878 int num_property_mappings = getImageListPropertyMappingSize();
881 /* always start with reliable default values */
882 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
883 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
884 element_info[i].special_graphic[j] =
885 element_info[i].graphic[ACTION_DEFAULT];
887 /* initialize special element/graphic mapping from static configuration */
888 for (i = 0; element_to_special_graphic[i].element > -1; i++)
890 int element = element_to_special_graphic[i].element;
891 int special = element_to_special_graphic[i].special;
892 int graphic = element_to_special_graphic[i].graphic;
893 int base_graphic = el2baseimg(element);
894 boolean base_redefined =
895 getImageListEntryFromImageID(base_graphic)->redefined;
896 boolean special_redefined =
897 getImageListEntryFromImageID(graphic)->redefined;
899 /* if the base graphic ("emerald", for example) has been redefined,
900 but not the special graphic ("emerald.EDITOR", for example), do not
901 use an existing (in this case considered obsolete) special graphic
902 anymore, but use the automatically created (down-scaled) graphic */
903 if (base_redefined && !special_redefined)
906 element_info[element].special_graphic[special] = graphic;
909 /* initialize special element/graphic mapping from dynamic configuration */
910 for (i = 0; i < num_property_mappings; i++)
912 int element = property_mapping[i].base_index;
913 int action = property_mapping[i].ext1_index;
914 int direction = property_mapping[i].ext2_index;
915 int special = property_mapping[i].ext3_index;
916 int graphic = property_mapping[i].artwork_index;
918 /* for action ".active", replace element with active element, if exists */
919 if (action == ACTION_ACTIVE && element != ELEMENT_ACTIVE(element))
921 element = ELEMENT_ACTIVE(element);
925 if (element >= MAX_NUM_ELEMENTS)
928 /* do not change special graphic if action or direction was specified */
929 if (action != -1 || direction != -1)
932 if (IS_SPECIAL_GFX_ARG(special))
933 element_info[element].special_graphic[special] = graphic;
936 /* now set all undefined/invalid graphics to default */
937 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
938 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
939 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
940 element_info[i].special_graphic[j] =
941 element_info[i].graphic[ACTION_DEFAULT];
944 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
946 if (type != TYPE_ELEMENT && type != TYPE_GRAPHIC)
947 return get_parameter_value(value_raw, suffix, type);
949 if (strEqual(value_raw, ARG_UNDEFINED))
950 return ARG_UNDEFINED_VALUE;
952 if (type == TYPE_ELEMENT)
954 char *value = getHashEntry(element_token_hash, value_raw);
958 Error(ERR_INFO_LINE, "-");
959 Error(ERR_INFO, "warning: error found in config file:");
960 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
961 Error(ERR_INFO, "error: invalid element token '%s'", value_raw);
962 Error(ERR_INFO, "custom graphic rejected for this element/action");
963 Error(ERR_INFO, "fallback done to undefined element for this graphic");
964 Error(ERR_INFO_LINE, "-");
967 return (value != NULL ? atoi(value) : EL_UNDEFINED);
969 else if (type == TYPE_GRAPHIC)
971 char *value = getHashEntry(graphic_token_hash, value_raw);
972 int fallback_graphic = IMG_CHAR_EXCLAM;
976 Error(ERR_INFO_LINE, "-");
977 Error(ERR_INFO, "warning: error found in config file:");
978 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
979 Error(ERR_INFO, "error: invalid graphic token '%s'", value_raw);
980 Error(ERR_INFO, "custom graphic rejected for this element/action");
981 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
982 Error(ERR_INFO_LINE, "-");
985 return (value != NULL ? atoi(value) : fallback_graphic);
991 static int get_scaled_graphic_width(int graphic)
993 int original_width = getOriginalImageWidthFromImageID(graphic);
994 int scale_up_factor = graphic_info[graphic].scale_up_factor;
996 return original_width * scale_up_factor;
999 static int get_scaled_graphic_height(int graphic)
1001 int original_height = getOriginalImageHeightFromImageID(graphic);
1002 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1004 return original_height * scale_up_factor;
1007 static void set_graphic_parameters_ext(int graphic, int *parameter,
1008 Bitmap **src_bitmaps)
1010 struct GraphicInfo *g = &graphic_info[graphic];
1011 Bitmap *src_bitmap = (src_bitmaps ? src_bitmaps[IMG_BITMAP_STANDARD] : NULL);
1012 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1013 int anim_frames_per_line = 1;
1015 /* always start with reliable default values */
1016 g->src_image_width = 0;
1017 g->src_image_height = 0;
1020 g->width = TILEX; /* default for element graphics */
1021 g->height = TILEY; /* default for element graphics */
1022 g->offset_x = 0; /* one or both of these values ... */
1023 g->offset_y = 0; /* ... will be corrected later */
1024 g->offset2_x = 0; /* one or both of these values ... */
1025 g->offset2_y = 0; /* ... will be corrected later */
1026 g->swap_double_tiles = -1; /* auto-detect tile swapping */
1027 g->crumbled_like = -1; /* do not use clone element */
1028 g->diggable_like = -1; /* do not use clone element */
1029 g->border_size = TILEX / 8; /* "CRUMBLED" border size */
1030 g->scale_up_factor = 1; /* default: no scaling up */
1031 g->tile_size = TILESIZE; /* default: standard tile size */
1032 g->clone_from = -1; /* do not use clone graphic */
1033 g->anim_delay_fixed = 0;
1034 g->anim_delay_random = 0;
1035 g->post_delay_fixed = 0;
1036 g->post_delay_random = 0;
1037 g->fade_mode = FADE_MODE_DEFAULT;
1041 g->align = ALIGN_CENTER; /* default for title screens */
1042 g->valign = VALIGN_MIDDLE; /* default for title screens */
1043 g->sort_priority = 0; /* default for title screens */
1045 g->style = STYLE_DEFAULT;
1047 g->bitmaps = src_bitmaps;
1048 g->bitmap = src_bitmap;
1050 /* optional zoom factor for scaling up the image to a larger size */
1051 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1052 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1053 if (g->scale_up_factor < 1)
1054 g->scale_up_factor = 1; /* no scaling */
1056 /* optional tile size for using non-standard image size */
1057 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1059 g->tile_size = parameter[GFX_ARG_TILE_SIZE];
1062 // CHECK: should tile sizes less than standard tile size be allowed?
1063 if (g->tile_size < TILESIZE)
1064 g->tile_size = TILESIZE; /* standard tile size */
1068 // CHECK: when setting tile size, should this set width and height?
1069 g->width = g->tile_size;
1070 g->height = g->tile_size;
1074 if (g->use_image_size)
1076 /* set new default bitmap size (with scaling, but without small images) */
1077 g->width = get_scaled_graphic_width(graphic);
1078 g->height = get_scaled_graphic_height(graphic);
1081 /* optional width and height of each animation frame */
1082 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1083 g->width = parameter[GFX_ARG_WIDTH];
1084 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1085 g->height = parameter[GFX_ARG_HEIGHT];
1087 /* optional x and y tile position of animation frame sequence */
1088 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1089 g->src_x = parameter[GFX_ARG_XPOS] * g->width;
1090 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1091 g->src_y = parameter[GFX_ARG_YPOS] * g->height;
1093 /* optional x and y pixel position of animation frame sequence */
1094 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1095 g->src_x = parameter[GFX_ARG_X];
1096 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1097 g->src_y = parameter[GFX_ARG_Y];
1103 Error(ERR_INFO_LINE, "-");
1104 Error(ERR_WARN, "invalid value %d for '%s.width' (fallback done to %d)",
1105 g->width, getTokenFromImageID(graphic), TILEX);
1106 Error(ERR_INFO_LINE, "-");
1108 g->width = TILEX; /* will be checked to be inside bitmap later */
1113 Error(ERR_INFO_LINE, "-");
1114 Error(ERR_WARN, "invalid value %d for '%s.height' (fallback done to %d)",
1115 g->height, getTokenFromImageID(graphic), TILEY);
1116 Error(ERR_INFO_LINE, "-");
1118 g->height = TILEY; /* will be checked to be inside bitmap later */
1124 /* get final bitmap size (with scaling, but without small images) */
1125 int src_image_width = get_scaled_graphic_width(graphic);
1126 int src_image_height = get_scaled_graphic_height(graphic);
1128 if (src_image_width == 0 || src_image_height == 0)
1130 /* only happens when loaded outside artwork system (like "global.busy") */
1131 src_image_width = src_bitmap->width;
1132 src_image_height = src_bitmap->height;
1135 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1137 anim_frames_per_row = src_image_width / g->tile_size;
1138 anim_frames_per_col = src_image_height / g->tile_size;
1142 anim_frames_per_row = src_image_width / g->width;
1143 anim_frames_per_col = src_image_height / g->height;
1146 g->src_image_width = src_image_width;
1147 g->src_image_height = src_image_height;
1150 /* correct x or y offset dependent of vertical or horizontal frame order */
1151 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1153 g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1154 parameter[GFX_ARG_OFFSET] : g->height);
1155 anim_frames_per_line = anim_frames_per_col;
1157 else /* frames are ordered horizontally */
1159 g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1160 parameter[GFX_ARG_OFFSET] : g->width);
1161 anim_frames_per_line = anim_frames_per_row;
1164 /* optionally, the x and y offset of frames can be specified directly */
1165 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1166 g->offset_x = parameter[GFX_ARG_XOFFSET];
1167 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1168 g->offset_y = parameter[GFX_ARG_YOFFSET];
1170 /* optionally, moving animations may have separate start and end graphics */
1171 g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1173 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1174 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1176 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1177 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1178 g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1179 parameter[GFX_ARG_2ND_OFFSET] : g->height);
1180 else /* frames are ordered horizontally */
1181 g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1182 parameter[GFX_ARG_2ND_OFFSET] : g->width);
1184 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1185 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1186 g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1187 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1188 g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1190 /* optionally, the second movement tile can be specified as start tile */
1191 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1192 g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1194 /* automatically determine correct number of frames, if not defined */
1195 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1196 g->anim_frames = parameter[GFX_ARG_FRAMES];
1197 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1198 g->anim_frames = anim_frames_per_row;
1199 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1200 g->anim_frames = anim_frames_per_col;
1204 if (g->anim_frames == 0) /* frames must be at least 1 */
1207 g->anim_frames_per_line =
1208 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1209 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1211 g->anim_delay = parameter[GFX_ARG_DELAY];
1212 if (g->anim_delay == 0) /* delay must be at least 1 */
1215 g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1217 /* automatically determine correct start frame, if not defined */
1218 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1219 g->anim_start_frame = 0;
1220 else if (g->anim_mode & ANIM_REVERSE)
1221 g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1223 g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1225 /* animation synchronized with global frame counter, not move position */
1226 g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1228 /* optional element for cloning crumble graphics */
1229 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1230 g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1232 /* optional element for cloning digging graphics */
1233 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1234 g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1236 /* optional border size for "crumbling" diggable graphics */
1237 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1238 g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1240 /* this is only used for player "boring" and "sleeping" actions */
1241 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1242 g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1243 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1244 g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1245 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1246 g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1247 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1248 g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1250 /* this is only used for toon animations */
1251 g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1252 g->step_delay = parameter[GFX_ARG_STEP_DELAY];
1254 /* this is only used for drawing font characters */
1255 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1256 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1258 /* this is only used for drawing envelope graphics */
1259 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1261 /* optional graphic for cloning all graphics settings */
1262 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1263 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1265 /* optional settings for drawing title screens and title messages */
1266 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1267 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1268 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1269 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1270 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1271 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1272 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1273 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1274 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1275 g->align = parameter[GFX_ARG_ALIGN];
1276 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1277 g->valign = parameter[GFX_ARG_VALIGN];
1278 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1279 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1281 if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
1282 g->class = parameter[GFX_ARG_CLASS];
1283 if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
1284 g->style = parameter[GFX_ARG_STYLE];
1286 /* this is only used for drawing menu buttons and text */
1287 g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
1288 g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
1289 g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
1290 g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
1293 static void set_graphic_parameters(int graphic)
1295 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1296 char **parameter_raw = image->parameter;
1297 Bitmap **src_bitmaps = getBitmapsFromImageID(graphic);
1298 int parameter[NUM_GFX_ARGS];
1301 /* if fallback to default artwork is done, also use the default parameters */
1302 if (image->fallback_to_default)
1303 parameter_raw = image->default_parameter;
1305 /* get integer values from string parameters */
1306 for (i = 0; i < NUM_GFX_ARGS; i++)
1307 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1308 image_config_suffix[i].token,
1309 image_config_suffix[i].type);
1311 set_graphic_parameters_ext(graphic, parameter, src_bitmaps);
1313 UPDATE_BUSY_STATE();
1316 static void set_cloned_graphic_parameters(int graphic)
1318 int fallback_graphic = IMG_CHAR_EXCLAM;
1319 int max_num_images = getImageListSize();
1320 int clone_graphic = graphic_info[graphic].clone_from;
1321 int num_references_followed = 1;
1323 while (graphic_info[clone_graphic].clone_from != -1 &&
1324 num_references_followed < max_num_images)
1326 clone_graphic = graphic_info[clone_graphic].clone_from;
1328 num_references_followed++;
1331 if (num_references_followed >= max_num_images)
1333 Error(ERR_INFO_LINE, "-");
1334 Error(ERR_INFO, "warning: error found in config file:");
1335 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1336 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1337 Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1338 Error(ERR_INFO, "custom graphic rejected for this element/action");
1340 if (graphic == fallback_graphic)
1341 Error(ERR_EXIT, "no fallback graphic available");
1343 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1344 Error(ERR_INFO_LINE, "-");
1346 graphic_info[graphic] = graphic_info[fallback_graphic];
1350 graphic_info[graphic] = graphic_info[clone_graphic];
1351 graphic_info[graphic].clone_from = clone_graphic;
1355 static void InitGraphicInfo()
1357 int fallback_graphic = IMG_CHAR_EXCLAM;
1358 int num_images = getImageListSize();
1361 /* use image size as default values for width and height for these images */
1362 static int full_size_graphics[] =
1367 IMG_BACKGROUND_ENVELOPE_1,
1368 IMG_BACKGROUND_ENVELOPE_2,
1369 IMG_BACKGROUND_ENVELOPE_3,
1370 IMG_BACKGROUND_ENVELOPE_4,
1371 IMG_BACKGROUND_REQUEST,
1374 IMG_BACKGROUND_TITLE_INITIAL,
1375 IMG_BACKGROUND_TITLE,
1376 IMG_BACKGROUND_MAIN,
1377 IMG_BACKGROUND_LEVELS,
1378 IMG_BACKGROUND_LEVELNR,
1379 IMG_BACKGROUND_SCORES,
1380 IMG_BACKGROUND_EDITOR,
1381 IMG_BACKGROUND_INFO,
1382 IMG_BACKGROUND_INFO_ELEMENTS,
1383 IMG_BACKGROUND_INFO_MUSIC,
1384 IMG_BACKGROUND_INFO_CREDITS,
1385 IMG_BACKGROUND_INFO_PROGRAM,
1386 IMG_BACKGROUND_INFO_VERSION,
1387 IMG_BACKGROUND_INFO_LEVELSET,
1388 IMG_BACKGROUND_SETUP,
1389 IMG_BACKGROUND_PLAYING,
1390 IMG_BACKGROUND_DOOR,
1391 IMG_BACKGROUND_TAPE,
1392 IMG_BACKGROUND_PANEL,
1393 IMG_BACKGROUND_PALETTE,
1394 IMG_BACKGROUND_TOOLBOX,
1396 IMG_TITLESCREEN_INITIAL_1,
1397 IMG_TITLESCREEN_INITIAL_2,
1398 IMG_TITLESCREEN_INITIAL_3,
1399 IMG_TITLESCREEN_INITIAL_4,
1400 IMG_TITLESCREEN_INITIAL_5,
1407 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1,
1408 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2,
1409 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3,
1410 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4,
1411 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5,
1412 IMG_BACKGROUND_TITLEMESSAGE_1,
1413 IMG_BACKGROUND_TITLEMESSAGE_2,
1414 IMG_BACKGROUND_TITLEMESSAGE_3,
1415 IMG_BACKGROUND_TITLEMESSAGE_4,
1416 IMG_BACKGROUND_TITLEMESSAGE_5,
1421 checked_free(graphic_info);
1423 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1425 /* initialize "use_image_size" flag with default value */
1426 for (i = 0; i < num_images; i++)
1427 graphic_info[i].use_image_size = FALSE;
1429 /* initialize "use_image_size" flag from static configuration above */
1430 for (i = 0; full_size_graphics[i] != -1; i++)
1431 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1433 /* first set all graphic paramaters ... */
1434 for (i = 0; i < num_images; i++)
1435 set_graphic_parameters(i);
1437 /* ... then copy these parameters for cloned graphics */
1438 for (i = 0; i < num_images; i++)
1439 if (graphic_info[i].clone_from != -1)
1440 set_cloned_graphic_parameters(i);
1442 for (i = 0; i < num_images; i++)
1447 int first_frame, last_frame;
1448 int src_bitmap_width, src_bitmap_height;
1450 /* now check if no animation frames are outside of the loaded image */
1452 if (graphic_info[i].bitmap == NULL)
1453 continue; /* skip check for optional images that are undefined */
1455 /* get image size (this can differ from the standard element tile size!) */
1456 width = graphic_info[i].width;
1457 height = graphic_info[i].height;
1459 /* get final bitmap size (with scaling, but without small images) */
1460 src_bitmap_width = graphic_info[i].src_image_width;
1461 src_bitmap_height = graphic_info[i].src_image_height;
1463 /* check if first animation frame is inside specified bitmap */
1466 getFixedGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1468 /* this avoids calculating wrong start position for out-of-bounds frame */
1469 src_x = graphic_info[i].src_x;
1470 src_y = graphic_info[i].src_y;
1472 if (src_x < 0 || src_y < 0 ||
1473 src_x + width > src_bitmap_width ||
1474 src_y + height > src_bitmap_height)
1476 Error(ERR_INFO_LINE, "-");
1477 Error(ERR_INFO, "warning: error found in config file:");
1478 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1479 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1480 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1482 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1483 src_x, src_y, src_bitmap_width, src_bitmap_height);
1484 Error(ERR_INFO, "custom graphic rejected for this element/action");
1486 if (i == fallback_graphic)
1487 Error(ERR_EXIT, "no fallback graphic available");
1489 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1490 Error(ERR_INFO_LINE, "-");
1492 graphic_info[i] = graphic_info[fallback_graphic];
1495 /* check if last animation frame is inside specified bitmap */
1497 last_frame = graphic_info[i].anim_frames - 1;
1498 getFixedGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1500 if (src_x < 0 || src_y < 0 ||
1501 src_x + width > src_bitmap_width ||
1502 src_y + height > src_bitmap_height)
1504 Error(ERR_INFO_LINE, "-");
1505 Error(ERR_INFO, "warning: error found in config file:");
1506 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1507 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1508 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1510 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1511 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1512 Error(ERR_INFO, "::: %d, %d", width, height);
1513 Error(ERR_INFO, "custom graphic rejected for this element/action");
1515 if (i == fallback_graphic)
1516 Error(ERR_EXIT, "no fallback graphic available");
1518 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1519 Error(ERR_INFO_LINE, "-");
1521 graphic_info[i] = graphic_info[fallback_graphic];
1526 static void InitGraphicCompatibilityInfo()
1528 struct FileInfo *fi_global_door =
1529 getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1530 int num_images = getImageListSize();
1533 /* the following compatibility handling is needed for the following case:
1534 versions up to 3.3.0.0 used one large bitmap "global.door" for various
1535 graphics mainly used for door and panel graphics, like editor, tape and
1536 in-game buttons with hard-coded bitmap positions and button sizes; as
1537 these graphics now have individual definitions, redefining "global.door"
1538 to change all these graphics at once like before does not work anymore
1539 (because all those individual definitions still have their default values);
1540 to solve this, remap all those individual definitions that are not
1541 redefined to the new bitmap of "global.door" if it was redefined */
1543 /* special compatibility handling if image "global.door" was redefined */
1544 if (fi_global_door->redefined)
1546 for (i = 0; i < num_images; i++)
1548 struct FileInfo *fi = getImageListEntryFromImageID(i);
1550 /* process only those images that still use the default settings */
1553 /* process all images which default to same image as "global.door" */
1554 if (strEqual(fi->default_filename, fi_global_door->default_filename))
1556 // printf("::: special treatment needed for token '%s'\n", fi->token);
1558 graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
1564 InitGraphicCompatibilityInfo_Doors();
1567 static void InitElementSoundInfo()
1569 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1570 int num_property_mappings = getSoundListPropertyMappingSize();
1573 /* set values to -1 to identify later as "uninitialized" values */
1574 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1575 for (act = 0; act < NUM_ACTIONS; act++)
1576 element_info[i].sound[act] = -1;
1578 /* initialize element/sound mapping from static configuration */
1579 for (i = 0; element_to_sound[i].element > -1; i++)
1581 int element = element_to_sound[i].element;
1582 int action = element_to_sound[i].action;
1583 int sound = element_to_sound[i].sound;
1584 boolean is_class = element_to_sound[i].is_class;
1587 action = ACTION_DEFAULT;
1590 element_info[element].sound[action] = sound;
1592 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1593 if (strEqual(element_info[j].class_name,
1594 element_info[element].class_name))
1595 element_info[j].sound[action] = sound;
1598 /* initialize element class/sound mapping from dynamic configuration */
1599 for (i = 0; i < num_property_mappings; i++)
1601 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1602 int action = property_mapping[i].ext1_index;
1603 int sound = property_mapping[i].artwork_index;
1605 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1609 action = ACTION_DEFAULT;
1611 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1612 if (strEqual(element_info[j].class_name,
1613 element_info[element_class].class_name))
1614 element_info[j].sound[action] = sound;
1617 /* initialize element/sound mapping from dynamic configuration */
1618 for (i = 0; i < num_property_mappings; i++)
1620 int element = property_mapping[i].base_index;
1621 int action = property_mapping[i].ext1_index;
1622 int sound = property_mapping[i].artwork_index;
1624 if (element >= MAX_NUM_ELEMENTS)
1628 action = ACTION_DEFAULT;
1630 element_info[element].sound[action] = sound;
1633 /* now set all '-1' values to element specific default values */
1634 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1636 for (act = 0; act < NUM_ACTIONS; act++)
1638 /* generic default action sound (defined by "[default]" directive) */
1639 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1641 /* look for special default action sound (classic game specific) */
1642 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1643 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1644 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1645 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1646 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1647 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1649 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1650 /* !!! make this better !!! */
1651 if (i == EL_EMPTY_SPACE)
1652 default_action_sound = element_info[EL_DEFAULT].sound[act];
1654 /* no sound for this specific action -- use default action sound */
1655 if (element_info[i].sound[act] == -1)
1656 element_info[i].sound[act] = default_action_sound;
1660 /* copy sound settings to some elements that are only stored in level file
1661 in native R'n'D levels, but are used by game engine in native EM levels */
1662 for (i = 0; copy_properties[i][0] != -1; i++)
1663 for (j = 1; j <= 4; j++)
1664 for (act = 0; act < NUM_ACTIONS; act++)
1665 element_info[copy_properties[i][j]].sound[act] =
1666 element_info[copy_properties[i][0]].sound[act];
1669 static void InitGameModeSoundInfo()
1673 /* set values to -1 to identify later as "uninitialized" values */
1674 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1677 /* initialize gamemode/sound mapping from static configuration */
1678 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1680 int gamemode = gamemode_to_sound[i].gamemode;
1681 int sound = gamemode_to_sound[i].sound;
1684 gamemode = GAME_MODE_DEFAULT;
1686 menu.sound[gamemode] = sound;
1689 /* now set all '-1' values to levelset specific default values */
1690 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1691 if (menu.sound[i] == -1)
1692 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1695 static void set_sound_parameters(int sound, char **parameter_raw)
1697 int parameter[NUM_SND_ARGS];
1700 /* get integer values from string parameters */
1701 for (i = 0; i < NUM_SND_ARGS; i++)
1703 get_parameter_value(parameter_raw[i],
1704 sound_config_suffix[i].token,
1705 sound_config_suffix[i].type);
1707 /* explicit loop mode setting in configuration overrides default value */
1708 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1709 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1711 /* sound volume to change the original volume when loading the sound file */
1712 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1714 /* sound priority to give certain sounds a higher or lower priority */
1715 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
1718 static void InitSoundInfo()
1720 int *sound_effect_properties;
1721 int num_sounds = getSoundListSize();
1724 checked_free(sound_info);
1726 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1727 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1729 /* initialize sound effect for all elements to "no sound" */
1730 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1731 for (j = 0; j < NUM_ACTIONS; j++)
1732 element_info[i].sound[j] = SND_UNDEFINED;
1734 for (i = 0; i < num_sounds; i++)
1736 struct FileInfo *sound = getSoundListEntry(i);
1737 int len_effect_text = strlen(sound->token);
1739 sound_effect_properties[i] = ACTION_OTHER;
1740 sound_info[i].loop = FALSE; /* default: play sound only once */
1742 /* determine all loop sounds and identify certain sound classes */
1744 for (j = 0; element_action_info[j].suffix; j++)
1746 int len_action_text = strlen(element_action_info[j].suffix);
1748 if (len_action_text < len_effect_text &&
1749 strEqual(&sound->token[len_effect_text - len_action_text],
1750 element_action_info[j].suffix))
1752 sound_effect_properties[i] = element_action_info[j].value;
1753 sound_info[i].loop = element_action_info[j].is_loop_sound;
1759 /* associate elements and some selected sound actions */
1761 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1763 if (element_info[j].class_name)
1765 int len_class_text = strlen(element_info[j].class_name);
1767 if (len_class_text + 1 < len_effect_text &&
1768 strncmp(sound->token,
1769 element_info[j].class_name, len_class_text) == 0 &&
1770 sound->token[len_class_text] == '.')
1772 int sound_action_value = sound_effect_properties[i];
1774 element_info[j].sound[sound_action_value] = i;
1779 set_sound_parameters(i, sound->parameter);
1782 free(sound_effect_properties);
1785 static void InitGameModeMusicInfo()
1787 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1788 int num_property_mappings = getMusicListPropertyMappingSize();
1789 int default_levelset_music = -1;
1792 /* set values to -1 to identify later as "uninitialized" values */
1793 for (i = 0; i < MAX_LEVELS; i++)
1794 levelset.music[i] = -1;
1795 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1798 /* initialize gamemode/music mapping from static configuration */
1799 for (i = 0; gamemode_to_music[i].music > -1; i++)
1801 int gamemode = gamemode_to_music[i].gamemode;
1802 int music = gamemode_to_music[i].music;
1805 gamemode = GAME_MODE_DEFAULT;
1807 menu.music[gamemode] = music;
1810 /* initialize gamemode/music mapping from dynamic configuration */
1811 for (i = 0; i < num_property_mappings; i++)
1813 int prefix = property_mapping[i].base_index;
1814 int gamemode = property_mapping[i].ext1_index;
1815 int level = property_mapping[i].ext2_index;
1816 int music = property_mapping[i].artwork_index;
1818 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1822 gamemode = GAME_MODE_DEFAULT;
1824 /* level specific music only allowed for in-game music */
1825 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1826 gamemode = GAME_MODE_PLAYING;
1831 default_levelset_music = music;
1834 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1835 levelset.music[level] = music;
1836 if (gamemode != GAME_MODE_PLAYING)
1837 menu.music[gamemode] = music;
1840 /* now set all '-1' values to menu specific default values */
1841 /* (undefined values of "levelset.music[]" might stay at "-1" to
1842 allow dynamic selection of music files from music directory!) */
1843 for (i = 0; i < MAX_LEVELS; i++)
1844 if (levelset.music[i] == -1)
1845 levelset.music[i] = default_levelset_music;
1846 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1847 if (menu.music[i] == -1)
1848 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1851 static void set_music_parameters(int music, char **parameter_raw)
1853 int parameter[NUM_MUS_ARGS];
1856 /* get integer values from string parameters */
1857 for (i = 0; i < NUM_MUS_ARGS; i++)
1859 get_parameter_value(parameter_raw[i],
1860 music_config_suffix[i].token,
1861 music_config_suffix[i].type);
1863 /* explicit loop mode setting in configuration overrides default value */
1864 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1865 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1868 static void InitMusicInfo()
1870 int num_music = getMusicListSize();
1873 checked_free(music_info);
1875 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1877 for (i = 0; i < num_music; i++)
1879 struct FileInfo *music = getMusicListEntry(i);
1880 int len_music_text = strlen(music->token);
1882 music_info[i].loop = TRUE; /* default: play music in loop mode */
1884 /* determine all loop music */
1886 for (j = 0; music_prefix_info[j].prefix; j++)
1888 int len_prefix_text = strlen(music_prefix_info[j].prefix);
1890 if (len_prefix_text < len_music_text &&
1891 strncmp(music->token,
1892 music_prefix_info[j].prefix, len_prefix_text) == 0)
1894 music_info[i].loop = music_prefix_info[j].is_loop_music;
1900 set_music_parameters(i, music->parameter);
1904 static void ReinitializeGraphics()
1906 print_timestamp_init("ReinitializeGraphics");
1908 InitGfxTileSizeInfo(game.tile_size, TILESIZE);
1910 InitGraphicInfo(); /* graphic properties mapping */
1911 print_timestamp_time("InitGraphicInfo");
1912 InitElementGraphicInfo(); /* element game graphic mapping */
1913 print_timestamp_time("InitElementGraphicInfo");
1914 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
1915 print_timestamp_time("InitElementSpecialGraphicInfo");
1917 InitElementSmallImages(); /* scale elements to all needed sizes */
1918 print_timestamp_time("InitElementSmallImages");
1919 InitScaledImages(); /* scale all other images, if needed */
1920 print_timestamp_time("InitScaledImages");
1921 InitFontGraphicInfo(); /* initialize text drawing functions */
1922 print_timestamp_time("InitFontGraphicInfo");
1924 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
1925 print_timestamp_time("InitGraphicInfo_EM");
1927 InitGraphicCompatibilityInfo();
1928 print_timestamp_time("InitGraphicCompatibilityInfo");
1930 SetMainBackgroundImage(IMG_BACKGROUND);
1931 print_timestamp_time("SetMainBackgroundImage");
1932 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1933 print_timestamp_time("SetDoorBackgroundImage");
1936 print_timestamp_time("InitGadgets");
1938 print_timestamp_time("InitToons");
1940 print_timestamp_time("InitDoors");
1942 print_timestamp_done("ReinitializeGraphics");
1945 static void ReinitializeSounds()
1947 InitSoundInfo(); /* sound properties mapping */
1948 InitElementSoundInfo(); /* element game sound mapping */
1949 InitGameModeSoundInfo(); /* game mode sound mapping */
1951 InitPlayLevelSound(); /* internal game sound settings */
1954 static void ReinitializeMusic()
1956 InitMusicInfo(); /* music properties mapping */
1957 InitGameModeMusicInfo(); /* game mode music mapping */
1960 static int get_special_property_bit(int element, int property_bit_nr)
1962 struct PropertyBitInfo
1968 static struct PropertyBitInfo pb_can_move_into_acid[] =
1970 /* the player may be able fall into acid when gravity is activated */
1975 { EL_SP_MURPHY, 0 },
1976 { EL_SOKOBAN_FIELD_PLAYER, 0 },
1978 /* all elements that can move may be able to also move into acid */
1981 { EL_BUG_RIGHT, 1 },
1984 { EL_SPACESHIP, 2 },
1985 { EL_SPACESHIP_LEFT, 2 },
1986 { EL_SPACESHIP_RIGHT, 2 },
1987 { EL_SPACESHIP_UP, 2 },
1988 { EL_SPACESHIP_DOWN, 2 },
1989 { EL_BD_BUTTERFLY, 3 },
1990 { EL_BD_BUTTERFLY_LEFT, 3 },
1991 { EL_BD_BUTTERFLY_RIGHT, 3 },
1992 { EL_BD_BUTTERFLY_UP, 3 },
1993 { EL_BD_BUTTERFLY_DOWN, 3 },
1994 { EL_BD_FIREFLY, 4 },
1995 { EL_BD_FIREFLY_LEFT, 4 },
1996 { EL_BD_FIREFLY_RIGHT, 4 },
1997 { EL_BD_FIREFLY_UP, 4 },
1998 { EL_BD_FIREFLY_DOWN, 4 },
2000 { EL_YAMYAM_LEFT, 5 },
2001 { EL_YAMYAM_RIGHT, 5 },
2002 { EL_YAMYAM_UP, 5 },
2003 { EL_YAMYAM_DOWN, 5 },
2004 { EL_DARK_YAMYAM, 6 },
2007 { EL_PACMAN_LEFT, 8 },
2008 { EL_PACMAN_RIGHT, 8 },
2009 { EL_PACMAN_UP, 8 },
2010 { EL_PACMAN_DOWN, 8 },
2012 { EL_MOLE_LEFT, 9 },
2013 { EL_MOLE_RIGHT, 9 },
2015 { EL_MOLE_DOWN, 9 },
2019 { EL_SATELLITE, 13 },
2020 { EL_SP_SNIKSNAK, 14 },
2021 { EL_SP_ELECTRON, 15 },
2024 { EL_EMC_ANDROID, 18 },
2029 static struct PropertyBitInfo pb_dont_collide_with[] =
2031 { EL_SP_SNIKSNAK, 0 },
2032 { EL_SP_ELECTRON, 1 },
2040 struct PropertyBitInfo *pb_info;
2043 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2044 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2049 struct PropertyBitInfo *pb_info = NULL;
2052 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2053 if (pb_definition[i].bit_nr == property_bit_nr)
2054 pb_info = pb_definition[i].pb_info;
2056 if (pb_info == NULL)
2059 for (i = 0; pb_info[i].element != -1; i++)
2060 if (pb_info[i].element == element)
2061 return pb_info[i].bit_nr;
2066 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2067 boolean property_value)
2069 int bit_nr = get_special_property_bit(element, property_bit_nr);
2074 *bitfield |= (1 << bit_nr);
2076 *bitfield &= ~(1 << bit_nr);
2080 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2082 int bit_nr = get_special_property_bit(element, property_bit_nr);
2085 return ((*bitfield & (1 << bit_nr)) != 0);
2090 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2092 static int group_nr;
2093 static struct ElementGroupInfo *group;
2094 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2097 if (actual_group == NULL) /* not yet initialized */
2100 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
2102 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2103 group_element - EL_GROUP_START + 1);
2105 /* replace element which caused too deep recursion by question mark */
2106 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2111 if (recursion_depth == 0) /* initialization */
2113 group = actual_group;
2114 group_nr = GROUP_NR(group_element);
2116 group->num_elements_resolved = 0;
2117 group->choice_pos = 0;
2119 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2120 element_info[i].in_group[group_nr] = FALSE;
2123 for (i = 0; i < actual_group->num_elements; i++)
2125 int element = actual_group->element[i];
2127 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2130 if (IS_GROUP_ELEMENT(element))
2131 ResolveGroupElementExt(element, recursion_depth + 1);
2134 group->element_resolved[group->num_elements_resolved++] = element;
2135 element_info[element].in_group[group_nr] = TRUE;
2140 void ResolveGroupElement(int group_element)
2142 ResolveGroupElementExt(group_element, 0);
2145 void InitElementPropertiesStatic()
2147 static boolean clipboard_elements_initialized = FALSE;
2149 static int ep_diggable[] =
2154 EL_SP_BUGGY_BASE_ACTIVATING,
2157 EL_INVISIBLE_SAND_ACTIVE,
2160 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2161 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2166 EL_SP_BUGGY_BASE_ACTIVE,
2173 static int ep_collectible_only[] =
2195 EL_DYNABOMB_INCREASE_NUMBER,
2196 EL_DYNABOMB_INCREASE_SIZE,
2197 EL_DYNABOMB_INCREASE_POWER,
2215 /* !!! handle separately !!! */
2216 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2222 static int ep_dont_run_into[] =
2224 /* same elements as in 'ep_dont_touch' */
2230 /* same elements as in 'ep_dont_collide_with' */
2242 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2247 EL_SP_BUGGY_BASE_ACTIVE,
2254 static int ep_dont_collide_with[] =
2256 /* same elements as in 'ep_dont_touch' */
2273 static int ep_dont_touch[] =
2283 static int ep_indestructible[] =
2287 EL_ACID_POOL_TOPLEFT,
2288 EL_ACID_POOL_TOPRIGHT,
2289 EL_ACID_POOL_BOTTOMLEFT,
2290 EL_ACID_POOL_BOTTOM,
2291 EL_ACID_POOL_BOTTOMRIGHT,
2292 EL_SP_HARDWARE_GRAY,
2293 EL_SP_HARDWARE_GREEN,
2294 EL_SP_HARDWARE_BLUE,
2296 EL_SP_HARDWARE_YELLOW,
2297 EL_SP_HARDWARE_BASE_1,
2298 EL_SP_HARDWARE_BASE_2,
2299 EL_SP_HARDWARE_BASE_3,
2300 EL_SP_HARDWARE_BASE_4,
2301 EL_SP_HARDWARE_BASE_5,
2302 EL_SP_HARDWARE_BASE_6,
2303 EL_INVISIBLE_STEELWALL,
2304 EL_INVISIBLE_STEELWALL_ACTIVE,
2305 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2306 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2307 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2308 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2309 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2310 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2311 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2312 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2313 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2314 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2315 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2316 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2318 EL_LIGHT_SWITCH_ACTIVE,
2319 EL_SIGN_EXCLAMATION,
2320 EL_SIGN_RADIOACTIVITY,
2327 EL_SIGN_ENTRY_FORBIDDEN,
2328 EL_SIGN_EMERGENCY_EXIT,
2336 EL_STEEL_EXIT_CLOSED,
2338 EL_STEEL_EXIT_OPENING,
2339 EL_STEEL_EXIT_CLOSING,
2340 EL_EM_STEEL_EXIT_CLOSED,
2341 EL_EM_STEEL_EXIT_OPEN,
2342 EL_EM_STEEL_EXIT_OPENING,
2343 EL_EM_STEEL_EXIT_CLOSING,
2344 EL_DC_STEELWALL_1_LEFT,
2345 EL_DC_STEELWALL_1_RIGHT,
2346 EL_DC_STEELWALL_1_TOP,
2347 EL_DC_STEELWALL_1_BOTTOM,
2348 EL_DC_STEELWALL_1_HORIZONTAL,
2349 EL_DC_STEELWALL_1_VERTICAL,
2350 EL_DC_STEELWALL_1_TOPLEFT,
2351 EL_DC_STEELWALL_1_TOPRIGHT,
2352 EL_DC_STEELWALL_1_BOTTOMLEFT,
2353 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2354 EL_DC_STEELWALL_1_TOPLEFT_2,
2355 EL_DC_STEELWALL_1_TOPRIGHT_2,
2356 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2357 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2358 EL_DC_STEELWALL_2_LEFT,
2359 EL_DC_STEELWALL_2_RIGHT,
2360 EL_DC_STEELWALL_2_TOP,
2361 EL_DC_STEELWALL_2_BOTTOM,
2362 EL_DC_STEELWALL_2_HORIZONTAL,
2363 EL_DC_STEELWALL_2_VERTICAL,
2364 EL_DC_STEELWALL_2_MIDDLE,
2365 EL_DC_STEELWALL_2_SINGLE,
2366 EL_STEELWALL_SLIPPERY,
2380 EL_GATE_1_GRAY_ACTIVE,
2381 EL_GATE_2_GRAY_ACTIVE,
2382 EL_GATE_3_GRAY_ACTIVE,
2383 EL_GATE_4_GRAY_ACTIVE,
2392 EL_EM_GATE_1_GRAY_ACTIVE,
2393 EL_EM_GATE_2_GRAY_ACTIVE,
2394 EL_EM_GATE_3_GRAY_ACTIVE,
2395 EL_EM_GATE_4_GRAY_ACTIVE,
2404 EL_EMC_GATE_5_GRAY_ACTIVE,
2405 EL_EMC_GATE_6_GRAY_ACTIVE,
2406 EL_EMC_GATE_7_GRAY_ACTIVE,
2407 EL_EMC_GATE_8_GRAY_ACTIVE,
2409 EL_DC_GATE_WHITE_GRAY,
2410 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2411 EL_DC_GATE_FAKE_GRAY,
2413 EL_SWITCHGATE_OPENING,
2414 EL_SWITCHGATE_CLOSED,
2415 EL_SWITCHGATE_CLOSING,
2416 EL_DC_SWITCHGATE_SWITCH_UP,
2417 EL_DC_SWITCHGATE_SWITCH_DOWN,
2419 EL_TIMEGATE_OPENING,
2421 EL_TIMEGATE_CLOSING,
2422 EL_DC_TIMEGATE_SWITCH,
2423 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2427 EL_TUBE_VERTICAL_LEFT,
2428 EL_TUBE_VERTICAL_RIGHT,
2429 EL_TUBE_HORIZONTAL_UP,
2430 EL_TUBE_HORIZONTAL_DOWN,
2435 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2436 EL_EXPANDABLE_STEELWALL_VERTICAL,
2437 EL_EXPANDABLE_STEELWALL_ANY,
2442 static int ep_slippery[] =
2456 EL_ROBOT_WHEEL_ACTIVE,
2462 EL_ACID_POOL_TOPLEFT,
2463 EL_ACID_POOL_TOPRIGHT,
2473 EL_STEELWALL_SLIPPERY,
2476 EL_EMC_WALL_SLIPPERY_1,
2477 EL_EMC_WALL_SLIPPERY_2,
2478 EL_EMC_WALL_SLIPPERY_3,
2479 EL_EMC_WALL_SLIPPERY_4,
2481 EL_EMC_MAGIC_BALL_ACTIVE,
2486 static int ep_can_change[] =
2491 static int ep_can_move[] =
2493 /* same elements as in 'pb_can_move_into_acid' */
2516 static int ep_can_fall[] =
2530 EL_QUICKSAND_FAST_FULL,
2532 EL_BD_MAGIC_WALL_FULL,
2533 EL_DC_MAGIC_WALL_FULL,
2547 static int ep_can_smash_player[] =
2573 static int ep_can_smash_enemies[] =
2582 static int ep_can_smash_everything[] =
2591 static int ep_explodes_by_fire[] =
2593 /* same elements as in 'ep_explodes_impact' */
2598 /* same elements as in 'ep_explodes_smashed' */
2608 EL_EM_DYNAMITE_ACTIVE,
2609 EL_DYNABOMB_PLAYER_1_ACTIVE,
2610 EL_DYNABOMB_PLAYER_2_ACTIVE,
2611 EL_DYNABOMB_PLAYER_3_ACTIVE,
2612 EL_DYNABOMB_PLAYER_4_ACTIVE,
2613 EL_DYNABOMB_INCREASE_NUMBER,
2614 EL_DYNABOMB_INCREASE_SIZE,
2615 EL_DYNABOMB_INCREASE_POWER,
2616 EL_SP_DISK_RED_ACTIVE,
2630 static int ep_explodes_smashed[] =
2632 /* same elements as in 'ep_explodes_impact' */
2646 static int ep_explodes_impact[] =
2655 static int ep_walkable_over[] =
2659 EL_SOKOBAN_FIELD_EMPTY,
2666 EL_EM_STEEL_EXIT_OPEN,
2667 EL_EM_STEEL_EXIT_OPENING,
2676 EL_GATE_1_GRAY_ACTIVE,
2677 EL_GATE_2_GRAY_ACTIVE,
2678 EL_GATE_3_GRAY_ACTIVE,
2679 EL_GATE_4_GRAY_ACTIVE,
2687 static int ep_walkable_inside[] =
2692 EL_TUBE_VERTICAL_LEFT,
2693 EL_TUBE_VERTICAL_RIGHT,
2694 EL_TUBE_HORIZONTAL_UP,
2695 EL_TUBE_HORIZONTAL_DOWN,
2704 static int ep_walkable_under[] =
2709 static int ep_passable_over[] =
2719 EL_EM_GATE_1_GRAY_ACTIVE,
2720 EL_EM_GATE_2_GRAY_ACTIVE,
2721 EL_EM_GATE_3_GRAY_ACTIVE,
2722 EL_EM_GATE_4_GRAY_ACTIVE,
2731 EL_EMC_GATE_5_GRAY_ACTIVE,
2732 EL_EMC_GATE_6_GRAY_ACTIVE,
2733 EL_EMC_GATE_7_GRAY_ACTIVE,
2734 EL_EMC_GATE_8_GRAY_ACTIVE,
2736 EL_DC_GATE_WHITE_GRAY,
2737 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2744 static int ep_passable_inside[] =
2750 EL_SP_PORT_HORIZONTAL,
2751 EL_SP_PORT_VERTICAL,
2753 EL_SP_GRAVITY_PORT_LEFT,
2754 EL_SP_GRAVITY_PORT_RIGHT,
2755 EL_SP_GRAVITY_PORT_UP,
2756 EL_SP_GRAVITY_PORT_DOWN,
2757 EL_SP_GRAVITY_ON_PORT_LEFT,
2758 EL_SP_GRAVITY_ON_PORT_RIGHT,
2759 EL_SP_GRAVITY_ON_PORT_UP,
2760 EL_SP_GRAVITY_ON_PORT_DOWN,
2761 EL_SP_GRAVITY_OFF_PORT_LEFT,
2762 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2763 EL_SP_GRAVITY_OFF_PORT_UP,
2764 EL_SP_GRAVITY_OFF_PORT_DOWN,
2769 static int ep_passable_under[] =
2774 static int ep_droppable[] =
2779 static int ep_explodes_1x1_old[] =
2784 static int ep_pushable[] =
2796 EL_SOKOBAN_FIELD_FULL,
2805 static int ep_explodes_cross_old[] =
2810 static int ep_protected[] =
2812 /* same elements as in 'ep_walkable_inside' */
2816 EL_TUBE_VERTICAL_LEFT,
2817 EL_TUBE_VERTICAL_RIGHT,
2818 EL_TUBE_HORIZONTAL_UP,
2819 EL_TUBE_HORIZONTAL_DOWN,
2825 /* same elements as in 'ep_passable_over' */
2834 EL_EM_GATE_1_GRAY_ACTIVE,
2835 EL_EM_GATE_2_GRAY_ACTIVE,
2836 EL_EM_GATE_3_GRAY_ACTIVE,
2837 EL_EM_GATE_4_GRAY_ACTIVE,
2846 EL_EMC_GATE_5_GRAY_ACTIVE,
2847 EL_EMC_GATE_6_GRAY_ACTIVE,
2848 EL_EMC_GATE_7_GRAY_ACTIVE,
2849 EL_EMC_GATE_8_GRAY_ACTIVE,
2851 EL_DC_GATE_WHITE_GRAY,
2852 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2856 /* same elements as in 'ep_passable_inside' */
2861 EL_SP_PORT_HORIZONTAL,
2862 EL_SP_PORT_VERTICAL,
2864 EL_SP_GRAVITY_PORT_LEFT,
2865 EL_SP_GRAVITY_PORT_RIGHT,
2866 EL_SP_GRAVITY_PORT_UP,
2867 EL_SP_GRAVITY_PORT_DOWN,
2868 EL_SP_GRAVITY_ON_PORT_LEFT,
2869 EL_SP_GRAVITY_ON_PORT_RIGHT,
2870 EL_SP_GRAVITY_ON_PORT_UP,
2871 EL_SP_GRAVITY_ON_PORT_DOWN,
2872 EL_SP_GRAVITY_OFF_PORT_LEFT,
2873 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2874 EL_SP_GRAVITY_OFF_PORT_UP,
2875 EL_SP_GRAVITY_OFF_PORT_DOWN,
2880 static int ep_throwable[] =
2885 static int ep_can_explode[] =
2887 /* same elements as in 'ep_explodes_impact' */
2892 /* same elements as in 'ep_explodes_smashed' */
2898 /* elements that can explode by explosion or by dragonfire */
2902 EL_EM_DYNAMITE_ACTIVE,
2903 EL_DYNABOMB_PLAYER_1_ACTIVE,
2904 EL_DYNABOMB_PLAYER_2_ACTIVE,
2905 EL_DYNABOMB_PLAYER_3_ACTIVE,
2906 EL_DYNABOMB_PLAYER_4_ACTIVE,
2907 EL_DYNABOMB_INCREASE_NUMBER,
2908 EL_DYNABOMB_INCREASE_SIZE,
2909 EL_DYNABOMB_INCREASE_POWER,
2910 EL_SP_DISK_RED_ACTIVE,
2918 /* elements that can explode only by explosion */
2924 static int ep_gravity_reachable[] =
2930 EL_INVISIBLE_SAND_ACTIVE,
2935 EL_SP_PORT_HORIZONTAL,
2936 EL_SP_PORT_VERTICAL,
2938 EL_SP_GRAVITY_PORT_LEFT,
2939 EL_SP_GRAVITY_PORT_RIGHT,
2940 EL_SP_GRAVITY_PORT_UP,
2941 EL_SP_GRAVITY_PORT_DOWN,
2942 EL_SP_GRAVITY_ON_PORT_LEFT,
2943 EL_SP_GRAVITY_ON_PORT_RIGHT,
2944 EL_SP_GRAVITY_ON_PORT_UP,
2945 EL_SP_GRAVITY_ON_PORT_DOWN,
2946 EL_SP_GRAVITY_OFF_PORT_LEFT,
2947 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2948 EL_SP_GRAVITY_OFF_PORT_UP,
2949 EL_SP_GRAVITY_OFF_PORT_DOWN,
2955 static int ep_player[] =
2962 EL_SOKOBAN_FIELD_PLAYER,
2968 static int ep_can_pass_magic_wall[] =
2982 static int ep_can_pass_dc_magic_wall[] =
2998 static int ep_switchable[] =
3002 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3003 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3004 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3005 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3006 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3007 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3008 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3009 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3010 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3011 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3012 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3013 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3014 EL_SWITCHGATE_SWITCH_UP,
3015 EL_SWITCHGATE_SWITCH_DOWN,
3016 EL_DC_SWITCHGATE_SWITCH_UP,
3017 EL_DC_SWITCHGATE_SWITCH_DOWN,
3019 EL_LIGHT_SWITCH_ACTIVE,
3021 EL_DC_TIMEGATE_SWITCH,
3022 EL_BALLOON_SWITCH_LEFT,
3023 EL_BALLOON_SWITCH_RIGHT,
3024 EL_BALLOON_SWITCH_UP,
3025 EL_BALLOON_SWITCH_DOWN,
3026 EL_BALLOON_SWITCH_ANY,
3027 EL_BALLOON_SWITCH_NONE,
3030 EL_EMC_MAGIC_BALL_SWITCH,
3031 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3036 static int ep_bd_element[] =
3070 static int ep_sp_element[] =
3072 /* should always be valid */
3075 /* standard classic Supaplex elements */
3082 EL_SP_HARDWARE_GRAY,
3090 EL_SP_GRAVITY_PORT_RIGHT,
3091 EL_SP_GRAVITY_PORT_DOWN,
3092 EL_SP_GRAVITY_PORT_LEFT,
3093 EL_SP_GRAVITY_PORT_UP,
3098 EL_SP_PORT_VERTICAL,
3099 EL_SP_PORT_HORIZONTAL,
3105 EL_SP_HARDWARE_BASE_1,
3106 EL_SP_HARDWARE_GREEN,
3107 EL_SP_HARDWARE_BLUE,
3109 EL_SP_HARDWARE_YELLOW,
3110 EL_SP_HARDWARE_BASE_2,
3111 EL_SP_HARDWARE_BASE_3,
3112 EL_SP_HARDWARE_BASE_4,
3113 EL_SP_HARDWARE_BASE_5,
3114 EL_SP_HARDWARE_BASE_6,
3118 /* additional elements that appeared in newer Supaplex levels */
3121 /* additional gravity port elements (not switching, but setting gravity) */
3122 EL_SP_GRAVITY_ON_PORT_LEFT,
3123 EL_SP_GRAVITY_ON_PORT_RIGHT,
3124 EL_SP_GRAVITY_ON_PORT_UP,
3125 EL_SP_GRAVITY_ON_PORT_DOWN,
3126 EL_SP_GRAVITY_OFF_PORT_LEFT,
3127 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3128 EL_SP_GRAVITY_OFF_PORT_UP,
3129 EL_SP_GRAVITY_OFF_PORT_DOWN,
3131 /* more than one Murphy in a level results in an inactive clone */
3134 /* runtime Supaplex elements */
3135 EL_SP_DISK_RED_ACTIVE,
3136 EL_SP_TERMINAL_ACTIVE,
3137 EL_SP_BUGGY_BASE_ACTIVATING,
3138 EL_SP_BUGGY_BASE_ACTIVE,
3145 static int ep_sb_element[] =
3150 EL_SOKOBAN_FIELD_EMPTY,
3151 EL_SOKOBAN_FIELD_FULL,
3152 EL_SOKOBAN_FIELD_PLAYER,
3157 EL_INVISIBLE_STEELWALL,
3162 static int ep_gem[] =
3174 static int ep_food_dark_yamyam[] =
3202 static int ep_food_penguin[] =
3216 static int ep_food_pig[] =
3228 static int ep_historic_wall[] =
3239 EL_GATE_1_GRAY_ACTIVE,
3240 EL_GATE_2_GRAY_ACTIVE,
3241 EL_GATE_3_GRAY_ACTIVE,
3242 EL_GATE_4_GRAY_ACTIVE,
3251 EL_EM_GATE_1_GRAY_ACTIVE,
3252 EL_EM_GATE_2_GRAY_ACTIVE,
3253 EL_EM_GATE_3_GRAY_ACTIVE,
3254 EL_EM_GATE_4_GRAY_ACTIVE,
3261 EL_EXPANDABLE_WALL_HORIZONTAL,
3262 EL_EXPANDABLE_WALL_VERTICAL,
3263 EL_EXPANDABLE_WALL_ANY,
3264 EL_EXPANDABLE_WALL_GROWING,
3265 EL_BD_EXPANDABLE_WALL,
3272 EL_SP_HARDWARE_GRAY,
3273 EL_SP_HARDWARE_GREEN,
3274 EL_SP_HARDWARE_BLUE,
3276 EL_SP_HARDWARE_YELLOW,
3277 EL_SP_HARDWARE_BASE_1,
3278 EL_SP_HARDWARE_BASE_2,
3279 EL_SP_HARDWARE_BASE_3,
3280 EL_SP_HARDWARE_BASE_4,
3281 EL_SP_HARDWARE_BASE_5,
3282 EL_SP_HARDWARE_BASE_6,
3284 EL_SP_TERMINAL_ACTIVE,
3287 EL_INVISIBLE_STEELWALL,
3288 EL_INVISIBLE_STEELWALL_ACTIVE,
3290 EL_INVISIBLE_WALL_ACTIVE,
3291 EL_STEELWALL_SLIPPERY,
3308 static int ep_historic_solid[] =
3312 EL_EXPANDABLE_WALL_HORIZONTAL,
3313 EL_EXPANDABLE_WALL_VERTICAL,
3314 EL_EXPANDABLE_WALL_ANY,
3315 EL_BD_EXPANDABLE_WALL,
3328 EL_QUICKSAND_FILLING,
3329 EL_QUICKSAND_EMPTYING,
3331 EL_MAGIC_WALL_ACTIVE,
3332 EL_MAGIC_WALL_EMPTYING,
3333 EL_MAGIC_WALL_FILLING,
3337 EL_BD_MAGIC_WALL_ACTIVE,
3338 EL_BD_MAGIC_WALL_EMPTYING,
3339 EL_BD_MAGIC_WALL_FULL,
3340 EL_BD_MAGIC_WALL_FILLING,
3341 EL_BD_MAGIC_WALL_DEAD,
3350 EL_SP_TERMINAL_ACTIVE,
3354 EL_INVISIBLE_WALL_ACTIVE,
3355 EL_SWITCHGATE_SWITCH_UP,
3356 EL_SWITCHGATE_SWITCH_DOWN,
3357 EL_DC_SWITCHGATE_SWITCH_UP,
3358 EL_DC_SWITCHGATE_SWITCH_DOWN,
3360 EL_TIMEGATE_SWITCH_ACTIVE,
3361 EL_DC_TIMEGATE_SWITCH,
3362 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3374 /* the following elements are a direct copy of "indestructible" elements,
3375 except "EL_ACID", which is "indestructible", but not "solid"! */
3380 EL_ACID_POOL_TOPLEFT,
3381 EL_ACID_POOL_TOPRIGHT,
3382 EL_ACID_POOL_BOTTOMLEFT,
3383 EL_ACID_POOL_BOTTOM,
3384 EL_ACID_POOL_BOTTOMRIGHT,
3385 EL_SP_HARDWARE_GRAY,
3386 EL_SP_HARDWARE_GREEN,
3387 EL_SP_HARDWARE_BLUE,
3389 EL_SP_HARDWARE_YELLOW,
3390 EL_SP_HARDWARE_BASE_1,
3391 EL_SP_HARDWARE_BASE_2,
3392 EL_SP_HARDWARE_BASE_3,
3393 EL_SP_HARDWARE_BASE_4,
3394 EL_SP_HARDWARE_BASE_5,
3395 EL_SP_HARDWARE_BASE_6,
3396 EL_INVISIBLE_STEELWALL,
3397 EL_INVISIBLE_STEELWALL_ACTIVE,
3398 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3399 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3400 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3401 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3402 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3403 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3404 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3405 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3406 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3407 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3408 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3409 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3411 EL_LIGHT_SWITCH_ACTIVE,
3412 EL_SIGN_EXCLAMATION,
3413 EL_SIGN_RADIOACTIVITY,
3420 EL_SIGN_ENTRY_FORBIDDEN,
3421 EL_SIGN_EMERGENCY_EXIT,
3429 EL_STEEL_EXIT_CLOSED,
3431 EL_DC_STEELWALL_1_LEFT,
3432 EL_DC_STEELWALL_1_RIGHT,
3433 EL_DC_STEELWALL_1_TOP,
3434 EL_DC_STEELWALL_1_BOTTOM,
3435 EL_DC_STEELWALL_1_HORIZONTAL,
3436 EL_DC_STEELWALL_1_VERTICAL,
3437 EL_DC_STEELWALL_1_TOPLEFT,
3438 EL_DC_STEELWALL_1_TOPRIGHT,
3439 EL_DC_STEELWALL_1_BOTTOMLEFT,
3440 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3441 EL_DC_STEELWALL_1_TOPLEFT_2,
3442 EL_DC_STEELWALL_1_TOPRIGHT_2,
3443 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3444 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3445 EL_DC_STEELWALL_2_LEFT,
3446 EL_DC_STEELWALL_2_RIGHT,
3447 EL_DC_STEELWALL_2_TOP,
3448 EL_DC_STEELWALL_2_BOTTOM,
3449 EL_DC_STEELWALL_2_HORIZONTAL,
3450 EL_DC_STEELWALL_2_VERTICAL,
3451 EL_DC_STEELWALL_2_MIDDLE,
3452 EL_DC_STEELWALL_2_SINGLE,
3453 EL_STEELWALL_SLIPPERY,
3467 EL_GATE_1_GRAY_ACTIVE,
3468 EL_GATE_2_GRAY_ACTIVE,
3469 EL_GATE_3_GRAY_ACTIVE,
3470 EL_GATE_4_GRAY_ACTIVE,
3479 EL_EM_GATE_1_GRAY_ACTIVE,
3480 EL_EM_GATE_2_GRAY_ACTIVE,
3481 EL_EM_GATE_3_GRAY_ACTIVE,
3482 EL_EM_GATE_4_GRAY_ACTIVE,
3484 EL_SWITCHGATE_OPENING,
3485 EL_SWITCHGATE_CLOSED,
3486 EL_SWITCHGATE_CLOSING,
3488 EL_TIMEGATE_OPENING,
3490 EL_TIMEGATE_CLOSING,
3494 EL_TUBE_VERTICAL_LEFT,
3495 EL_TUBE_VERTICAL_RIGHT,
3496 EL_TUBE_HORIZONTAL_UP,
3497 EL_TUBE_HORIZONTAL_DOWN,
3506 static int ep_classic_enemy[] =
3523 static int ep_belt[] =
3525 EL_CONVEYOR_BELT_1_LEFT,
3526 EL_CONVEYOR_BELT_1_MIDDLE,
3527 EL_CONVEYOR_BELT_1_RIGHT,
3528 EL_CONVEYOR_BELT_2_LEFT,
3529 EL_CONVEYOR_BELT_2_MIDDLE,
3530 EL_CONVEYOR_BELT_2_RIGHT,
3531 EL_CONVEYOR_BELT_3_LEFT,
3532 EL_CONVEYOR_BELT_3_MIDDLE,
3533 EL_CONVEYOR_BELT_3_RIGHT,
3534 EL_CONVEYOR_BELT_4_LEFT,
3535 EL_CONVEYOR_BELT_4_MIDDLE,
3536 EL_CONVEYOR_BELT_4_RIGHT,
3541 static int ep_belt_active[] =
3543 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3544 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3545 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3546 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3547 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3548 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3549 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3550 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3551 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3552 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3553 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3554 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3559 static int ep_belt_switch[] =
3561 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3562 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3563 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3564 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3565 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3566 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3567 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3568 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3569 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3570 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3571 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3572 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3577 static int ep_tube[] =
3584 EL_TUBE_HORIZONTAL_UP,
3585 EL_TUBE_HORIZONTAL_DOWN,
3587 EL_TUBE_VERTICAL_LEFT,
3588 EL_TUBE_VERTICAL_RIGHT,
3594 static int ep_acid_pool[] =
3596 EL_ACID_POOL_TOPLEFT,
3597 EL_ACID_POOL_TOPRIGHT,
3598 EL_ACID_POOL_BOTTOMLEFT,
3599 EL_ACID_POOL_BOTTOM,
3600 EL_ACID_POOL_BOTTOMRIGHT,
3605 static int ep_keygate[] =
3615 EL_GATE_1_GRAY_ACTIVE,
3616 EL_GATE_2_GRAY_ACTIVE,
3617 EL_GATE_3_GRAY_ACTIVE,
3618 EL_GATE_4_GRAY_ACTIVE,
3627 EL_EM_GATE_1_GRAY_ACTIVE,
3628 EL_EM_GATE_2_GRAY_ACTIVE,
3629 EL_EM_GATE_3_GRAY_ACTIVE,
3630 EL_EM_GATE_4_GRAY_ACTIVE,
3639 EL_EMC_GATE_5_GRAY_ACTIVE,
3640 EL_EMC_GATE_6_GRAY_ACTIVE,
3641 EL_EMC_GATE_7_GRAY_ACTIVE,
3642 EL_EMC_GATE_8_GRAY_ACTIVE,
3644 EL_DC_GATE_WHITE_GRAY,
3645 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3650 static int ep_amoeboid[] =
3662 static int ep_amoebalive[] =
3673 static int ep_has_editor_content[] =
3679 EL_SOKOBAN_FIELD_PLAYER,
3696 static int ep_can_turn_each_move[] =
3698 /* !!! do something with this one !!! */
3702 static int ep_can_grow[] =
3716 static int ep_active_bomb[] =
3719 EL_EM_DYNAMITE_ACTIVE,
3720 EL_DYNABOMB_PLAYER_1_ACTIVE,
3721 EL_DYNABOMB_PLAYER_2_ACTIVE,
3722 EL_DYNABOMB_PLAYER_3_ACTIVE,
3723 EL_DYNABOMB_PLAYER_4_ACTIVE,
3724 EL_SP_DISK_RED_ACTIVE,
3729 static int ep_inactive[] =
3739 EL_QUICKSAND_FAST_EMPTY,
3762 EL_GATE_1_GRAY_ACTIVE,
3763 EL_GATE_2_GRAY_ACTIVE,
3764 EL_GATE_3_GRAY_ACTIVE,
3765 EL_GATE_4_GRAY_ACTIVE,
3774 EL_EM_GATE_1_GRAY_ACTIVE,
3775 EL_EM_GATE_2_GRAY_ACTIVE,
3776 EL_EM_GATE_3_GRAY_ACTIVE,
3777 EL_EM_GATE_4_GRAY_ACTIVE,
3786 EL_EMC_GATE_5_GRAY_ACTIVE,
3787 EL_EMC_GATE_6_GRAY_ACTIVE,
3788 EL_EMC_GATE_7_GRAY_ACTIVE,
3789 EL_EMC_GATE_8_GRAY_ACTIVE,
3791 EL_DC_GATE_WHITE_GRAY,
3792 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3793 EL_DC_GATE_FAKE_GRAY,
3796 EL_INVISIBLE_STEELWALL,
3804 EL_WALL_EMERALD_YELLOW,
3805 EL_DYNABOMB_INCREASE_NUMBER,
3806 EL_DYNABOMB_INCREASE_SIZE,
3807 EL_DYNABOMB_INCREASE_POWER,
3811 EL_SOKOBAN_FIELD_EMPTY,
3812 EL_SOKOBAN_FIELD_FULL,
3813 EL_WALL_EMERALD_RED,
3814 EL_WALL_EMERALD_PURPLE,
3815 EL_ACID_POOL_TOPLEFT,
3816 EL_ACID_POOL_TOPRIGHT,
3817 EL_ACID_POOL_BOTTOMLEFT,
3818 EL_ACID_POOL_BOTTOM,
3819 EL_ACID_POOL_BOTTOMRIGHT,
3823 EL_BD_MAGIC_WALL_DEAD,
3825 EL_DC_MAGIC_WALL_DEAD,
3826 EL_AMOEBA_TO_DIAMOND,
3834 EL_SP_GRAVITY_PORT_RIGHT,
3835 EL_SP_GRAVITY_PORT_DOWN,
3836 EL_SP_GRAVITY_PORT_LEFT,
3837 EL_SP_GRAVITY_PORT_UP,
3838 EL_SP_PORT_HORIZONTAL,
3839 EL_SP_PORT_VERTICAL,
3850 EL_SP_HARDWARE_GRAY,
3851 EL_SP_HARDWARE_GREEN,
3852 EL_SP_HARDWARE_BLUE,
3854 EL_SP_HARDWARE_YELLOW,
3855 EL_SP_HARDWARE_BASE_1,
3856 EL_SP_HARDWARE_BASE_2,
3857 EL_SP_HARDWARE_BASE_3,
3858 EL_SP_HARDWARE_BASE_4,
3859 EL_SP_HARDWARE_BASE_5,
3860 EL_SP_HARDWARE_BASE_6,
3861 EL_SP_GRAVITY_ON_PORT_LEFT,
3862 EL_SP_GRAVITY_ON_PORT_RIGHT,
3863 EL_SP_GRAVITY_ON_PORT_UP,
3864 EL_SP_GRAVITY_ON_PORT_DOWN,
3865 EL_SP_GRAVITY_OFF_PORT_LEFT,
3866 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3867 EL_SP_GRAVITY_OFF_PORT_UP,
3868 EL_SP_GRAVITY_OFF_PORT_DOWN,
3869 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3870 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3871 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3872 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3873 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3874 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3875 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3876 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3877 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3878 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3879 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3880 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3881 EL_SIGN_EXCLAMATION,
3882 EL_SIGN_RADIOACTIVITY,
3889 EL_SIGN_ENTRY_FORBIDDEN,
3890 EL_SIGN_EMERGENCY_EXIT,
3898 EL_DC_STEELWALL_1_LEFT,
3899 EL_DC_STEELWALL_1_RIGHT,
3900 EL_DC_STEELWALL_1_TOP,
3901 EL_DC_STEELWALL_1_BOTTOM,
3902 EL_DC_STEELWALL_1_HORIZONTAL,
3903 EL_DC_STEELWALL_1_VERTICAL,
3904 EL_DC_STEELWALL_1_TOPLEFT,
3905 EL_DC_STEELWALL_1_TOPRIGHT,
3906 EL_DC_STEELWALL_1_BOTTOMLEFT,
3907 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3908 EL_DC_STEELWALL_1_TOPLEFT_2,
3909 EL_DC_STEELWALL_1_TOPRIGHT_2,
3910 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3911 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3912 EL_DC_STEELWALL_2_LEFT,
3913 EL_DC_STEELWALL_2_RIGHT,
3914 EL_DC_STEELWALL_2_TOP,
3915 EL_DC_STEELWALL_2_BOTTOM,
3916 EL_DC_STEELWALL_2_HORIZONTAL,
3917 EL_DC_STEELWALL_2_VERTICAL,
3918 EL_DC_STEELWALL_2_MIDDLE,
3919 EL_DC_STEELWALL_2_SINGLE,
3920 EL_STEELWALL_SLIPPERY,
3925 EL_EMC_WALL_SLIPPERY_1,
3926 EL_EMC_WALL_SLIPPERY_2,
3927 EL_EMC_WALL_SLIPPERY_3,
3928 EL_EMC_WALL_SLIPPERY_4,
3949 static int ep_em_slippery_wall[] =
3954 static int ep_gfx_crumbled[] =
3965 static int ep_editor_cascade_active[] =
3967 EL_INTERNAL_CASCADE_BD_ACTIVE,
3968 EL_INTERNAL_CASCADE_EM_ACTIVE,
3969 EL_INTERNAL_CASCADE_EMC_ACTIVE,
3970 EL_INTERNAL_CASCADE_RND_ACTIVE,
3971 EL_INTERNAL_CASCADE_SB_ACTIVE,
3972 EL_INTERNAL_CASCADE_SP_ACTIVE,
3973 EL_INTERNAL_CASCADE_DC_ACTIVE,
3974 EL_INTERNAL_CASCADE_DX_ACTIVE,
3975 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
3976 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
3977 EL_INTERNAL_CASCADE_CE_ACTIVE,
3978 EL_INTERNAL_CASCADE_GE_ACTIVE,
3979 EL_INTERNAL_CASCADE_REF_ACTIVE,
3980 EL_INTERNAL_CASCADE_USER_ACTIVE,
3981 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
3986 static int ep_editor_cascade_inactive[] =
3988 EL_INTERNAL_CASCADE_BD,
3989 EL_INTERNAL_CASCADE_EM,
3990 EL_INTERNAL_CASCADE_EMC,
3991 EL_INTERNAL_CASCADE_RND,
3992 EL_INTERNAL_CASCADE_SB,
3993 EL_INTERNAL_CASCADE_SP,
3994 EL_INTERNAL_CASCADE_DC,
3995 EL_INTERNAL_CASCADE_DX,
3996 EL_INTERNAL_CASCADE_CHARS,
3997 EL_INTERNAL_CASCADE_STEEL_CHARS,
3998 EL_INTERNAL_CASCADE_CE,
3999 EL_INTERNAL_CASCADE_GE,
4000 EL_INTERNAL_CASCADE_REF,
4001 EL_INTERNAL_CASCADE_USER,
4002 EL_INTERNAL_CASCADE_DYNAMIC,
4007 static int ep_obsolete[] =
4011 EL_EM_KEY_1_FILE_OBSOLETE,
4012 EL_EM_KEY_2_FILE_OBSOLETE,
4013 EL_EM_KEY_3_FILE_OBSOLETE,
4014 EL_EM_KEY_4_FILE_OBSOLETE,
4015 EL_ENVELOPE_OBSOLETE,
4024 } element_properties[] =
4026 { ep_diggable, EP_DIGGABLE },
4027 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4028 { ep_dont_run_into, EP_DONT_RUN_INTO },
4029 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4030 { ep_dont_touch, EP_DONT_TOUCH },
4031 { ep_indestructible, EP_INDESTRUCTIBLE },
4032 { ep_slippery, EP_SLIPPERY },
4033 { ep_can_change, EP_CAN_CHANGE },
4034 { ep_can_move, EP_CAN_MOVE },
4035 { ep_can_fall, EP_CAN_FALL },
4036 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4037 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4038 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4039 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4040 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4041 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4042 { ep_walkable_over, EP_WALKABLE_OVER },
4043 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4044 { ep_walkable_under, EP_WALKABLE_UNDER },
4045 { ep_passable_over, EP_PASSABLE_OVER },
4046 { ep_passable_inside, EP_PASSABLE_INSIDE },
4047 { ep_passable_under, EP_PASSABLE_UNDER },
4048 { ep_droppable, EP_DROPPABLE },
4049 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4050 { ep_pushable, EP_PUSHABLE },
4051 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4052 { ep_protected, EP_PROTECTED },
4053 { ep_throwable, EP_THROWABLE },
4054 { ep_can_explode, EP_CAN_EXPLODE },
4055 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4057 { ep_player, EP_PLAYER },
4058 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4059 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4060 { ep_switchable, EP_SWITCHABLE },
4061 { ep_bd_element, EP_BD_ELEMENT },
4062 { ep_sp_element, EP_SP_ELEMENT },
4063 { ep_sb_element, EP_SB_ELEMENT },
4065 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4066 { ep_food_penguin, EP_FOOD_PENGUIN },
4067 { ep_food_pig, EP_FOOD_PIG },
4068 { ep_historic_wall, EP_HISTORIC_WALL },
4069 { ep_historic_solid, EP_HISTORIC_SOLID },
4070 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4071 { ep_belt, EP_BELT },
4072 { ep_belt_active, EP_BELT_ACTIVE },
4073 { ep_belt_switch, EP_BELT_SWITCH },
4074 { ep_tube, EP_TUBE },
4075 { ep_acid_pool, EP_ACID_POOL },
4076 { ep_keygate, EP_KEYGATE },
4077 { ep_amoeboid, EP_AMOEBOID },
4078 { ep_amoebalive, EP_AMOEBALIVE },
4079 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4080 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4081 { ep_can_grow, EP_CAN_GROW },
4082 { ep_active_bomb, EP_ACTIVE_BOMB },
4083 { ep_inactive, EP_INACTIVE },
4085 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4087 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4089 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4090 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4092 { ep_obsolete, EP_OBSOLETE },
4099 /* always start with reliable default values (element has no properties) */
4100 /* (but never initialize clipboard elements after the very first time) */
4101 /* (to be able to use clipboard elements between several levels) */
4102 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4103 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4104 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4105 SET_PROPERTY(i, j, FALSE);
4107 /* set all base element properties from above array definitions */
4108 for (i = 0; element_properties[i].elements != NULL; i++)
4109 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4110 SET_PROPERTY((element_properties[i].elements)[j],
4111 element_properties[i].property, TRUE);
4113 /* copy properties to some elements that are only stored in level file */
4114 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4115 for (j = 0; copy_properties[j][0] != -1; j++)
4116 if (HAS_PROPERTY(copy_properties[j][0], i))
4117 for (k = 1; k <= 4; k++)
4118 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4120 /* set static element properties that are not listed in array definitions */
4121 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4122 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4124 clipboard_elements_initialized = TRUE;
4127 void InitElementPropertiesEngine(int engine_version)
4129 static int no_wall_properties[] =
4132 EP_COLLECTIBLE_ONLY,
4134 EP_DONT_COLLIDE_WITH,
4137 EP_CAN_SMASH_PLAYER,
4138 EP_CAN_SMASH_ENEMIES,
4139 EP_CAN_SMASH_EVERYTHING,
4144 EP_FOOD_DARK_YAMYAM,
4160 /* important: after initialization in InitElementPropertiesStatic(), the
4161 elements are not again initialized to a default value; therefore all
4162 changes have to make sure that they leave the element with a defined
4163 property (which means that conditional property changes must be set to
4164 a reliable default value before) */
4166 /* resolve group elements */
4167 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4168 ResolveGroupElement(EL_GROUP_START + i);
4170 /* set all special, combined or engine dependent element properties */
4171 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4173 /* do not change (already initialized) clipboard elements here */
4174 if (IS_CLIPBOARD_ELEMENT(i))
4177 /* ---------- INACTIVE ------------------------------------------------- */
4178 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4179 i <= EL_CHAR_END) ||
4180 (i >= EL_STEEL_CHAR_START &&
4181 i <= EL_STEEL_CHAR_END)));
4183 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4184 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4185 IS_WALKABLE_INSIDE(i) ||
4186 IS_WALKABLE_UNDER(i)));
4188 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4189 IS_PASSABLE_INSIDE(i) ||
4190 IS_PASSABLE_UNDER(i)));
4192 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4193 IS_PASSABLE_OVER(i)));
4195 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4196 IS_PASSABLE_INSIDE(i)));
4198 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4199 IS_PASSABLE_UNDER(i)));
4201 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4204 /* ---------- COLLECTIBLE ---------------------------------------------- */
4205 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4209 /* ---------- SNAPPABLE ------------------------------------------------ */
4210 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4211 IS_COLLECTIBLE(i) ||
4215 /* ---------- WALL ----------------------------------------------------- */
4216 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4218 for (j = 0; no_wall_properties[j] != -1; j++)
4219 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4220 i >= EL_FIRST_RUNTIME_UNREAL)
4221 SET_PROPERTY(i, EP_WALL, FALSE);
4223 if (IS_HISTORIC_WALL(i))
4224 SET_PROPERTY(i, EP_WALL, TRUE);
4226 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4227 if (engine_version < VERSION_IDENT(2,2,0,0))
4228 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4230 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4232 !IS_COLLECTIBLE(i)));
4234 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4235 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4236 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4238 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4239 IS_INDESTRUCTIBLE(i)));
4241 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4243 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4244 else if (engine_version < VERSION_IDENT(2,2,0,0))
4245 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4247 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4251 if (IS_CUSTOM_ELEMENT(i))
4253 /* these are additional properties which are initially false when set */
4255 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4257 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4258 if (DONT_COLLIDE_WITH(i))
4259 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4261 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4262 if (CAN_SMASH_EVERYTHING(i))
4263 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4264 if (CAN_SMASH_ENEMIES(i))
4265 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4268 /* ---------- CAN_SMASH ------------------------------------------------ */
4269 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4270 CAN_SMASH_ENEMIES(i) ||
4271 CAN_SMASH_EVERYTHING(i)));
4273 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4274 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4275 EXPLODES_BY_FIRE(i)));
4277 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4278 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4279 EXPLODES_SMASHED(i)));
4281 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4282 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4283 EXPLODES_IMPACT(i)));
4285 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4286 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4288 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4289 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4290 i == EL_BLACK_ORB));
4292 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4293 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4295 IS_CUSTOM_ELEMENT(i)));
4297 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4298 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4299 i == EL_SP_ELECTRON));
4301 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4302 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4303 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4304 getMoveIntoAcidProperty(&level, i));
4306 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4307 if (MAYBE_DONT_COLLIDE_WITH(i))
4308 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4309 getDontCollideWithProperty(&level, i));
4311 /* ---------- SP_PORT -------------------------------------------------- */
4312 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4313 IS_PASSABLE_INSIDE(i)));
4315 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4316 for (j = 0; j < level.num_android_clone_elements; j++)
4317 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4319 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4321 /* ---------- CAN_CHANGE ----------------------------------------------- */
4322 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4323 for (j = 0; j < element_info[i].num_change_pages; j++)
4324 if (element_info[i].change_page[j].can_change)
4325 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4327 /* ---------- HAS_ACTION ----------------------------------------------- */
4328 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4329 for (j = 0; j < element_info[i].num_change_pages; j++)
4330 if (element_info[i].change_page[j].has_action)
4331 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4333 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4334 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4337 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4338 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4339 element_info[i].crumbled[ACTION_DEFAULT] !=
4340 element_info[i].graphic[ACTION_DEFAULT]);
4342 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4343 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4344 IS_EDITOR_CASCADE_INACTIVE(i)));
4347 /* dynamically adjust element properties according to game engine version */
4349 static int ep_em_slippery_wall[] =
4354 EL_EXPANDABLE_WALL_HORIZONTAL,
4355 EL_EXPANDABLE_WALL_VERTICAL,
4356 EL_EXPANDABLE_WALL_ANY,
4357 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4358 EL_EXPANDABLE_STEELWALL_VERTICAL,
4359 EL_EXPANDABLE_STEELWALL_ANY,
4360 EL_EXPANDABLE_STEELWALL_GROWING,
4364 static int ep_em_explodes_by_fire[] =
4367 EL_EM_DYNAMITE_ACTIVE,
4372 /* special EM style gems behaviour */
4373 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4374 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4375 level.em_slippery_gems);
4377 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4378 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4379 (level.em_slippery_gems &&
4380 engine_version > VERSION_IDENT(2,0,1,0)));
4382 /* special EM style explosion behaviour regarding chain reactions */
4383 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4384 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4385 level.em_explodes_by_fire);
4388 /* this is needed because some graphics depend on element properties */
4389 if (game_status == GAME_MODE_PLAYING)
4390 InitElementGraphicInfo();
4393 void InitElementPropertiesAfterLoading(int engine_version)
4397 /* set some other uninitialized values of custom elements in older levels */
4398 if (engine_version < VERSION_IDENT(3,1,0,0))
4400 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4402 int element = EL_CUSTOM_START + i;
4404 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4406 element_info[element].explosion_delay = 17;
4407 element_info[element].ignition_delay = 8;
4412 void InitElementPropertiesGfxElement()
4416 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4418 struct ElementInfo *ei = &element_info[i];
4420 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4424 static void InitGlobal()
4429 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4431 /* check if element_name_info entry defined for each element in "main.h" */
4432 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4433 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4435 element_info[i].token_name = element_name_info[i].token_name;
4436 element_info[i].class_name = element_name_info[i].class_name;
4437 element_info[i].editor_description= element_name_info[i].editor_description;
4440 /* create hash from image config list */
4441 image_config_hash = newSetupFileHash();
4442 for (i = 0; image_config[i].token != NULL; i++)
4443 setHashEntry(image_config_hash,
4444 image_config[i].token,
4445 image_config[i].value);
4447 /* create hash from element token list */
4448 element_token_hash = newSetupFileHash();
4449 for (i = 0; element_name_info[i].token_name != NULL; i++)
4450 setHashEntry(element_token_hash,
4451 element_name_info[i].token_name,
4454 /* create hash from graphic token list */
4455 graphic_token_hash = newSetupFileHash();
4456 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4457 if (strSuffix(image_config[i].value, ".png") ||
4458 strSuffix(image_config[i].value, ".pcx") ||
4459 strSuffix(image_config[i].value, ".wav") ||
4460 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4461 setHashEntry(graphic_token_hash,
4462 image_config[i].token,
4463 int2str(graphic++, 0));
4465 /* create hash from font token list */
4466 font_token_hash = newSetupFileHash();
4467 for (i = 0; font_info[i].token_name != NULL; i++)
4468 setHashEntry(font_token_hash,
4469 font_info[i].token_name,
4472 /* set default filenames for all cloned graphics in static configuration */
4473 for (i = 0; image_config[i].token != NULL; i++)
4475 if (strEqual(image_config[i].value, UNDEFINED_FILENAME))
4477 char *token = image_config[i].token;
4478 char *token_clone_from = getStringCat2(token, ".clone_from");
4479 char *token_cloned = getHashEntry(image_config_hash, token_clone_from);
4481 if (token_cloned != NULL)
4483 char *value_cloned = getHashEntry(image_config_hash, token_cloned);
4485 if (value_cloned != NULL)
4487 /* set default filename in static configuration */
4488 image_config[i].value = value_cloned;
4490 /* set default filename in image config hash */
4491 setHashEntry(image_config_hash, token, value_cloned);
4495 free(token_clone_from);
4499 /* always start with reliable default values (all elements) */
4500 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4501 ActiveElement[i] = i;
4503 /* now add all entries that have an active state (active elements) */
4504 for (i = 0; element_with_active_state[i].element != -1; i++)
4506 int element = element_with_active_state[i].element;
4507 int element_active = element_with_active_state[i].element_active;
4509 ActiveElement[element] = element_active;
4512 /* always start with reliable default values (all buttons) */
4513 for (i = 0; i < NUM_IMAGE_FILES; i++)
4514 ActiveButton[i] = i;
4516 /* now add all entries that have an active state (active buttons) */
4517 for (i = 0; button_with_active_state[i].button != -1; i++)
4519 int button = button_with_active_state[i].button;
4520 int button_active = button_with_active_state[i].button_active;
4522 ActiveButton[button] = button_active;
4525 /* always start with reliable default values (all fonts) */
4526 for (i = 0; i < NUM_FONTS; i++)
4529 /* now add all entries that have an active state (active fonts) */
4530 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4532 int font = font_with_active_state[i].font_nr;
4533 int font_active = font_with_active_state[i].font_nr_active;
4535 ActiveFont[font] = font_active;
4538 global.autoplay_leveldir = NULL;
4539 global.convert_leveldir = NULL;
4540 global.create_images_dir = NULL;
4542 global.frames_per_second = 0;
4543 global.fps_slowdown = FALSE;
4544 global.fps_slowdown_factor = 1;
4546 global.border_status = GAME_MODE_MAIN;
4548 global.use_envelope_request = FALSE;
4551 void Execute_Command(char *command)
4555 if (strEqual(command, "print graphicsinfo.conf"))
4557 printf("# You can configure additional/alternative image files here.\n");
4558 printf("# (The entries below are default and therefore commented out.)\n");
4560 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4562 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4565 for (i = 0; image_config[i].token != NULL; i++)
4566 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
4567 image_config[i].value));
4571 else if (strEqual(command, "print soundsinfo.conf"))
4573 printf("# You can configure additional/alternative sound files here.\n");
4574 printf("# (The entries below are default and therefore commented out.)\n");
4576 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4578 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4581 for (i = 0; sound_config[i].token != NULL; i++)
4582 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4583 sound_config[i].value));
4587 else if (strEqual(command, "print musicinfo.conf"))
4589 printf("# You can configure additional/alternative music files here.\n");
4590 printf("# (The entries below are default and therefore commented out.)\n");
4592 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4594 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4597 for (i = 0; music_config[i].token != NULL; i++)
4598 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
4599 music_config[i].value));
4603 else if (strEqual(command, "print editorsetup.conf"))
4605 printf("# You can configure your personal editor element list here.\n");
4606 printf("# (The entries below are default and therefore commented out.)\n");
4609 /* this is needed to be able to check element list for cascade elements */
4610 InitElementPropertiesStatic();
4611 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4613 PrintEditorElementList();
4617 else if (strEqual(command, "print helpanim.conf"))
4619 printf("# You can configure different element help animations here.\n");
4620 printf("# (The entries below are default and therefore commented out.)\n");
4623 for (i = 0; helpanim_config[i].token != NULL; i++)
4625 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4626 helpanim_config[i].value));
4628 if (strEqual(helpanim_config[i].token, "end"))
4634 else if (strEqual(command, "print helptext.conf"))
4636 printf("# You can configure different element help text here.\n");
4637 printf("# (The entries below are default and therefore commented out.)\n");
4640 for (i = 0; helptext_config[i].token != NULL; i++)
4641 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4642 helptext_config[i].value));
4646 else if (strPrefix(command, "dump level "))
4648 char *filename = &command[11];
4650 if (!fileExists(filename))
4651 Error(ERR_EXIT, "cannot open file '%s'", filename);
4653 LoadLevelFromFilename(&level, filename);
4658 else if (strPrefix(command, "dump tape "))
4660 char *filename = &command[10];
4662 if (!fileExists(filename))
4663 Error(ERR_EXIT, "cannot open file '%s'", filename);
4665 LoadTapeFromFilename(filename);
4670 else if (strPrefix(command, "autoplay "))
4672 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
4674 while (*str_ptr != '\0') /* continue parsing string */
4676 /* cut leading whitespace from string, replace it by string terminator */
4677 while (*str_ptr == ' ' || *str_ptr == '\t')
4680 if (*str_ptr == '\0') /* end of string reached */
4683 if (global.autoplay_leveldir == NULL) /* read level set string */
4685 global.autoplay_leveldir = str_ptr;
4686 global.autoplay_all = TRUE; /* default: play all tapes */
4688 for (i = 0; i < MAX_TAPES_PER_SET; i++)
4689 global.autoplay_level[i] = FALSE;
4691 else /* read level number string */
4693 int level_nr = atoi(str_ptr); /* get level_nr value */
4695 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
4696 global.autoplay_level[level_nr] = TRUE;
4698 global.autoplay_all = FALSE;
4701 /* advance string pointer to the next whitespace (or end of string) */
4702 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
4706 else if (strPrefix(command, "convert "))
4708 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
4709 char *str_ptr = strchr(str_copy, ' ');
4711 global.convert_leveldir = str_copy;
4712 global.convert_level_nr = -1;
4714 if (str_ptr != NULL) /* level number follows */
4716 *str_ptr++ = '\0'; /* terminate leveldir string */
4717 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
4720 else if (strPrefix(command, "create images "))
4722 global.create_images_dir = getStringCopy(&command[14]);
4724 if (access(global.create_images_dir, W_OK) != 0)
4725 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
4726 global.create_images_dir);
4730 #if defined(TARGET_SDL2)
4731 else if (strEqual(command, "SDL_ListModes"))
4733 SDL_Init(SDL_INIT_VIDEO);
4735 int num_displays = SDL_GetNumVideoDisplays();
4737 // check if there are any displays available
4738 if (num_displays < 0)
4740 printf("No displays available: %s\n", SDL_GetError());
4745 for (i = 0; i < num_displays; i++)
4747 int num_modes = SDL_GetNumDisplayModes(i);
4750 printf("Available display modes for display %d:\n", i);
4752 // check if there are any display modes available for this display
4755 printf("No display modes available for display %d: %s\n",
4761 for (j = 0; j < num_modes; j++)
4763 SDL_DisplayMode mode;
4765 if (SDL_GetDisplayMode(i, j, &mode) < 0)
4767 printf("Cannot get display mode %d for display %d: %s\n",
4768 j, i, SDL_GetError());
4773 printf("- %d x %d\n", mode.w, mode.h);
4779 #elif defined(TARGET_SDL)
4780 else if (strEqual(command, "SDL_ListModes"))
4785 SDL_Init(SDL_INIT_VIDEO);
4787 /* get available fullscreen/hardware modes */
4788 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
4790 /* check if there are any modes available */
4793 printf("No modes available!\n");
4798 /* check if our resolution is restricted */
4799 if (modes == (SDL_Rect **)-1)
4801 printf("All resolutions available.\n");
4805 printf("Available display modes:\n");
4807 for (i = 0; modes[i]; i++)
4808 printf("- %d x %d\n", modes[i]->w, modes[i]->h);
4818 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4822 static void InitSetup()
4824 LoadSetup(); /* global setup info */
4826 /* set some options from setup file */
4828 if (setup.options.verbose)
4829 options.verbose = TRUE;
4832 static void InitGameInfo()
4834 game.restart_level = FALSE;
4837 static void InitPlayerInfo()
4841 /* choose default local player */
4842 local_player = &stored_player[0];
4844 for (i = 0; i < MAX_PLAYERS; i++)
4845 stored_player[i].connected = FALSE;
4847 local_player->connected = TRUE;
4850 static void InitArtworkInfo()
4855 static char *get_string_in_brackets(char *string)
4857 char *string_in_brackets = checked_malloc(strlen(string) + 3);
4859 sprintf(string_in_brackets, "[%s]", string);
4861 return string_in_brackets;
4864 static char *get_level_id_suffix(int id_nr)
4866 char *id_suffix = checked_malloc(1 + 3 + 1);
4868 if (id_nr < 0 || id_nr > 999)
4871 sprintf(id_suffix, ".%03d", id_nr);
4876 static void InitArtworkConfig()
4878 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
4879 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
4880 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
4881 static char *action_id_suffix[NUM_ACTIONS + 1];
4882 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
4883 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
4884 static char *level_id_suffix[MAX_LEVELS + 1];
4885 static char *dummy[1] = { NULL };
4886 static char *ignore_generic_tokens[] =
4892 static char **ignore_image_tokens;
4893 static char **ignore_sound_tokens;
4894 static char **ignore_music_tokens;
4895 int num_ignore_generic_tokens;
4896 int num_ignore_image_tokens;
4897 int num_ignore_sound_tokens;
4898 int num_ignore_music_tokens;
4901 /* dynamically determine list of generic tokens to be ignored */
4902 num_ignore_generic_tokens = 0;
4903 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
4904 num_ignore_generic_tokens++;
4906 /* dynamically determine list of image tokens to be ignored */
4907 num_ignore_image_tokens = num_ignore_generic_tokens;
4908 for (i = 0; image_config_vars[i].token != NULL; i++)
4909 num_ignore_image_tokens++;
4910 ignore_image_tokens =
4911 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
4912 for (i = 0; i < num_ignore_generic_tokens; i++)
4913 ignore_image_tokens[i] = ignore_generic_tokens[i];
4914 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
4915 ignore_image_tokens[num_ignore_generic_tokens + i] =
4916 image_config_vars[i].token;
4917 ignore_image_tokens[num_ignore_image_tokens] = NULL;
4919 /* dynamically determine list of sound tokens to be ignored */
4920 num_ignore_sound_tokens = num_ignore_generic_tokens;
4921 ignore_sound_tokens =
4922 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
4923 for (i = 0; i < num_ignore_generic_tokens; i++)
4924 ignore_sound_tokens[i] = ignore_generic_tokens[i];
4925 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
4927 /* dynamically determine list of music tokens to be ignored */
4928 num_ignore_music_tokens = num_ignore_generic_tokens;
4929 ignore_music_tokens =
4930 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
4931 for (i = 0; i < num_ignore_generic_tokens; i++)
4932 ignore_music_tokens[i] = ignore_generic_tokens[i];
4933 ignore_music_tokens[num_ignore_music_tokens] = NULL;
4935 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4936 image_id_prefix[i] = element_info[i].token_name;
4937 for (i = 0; i < NUM_FONTS; i++)
4938 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
4939 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
4941 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4942 sound_id_prefix[i] = element_info[i].token_name;
4943 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4944 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
4945 get_string_in_brackets(element_info[i].class_name);
4946 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
4948 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
4949 music_id_prefix[i] = music_prefix_info[i].prefix;
4950 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
4952 for (i = 0; i < NUM_ACTIONS; i++)
4953 action_id_suffix[i] = element_action_info[i].suffix;
4954 action_id_suffix[NUM_ACTIONS] = NULL;
4956 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
4957 direction_id_suffix[i] = element_direction_info[i].suffix;
4958 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
4960 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
4961 special_id_suffix[i] = special_suffix_info[i].suffix;
4962 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
4964 for (i = 0; i < MAX_LEVELS; i++)
4965 level_id_suffix[i] = get_level_id_suffix(i);
4966 level_id_suffix[MAX_LEVELS] = NULL;
4968 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
4969 image_id_prefix, action_id_suffix, direction_id_suffix,
4970 special_id_suffix, ignore_image_tokens);
4971 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
4972 sound_id_prefix, action_id_suffix, dummy,
4973 special_id_suffix, ignore_sound_tokens);
4974 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
4975 music_id_prefix, special_id_suffix, level_id_suffix,
4976 dummy, ignore_music_tokens);
4979 static void InitMixer()
4986 void InitGfxBuffers()
4988 /* create additional image buffers for double-buffering and cross-fading */
4989 ReCreateBitmap(&bitmap_db_store, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
4990 ReCreateBitmap(&bitmap_db_cross, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
4991 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE, DEFAULT_DEPTH);
4992 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE, DEFAULT_DEPTH);
4993 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE, DEFAULT_DEPTH);
4994 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE, DEFAULT_DEPTH);
4995 ReCreateBitmap(&bitmap_db_toons, FULL_SXSIZE, FULL_SYSIZE, DEFAULT_DEPTH);
4997 /* initialize screen properties */
4998 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
4999 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5001 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5002 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5003 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5004 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5005 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5006 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5008 InitGfxBuffers_EM();
5009 InitGfxBuffers_SP();
5014 struct GraphicInfo *graphic_info_last = graphic_info;
5015 char *filename_font_initial = NULL;
5016 char *filename_anim_initial = NULL;
5017 Bitmap *bitmap_font_initial = NULL;
5021 /* determine settings for initial font (for displaying startup messages) */
5022 for (i = 0; image_config[i].token != NULL; i++)
5024 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5026 char font_token[128];
5029 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5030 len_font_token = strlen(font_token);
5032 if (strEqual(image_config[i].token, font_token))
5033 filename_font_initial = image_config[i].value;
5034 else if (strlen(image_config[i].token) > len_font_token &&
5035 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5037 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5038 font_initial[j].src_x = atoi(image_config[i].value);
5039 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5040 font_initial[j].src_y = atoi(image_config[i].value);
5041 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5042 font_initial[j].width = atoi(image_config[i].value);
5043 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5044 font_initial[j].height = atoi(image_config[i].value);
5049 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5051 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5052 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5055 if (filename_font_initial == NULL) /* should not happen */
5056 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5059 InitGfxCustomArtworkInfo();
5061 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5063 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5064 font_initial[j].bitmap = bitmap_font_initial;
5066 InitFontGraphicInfo();
5068 font_height = getFontHeight(FC_RED);
5070 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
5071 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
5072 DrawInitText(PROGRAM_WEBSITE_STRING, WIN_YSIZE - 20 - font_height, FC_RED);
5074 DrawInitText("Loading graphics", 120, FC_GREEN);
5076 /* initialize busy animation with default values */
5077 int parameter[NUM_GFX_ARGS];
5078 for (i = 0; i < NUM_GFX_ARGS; i++)
5079 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5080 image_config_suffix[i].token,
5081 image_config_suffix[i].type);
5083 /* determine settings for busy animation (when displaying startup messages) */
5084 for (i = 0; image_config[i].token != NULL; i++)
5086 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5087 int len_anim_token = strlen(anim_token);
5089 if (strEqual(image_config[i].token, anim_token))
5090 filename_anim_initial = image_config[i].value;
5091 else if (strlen(image_config[i].token) > len_anim_token &&
5092 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5094 for (j = 0; image_config_suffix[j].token != NULL; j++)
5096 if (strEqual(&image_config[i].token[len_anim_token],
5097 image_config_suffix[j].token))
5099 get_graphic_parameter_value(image_config[i].value,
5100 image_config_suffix[j].token,
5101 image_config_suffix[j].type);
5106 #if defined(CREATE_SPECIAL_EDITION_RND_JUE)
5107 filename_anim_initial = "loading.pcx";
5109 parameter[GFX_ARG_X] = 0;
5110 parameter[GFX_ARG_Y] = 0;
5111 parameter[GFX_ARG_WIDTH] = 128;
5112 parameter[GFX_ARG_HEIGHT] = 40;
5113 parameter[GFX_ARG_FRAMES] = 32;
5114 parameter[GFX_ARG_DELAY] = 4;
5115 parameter[GFX_ARG_FRAMES_PER_LINE] = ARG_UNDEFINED_VALUE;
5118 if (filename_anim_initial == NULL) /* should not happen */
5119 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5121 anim_initial.bitmaps =
5122 checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5124 anim_initial.bitmaps[IMG_BITMAP_STANDARD] =
5125 LoadCustomImage(filename_anim_initial);
5127 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
5129 set_graphic_parameters_ext(0, parameter, anim_initial.bitmaps);
5131 graphic_info = graphic_info_last;
5133 init.busy.width = anim_initial.width;
5134 init.busy.height = anim_initial.height;
5136 InitMenuDesignSettings_Static();
5137 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5139 /* use copy of busy animation to prevent change while reloading artwork */
5143 void RedrawBackground()
5145 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
5146 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
5148 redraw_mask = REDRAW_ALL;
5151 void InitGfxBackground()
5155 fieldbuffer = bitmap_db_field;
5156 SetDrawtoField(DRAW_BACKBUFFER);
5158 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5160 for (x = 0; x < MAX_BUF_XSIZE; x++)
5161 for (y = 0; y < MAX_BUF_YSIZE; y++)
5164 redraw_mask = REDRAW_ALL;
5167 static void InitLevelInfo()
5169 LoadLevelInfo(); /* global level info */
5170 LoadLevelSetup_LastSeries(); /* last played series info */
5171 LoadLevelSetup_SeriesInfo(); /* last played level info */
5174 static void InitLevelArtworkInfo()
5176 LoadLevelArtworkInfo();
5179 static void InitImages()
5181 print_timestamp_init("InitImages");
5184 printf("::: leveldir_current->identifier == '%s'\n",
5185 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5186 printf("::: leveldir_current->graphics_path == '%s'\n",
5187 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5188 printf("::: leveldir_current->graphics_set == '%s'\n",
5189 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5190 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5191 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5194 setLevelArtworkDir(artwork.gfx_first);
5197 printf("::: leveldir_current->identifier == '%s'\n",
5198 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5199 printf("::: leveldir_current->graphics_path == '%s'\n",
5200 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5201 printf("::: leveldir_current->graphics_set == '%s'\n",
5202 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5203 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5204 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5208 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5209 leveldir_current->identifier,
5210 artwork.gfx_current_identifier,
5211 artwork.gfx_current->identifier,
5212 leveldir_current->graphics_set,
5213 leveldir_current->graphics_path);
5216 UPDATE_BUSY_STATE();
5218 ReloadCustomImages();
5219 print_timestamp_time("ReloadCustomImages");
5221 UPDATE_BUSY_STATE();
5223 LoadCustomElementDescriptions();
5224 print_timestamp_time("LoadCustomElementDescriptions");
5226 UPDATE_BUSY_STATE();
5228 LoadMenuDesignSettings();
5229 print_timestamp_time("LoadMenuDesignSettings");
5231 UPDATE_BUSY_STATE();
5233 ReinitializeGraphics();
5234 print_timestamp_time("ReinitializeGraphics");
5236 UPDATE_BUSY_STATE();
5238 print_timestamp_done("InitImages");
5241 static void InitSound(char *identifier)
5243 print_timestamp_init("InitSound");
5245 if (identifier == NULL)
5246 identifier = artwork.snd_current->identifier;
5248 /* set artwork path to send it to the sound server process */
5249 setLevelArtworkDir(artwork.snd_first);
5251 InitReloadCustomSounds(identifier);
5252 print_timestamp_time("InitReloadCustomSounds");
5254 ReinitializeSounds();
5255 print_timestamp_time("ReinitializeSounds");
5257 print_timestamp_done("InitSound");
5260 static void InitMusic(char *identifier)
5262 print_timestamp_init("InitMusic");
5264 if (identifier == NULL)
5265 identifier = artwork.mus_current->identifier;
5267 /* set artwork path to send it to the sound server process */
5268 setLevelArtworkDir(artwork.mus_first);
5270 InitReloadCustomMusic(identifier);
5271 print_timestamp_time("InitReloadCustomMusic");
5273 ReinitializeMusic();
5274 print_timestamp_time("ReinitializeMusic");
5276 print_timestamp_done("InitMusic");
5279 void InitNetworkServer()
5281 #if defined(NETWORK_AVALIABLE)
5285 if (!options.network)
5288 #if defined(NETWORK_AVALIABLE)
5289 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5291 if (!ConnectToServer(options.server_host, options.server_port))
5292 Error(ERR_EXIT, "cannot connect to network game server");
5294 SendToServer_PlayerName(setup.player_name);
5295 SendToServer_ProtocolVersion();
5298 SendToServer_NrWanted(nr_wanted);
5302 static boolean CheckArtworkConfigForCustomElements(char *filename)
5304 SetupFileHash *setup_file_hash;
5305 boolean redefined_ce_found = FALSE;
5307 /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */
5309 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5311 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5313 char *token = HASH_ITERATION_TOKEN(itr);
5315 if (strPrefix(token, "custom_"))
5317 redefined_ce_found = TRUE;
5322 END_HASH_ITERATION(setup_file_hash, itr)
5324 freeSetupFileHash(setup_file_hash);
5327 return redefined_ce_found;
5330 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5332 char *filename_base, *filename_local;
5333 boolean redefined_ce_found = FALSE;
5335 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5338 printf("::: leveldir_current->identifier == '%s'\n",
5339 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5340 printf("::: leveldir_current->graphics_path == '%s'\n",
5341 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5342 printf("::: leveldir_current->graphics_set == '%s'\n",
5343 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5344 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5345 leveldir_current == NULL ? "[NULL]" :
5346 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5349 /* first look for special artwork configured in level series config */
5350 filename_base = getCustomArtworkLevelConfigFilename(type);
5353 printf("::: filename_base == '%s'\n", filename_base);
5356 if (fileExists(filename_base))
5357 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5359 filename_local = getCustomArtworkConfigFilename(type);
5362 printf("::: filename_local == '%s'\n", filename_local);
5365 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5366 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5369 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5372 return redefined_ce_found;
5375 static void InitOverrideArtwork()
5377 boolean redefined_ce_found = FALSE;
5379 /* to check if this level set redefines any CEs, do not use overriding */
5380 gfx.override_level_graphics = FALSE;
5381 gfx.override_level_sounds = FALSE;
5382 gfx.override_level_music = FALSE;
5384 /* now check if this level set has definitions for custom elements */
5385 if (setup.override_level_graphics == AUTO ||
5386 setup.override_level_sounds == AUTO ||
5387 setup.override_level_music == AUTO)
5388 redefined_ce_found =
5389 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5390 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5391 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5394 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5397 if (redefined_ce_found)
5399 /* this level set has CE definitions: change "AUTO" to "FALSE" */
5400 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5401 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
5402 gfx.override_level_music = (setup.override_level_music == TRUE);
5406 /* this level set has no CE definitions: change "AUTO" to "TRUE" */
5407 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5408 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
5409 gfx.override_level_music = (setup.override_level_music != FALSE);
5413 printf("::: => %d, %d, %d\n",
5414 gfx.override_level_graphics,
5415 gfx.override_level_sounds,
5416 gfx.override_level_music);
5420 static char *getNewArtworkIdentifier(int type)
5422 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5423 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5424 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5425 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5426 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5427 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5428 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5429 char *leveldir_identifier = leveldir_current->identifier;
5430 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
5431 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5432 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5433 char *artwork_current_identifier;
5434 char *artwork_new_identifier = NULL; /* default: nothing has changed */
5436 /* leveldir_current may be invalid (level group, parent link) */
5437 if (!validLevelSeries(leveldir_current))
5440 /* 1st step: determine artwork set to be activated in descending order:
5441 --------------------------------------------------------------------
5442 1. setup artwork (when configured to override everything else)
5443 2. artwork set configured in "levelinfo.conf" of current level set
5444 (artwork in level directory will have priority when loading later)
5445 3. artwork in level directory (stored in artwork sub-directory)
5446 4. setup artwork (currently configured in setup menu) */
5448 if (setup_override_artwork)
5449 artwork_current_identifier = setup_artwork_set;
5450 else if (leveldir_artwork_set != NULL)
5451 artwork_current_identifier = leveldir_artwork_set;
5452 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5453 artwork_current_identifier = leveldir_identifier;
5455 artwork_current_identifier = setup_artwork_set;
5458 /* 2nd step: check if it is really needed to reload artwork set
5459 ------------------------------------------------------------ */
5461 /* ---------- reload if level set and also artwork set has changed ------- */
5462 if (leveldir_current_identifier[type] != leveldir_identifier &&
5463 (last_has_level_artwork_set[type] || has_level_artwork_set))
5464 artwork_new_identifier = artwork_current_identifier;
5466 leveldir_current_identifier[type] = leveldir_identifier;
5467 last_has_level_artwork_set[type] = has_level_artwork_set;
5469 /* ---------- reload if "override artwork" setting has changed ----------- */
5470 if (last_override_level_artwork[type] != setup_override_artwork)
5471 artwork_new_identifier = artwork_current_identifier;
5473 last_override_level_artwork[type] = setup_override_artwork;
5475 /* ---------- reload if current artwork identifier has changed ----------- */
5476 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5477 artwork_current_identifier))
5478 artwork_new_identifier = artwork_current_identifier;
5480 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5482 /* ---------- do not reload directly after starting ---------------------- */
5483 if (!initialized[type])
5484 artwork_new_identifier = NULL;
5486 initialized[type] = TRUE;
5488 return artwork_new_identifier;
5491 void ReloadCustomArtwork(int force_reload)
5493 int last_game_status = game_status; /* save current game status */
5494 char *gfx_new_identifier;
5495 char *snd_new_identifier;
5496 char *mus_new_identifier;
5497 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5498 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5499 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5500 boolean reload_needed;
5502 InitOverrideArtwork();
5504 force_reload_gfx |= AdjustGraphicsForEMC();
5506 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5507 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5508 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5510 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
5511 snd_new_identifier != NULL || force_reload_snd ||
5512 mus_new_identifier != NULL || force_reload_mus);
5517 print_timestamp_init("ReloadCustomArtwork");
5519 game_status = GAME_MODE_LOADING;
5521 FadeOut(REDRAW_ALL);
5523 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5524 print_timestamp_time("ClearRectangle");
5528 if (gfx_new_identifier != NULL || force_reload_gfx)
5531 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5532 artwork.gfx_current_identifier,
5534 artwork.gfx_current->identifier,
5535 leveldir_current->graphics_set);
5539 print_timestamp_time("InitImages");
5542 if (snd_new_identifier != NULL || force_reload_snd)
5544 InitSound(snd_new_identifier);
5545 print_timestamp_time("InitSound");
5548 if (mus_new_identifier != NULL || force_reload_mus)
5550 InitMusic(mus_new_identifier);
5551 print_timestamp_time("InitMusic");
5554 game_status = last_game_status; /* restore current game status */
5556 init_last = init; /* switch to new busy animation */
5558 FadeOut(REDRAW_ALL);
5562 /* force redraw of (open or closed) door graphics */
5563 SetDoorState(DOOR_OPEN_ALL);
5564 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5566 FadeSetEnterScreen();
5567 FadeSkipNextFadeOut();
5569 print_timestamp_done("ReloadCustomArtwork");
5571 LimitScreenUpdates(FALSE);
5574 void KeyboardAutoRepeatOffUnlessAutoplay()
5576 if (global.autoplay_leveldir == NULL)
5577 KeyboardAutoRepeatOff();
5580 void DisplayExitMessage(char *format, va_list ap)
5582 // check if draw buffer and fonts for exit message are already available
5583 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
5586 int font_1 = FC_RED;
5587 int font_2 = FC_YELLOW;
5588 int font_3 = FC_BLUE;
5589 int font_width = getFontWidth(font_2);
5590 int font_height = getFontHeight(font_2);
5593 int sxsize = WIN_XSIZE - 2 * sx;
5594 int sysize = WIN_YSIZE - 2 * sy;
5595 int line_length = sxsize / font_width;
5596 int max_lines = sysize / font_height;
5597 int num_lines_printed;
5601 gfx.sxsize = sxsize;
5602 gfx.sysize = sysize;
5606 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5608 DrawTextSCentered(sy, font_1, "Fatal error:");
5609 sy += 3 * font_height;;
5612 DrawTextBufferVA(sx, sy, format, ap, font_2,
5613 line_length, line_length, max_lines,
5614 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5615 sy += (num_lines_printed + 3) * font_height;
5617 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
5618 sy += 3 * font_height;
5621 DrawTextBuffer(sx, sy, program.error_filename, font_2,
5622 line_length, line_length, max_lines,
5623 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5625 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
5627 redraw_mask = REDRAW_ALL;
5629 /* force drawing exit message even if screen updates are currently limited */
5630 LimitScreenUpdates(FALSE);
5634 /* deactivate toons on error message screen */
5635 setup.toons = FALSE;
5637 WaitForEventToContinue();
5641 /* ========================================================================= */
5643 /* ========================================================================= */
5647 print_timestamp_init("OpenAll");
5649 game_status = GAME_MODE_LOADING;
5653 InitGlobal(); /* initialize some global variables */
5655 print_timestamp_time("[init global stuff]");
5657 if (options.execute_command)
5658 Execute_Command(options.execute_command);
5660 if (options.serveronly)
5662 #if defined(PLATFORM_UNIX)
5663 NetworkServer(options.server_port, options.serveronly);
5665 Error(ERR_WARN, "networking only supported in Unix version");
5668 exit(0); /* never reached, server loops forever */
5673 print_timestamp_time("[init setup/config stuff (1)]");
5676 print_timestamp_time("[init setup/config stuff (2)]");
5678 print_timestamp_time("[init setup/config stuff (3)]");
5679 InitArtworkInfo(); /* needed before loading gfx, sound & music */
5680 print_timestamp_time("[init setup/config stuff (4)]");
5681 InitArtworkConfig(); /* needed before forking sound child process */
5682 print_timestamp_time("[init setup/config stuff (5)]");
5684 print_timestamp_time("[init setup/config stuff (6)]");
5686 InitRND(NEW_RANDOMIZE);
5687 InitSimpleRandom(NEW_RANDOMIZE);
5691 print_timestamp_time("[init setup/config stuff]");
5694 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
5696 InitEventFilter(FilterEvents);
5698 print_timestamp_time("[init video stuff]");
5700 InitElementPropertiesStatic();
5701 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5702 InitElementPropertiesGfxElement();
5704 print_timestamp_time("[init element properties stuff]");
5708 print_timestamp_time("InitGfx");
5711 print_timestamp_time("InitLevelInfo");
5713 InitLevelArtworkInfo();
5714 print_timestamp_time("InitLevelArtworkInfo");
5716 InitOverrideArtwork(); /* needs to know current level directory */
5717 print_timestamp_time("InitOverrideArtwork");
5719 InitImages(); /* needs to know current level directory */
5720 print_timestamp_time("InitImages");
5722 InitSound(NULL); /* needs to know current level directory */
5723 print_timestamp_time("InitSound");
5725 InitMusic(NULL); /* needs to know current level directory */
5726 print_timestamp_time("InitMusic");
5728 InitGfxBackground();
5733 if (global.autoplay_leveldir)
5738 else if (global.convert_leveldir)
5743 else if (global.create_images_dir)
5745 CreateLevelSketchImages();
5749 game_status = GAME_MODE_MAIN;
5751 FadeSetEnterScreen();
5752 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
5753 FadeSkipNextFadeOut();
5755 print_timestamp_time("[post-artwork]");
5757 print_timestamp_done("OpenAll");
5761 InitNetworkServer();
5764 Error(ERR_DEBUG, "::: SDL_GetBasePath() == '%s'",
5766 Error(ERR_DEBUG, "::: SDL_GetPrefPath() == '%s'",
5767 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
5768 #if defined(PLATFORM_ANDROID)
5769 Error(ERR_DEBUG, "::: SDL_AndroidGetInternalStoragePath() == '%s'",
5770 SDL_AndroidGetInternalStoragePath());
5771 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStoragePath() == '%s'",
5772 SDL_AndroidGetExternalStoragePath());
5773 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStorageState() == '%s'",
5774 (SDL_AndroidGetExternalStorageState() ==
5775 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "read" :
5776 SDL_AndroidGetExternalStorageState() ==
5777 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "write" : "not available"));
5782 void CloseAllAndExit(int exit_value)
5787 CloseAudio(); /* called after freeing sounds (needed for SDL) */
5794 #if defined(TARGET_SDL)
5795 #if defined(TARGET_SDL2)
5797 // set a flag to tell the network server thread to quit and wait for it
5798 // using SDL_WaitThread()
5800 if (network_server) /* terminate network server */
5801 SDL_KillThread(server_thread);
5805 CloseVideoDisplay();
5806 ClosePlatformDependentStuff();
5808 if (exit_value != 0)
5810 /* fall back to default level set (current set may have caused an error) */
5811 SaveLevelSetup_LastSeries_Deactivate();
5813 /* tell user where to find error log file which may contain more details */
5814 // (error notification now directly displayed on screen inside R'n'D
5815 // NotifyUserAboutErrorFile(); /* currently only works for Windows */