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);
956 return (value != NULL ? atoi(value) : EL_UNDEFINED);
958 else if (type == TYPE_GRAPHIC)
960 char *value = getHashEntry(graphic_token_hash, value_raw);
962 return (value != NULL ? atoi(value) : IMG_UNDEFINED);
968 static int get_scaled_graphic_width(int graphic)
970 int original_width = getOriginalImageWidthFromImageID(graphic);
971 int scale_up_factor = graphic_info[graphic].scale_up_factor;
973 return original_width * scale_up_factor;
976 static int get_scaled_graphic_height(int graphic)
978 int original_height = getOriginalImageHeightFromImageID(graphic);
979 int scale_up_factor = graphic_info[graphic].scale_up_factor;
981 return original_height * scale_up_factor;
984 static void set_graphic_parameters_ext(int graphic, int *parameter,
985 Bitmap **src_bitmaps)
987 struct GraphicInfo *g = &graphic_info[graphic];
988 Bitmap *src_bitmap = (src_bitmaps ? src_bitmaps[IMG_BITMAP_STANDARD] : NULL);
989 int anim_frames_per_row = 1, anim_frames_per_col = 1;
990 int anim_frames_per_line = 1;
992 /* always start with reliable default values */
993 g->src_image_width = 0;
994 g->src_image_height = 0;
997 g->width = TILEX; /* default for element graphics */
998 g->height = TILEY; /* default for element graphics */
999 g->offset_x = 0; /* one or both of these values ... */
1000 g->offset_y = 0; /* ... will be corrected later */
1001 g->offset2_x = 0; /* one or both of these values ... */
1002 g->offset2_y = 0; /* ... will be corrected later */
1003 g->swap_double_tiles = -1; /* auto-detect tile swapping */
1004 g->crumbled_like = -1; /* do not use clone element */
1005 g->diggable_like = -1; /* do not use clone element */
1006 g->border_size = TILEX / 8; /* "CRUMBLED" border size */
1007 g->scale_up_factor = 1; /* default: no scaling up */
1008 g->tile_size = TILESIZE; /* default: standard tile size */
1009 g->clone_from = -1; /* do not use clone graphic */
1010 g->anim_delay_fixed = 0;
1011 g->anim_delay_random = 0;
1012 g->post_delay_fixed = 0;
1013 g->post_delay_random = 0;
1014 g->fade_mode = FADE_MODE_DEFAULT;
1018 g->align = ALIGN_CENTER; /* default for title screens */
1019 g->valign = VALIGN_MIDDLE; /* default for title screens */
1020 g->sort_priority = 0; /* default for title screens */
1022 g->style = STYLE_DEFAULT;
1024 g->bitmaps = src_bitmaps;
1025 g->bitmap = src_bitmap;
1027 /* optional zoom factor for scaling up the image to a larger size */
1028 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1029 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1030 if (g->scale_up_factor < 1)
1031 g->scale_up_factor = 1; /* no scaling */
1033 /* optional tile size for using non-standard image size */
1034 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1036 g->tile_size = parameter[GFX_ARG_TILE_SIZE];
1039 // CHECK: should tile sizes less than standard tile size be allowed?
1040 if (g->tile_size < TILESIZE)
1041 g->tile_size = TILESIZE; /* standard tile size */
1045 // CHECK: when setting tile size, should this set width and height?
1046 g->width = g->tile_size;
1047 g->height = g->tile_size;
1051 if (g->use_image_size)
1053 /* set new default bitmap size (with scaling, but without small images) */
1054 g->width = get_scaled_graphic_width(graphic);
1055 g->height = get_scaled_graphic_height(graphic);
1058 /* optional width and height of each animation frame */
1059 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1060 g->width = parameter[GFX_ARG_WIDTH];
1061 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1062 g->height = parameter[GFX_ARG_HEIGHT];
1064 /* optional x and y tile position of animation frame sequence */
1065 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1066 g->src_x = parameter[GFX_ARG_XPOS] * g->width;
1067 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1068 g->src_y = parameter[GFX_ARG_YPOS] * g->height;
1070 /* optional x and y pixel position of animation frame sequence */
1071 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1072 g->src_x = parameter[GFX_ARG_X];
1073 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1074 g->src_y = parameter[GFX_ARG_Y];
1080 Error(ERR_INFO_LINE, "-");
1081 Error(ERR_WARN, "invalid value %d for '%s.width' (fallback done to %d)",
1082 g->width, getTokenFromImageID(graphic), TILEX);
1083 Error(ERR_INFO_LINE, "-");
1085 g->width = TILEX; /* will be checked to be inside bitmap later */
1090 Error(ERR_INFO_LINE, "-");
1091 Error(ERR_WARN, "invalid value %d for '%s.height' (fallback done to %d)",
1092 g->height, getTokenFromImageID(graphic), TILEY);
1093 Error(ERR_INFO_LINE, "-");
1095 g->height = TILEY; /* will be checked to be inside bitmap later */
1101 /* get final bitmap size (with scaling, but without small images) */
1102 int src_image_width = get_scaled_graphic_width(graphic);
1103 int src_image_height = get_scaled_graphic_height(graphic);
1105 if (src_image_width == 0 || src_image_height == 0)
1107 /* only happens when loaded outside artwork system (like "global.busy") */
1108 src_image_width = src_bitmap->width;
1109 src_image_height = src_bitmap->height;
1112 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1114 anim_frames_per_row = src_image_width / g->tile_size;
1115 anim_frames_per_col = src_image_height / g->tile_size;
1119 anim_frames_per_row = src_image_width / g->width;
1120 anim_frames_per_col = src_image_height / g->height;
1123 g->src_image_width = src_image_width;
1124 g->src_image_height = src_image_height;
1127 /* correct x or y offset dependent of vertical or horizontal frame order */
1128 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1130 g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1131 parameter[GFX_ARG_OFFSET] : g->height);
1132 anim_frames_per_line = anim_frames_per_col;
1134 else /* frames are ordered horizontally */
1136 g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1137 parameter[GFX_ARG_OFFSET] : g->width);
1138 anim_frames_per_line = anim_frames_per_row;
1141 /* optionally, the x and y offset of frames can be specified directly */
1142 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1143 g->offset_x = parameter[GFX_ARG_XOFFSET];
1144 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1145 g->offset_y = parameter[GFX_ARG_YOFFSET];
1147 /* optionally, moving animations may have separate start and end graphics */
1148 g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1150 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1151 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1153 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1154 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1155 g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1156 parameter[GFX_ARG_2ND_OFFSET] : g->height);
1157 else /* frames are ordered horizontally */
1158 g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1159 parameter[GFX_ARG_2ND_OFFSET] : g->width);
1161 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1162 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1163 g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1164 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1165 g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1167 /* optionally, the second movement tile can be specified as start tile */
1168 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1169 g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1171 /* automatically determine correct number of frames, if not defined */
1172 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1173 g->anim_frames = parameter[GFX_ARG_FRAMES];
1174 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1175 g->anim_frames = anim_frames_per_row;
1176 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1177 g->anim_frames = anim_frames_per_col;
1181 if (g->anim_frames == 0) /* frames must be at least 1 */
1184 g->anim_frames_per_line =
1185 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1186 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1188 g->anim_delay = parameter[GFX_ARG_DELAY];
1189 if (g->anim_delay == 0) /* delay must be at least 1 */
1192 g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1194 /* automatically determine correct start frame, if not defined */
1195 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1196 g->anim_start_frame = 0;
1197 else if (g->anim_mode & ANIM_REVERSE)
1198 g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1200 g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1202 /* animation synchronized with global frame counter, not move position */
1203 g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1205 /* optional element for cloning crumble graphics */
1206 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1207 g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1209 /* optional element for cloning digging graphics */
1210 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1211 g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1213 /* optional border size for "crumbling" diggable graphics */
1214 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1215 g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1217 /* this is only used for player "boring" and "sleeping" actions */
1218 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1219 g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1220 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1221 g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1222 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1223 g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1224 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1225 g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1227 /* this is only used for toon animations */
1228 g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1229 g->step_delay = parameter[GFX_ARG_STEP_DELAY];
1231 /* this is only used for drawing font characters */
1232 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1233 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1235 /* this is only used for drawing envelope graphics */
1236 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1238 /* optional graphic for cloning all graphics settings */
1239 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1240 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1242 /* optional settings for drawing title screens and title messages */
1243 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1244 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1245 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1246 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1247 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1248 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1249 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1250 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1251 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1252 g->align = parameter[GFX_ARG_ALIGN];
1253 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1254 g->valign = parameter[GFX_ARG_VALIGN];
1255 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1256 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1258 if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
1259 g->class = parameter[GFX_ARG_CLASS];
1260 if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
1261 g->style = parameter[GFX_ARG_STYLE];
1263 /* this is only used for drawing menu buttons and text */
1264 g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
1265 g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
1266 g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
1267 g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
1270 static void set_graphic_parameters(int graphic)
1272 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1273 char **parameter_raw = image->parameter;
1274 Bitmap **src_bitmaps = getBitmapsFromImageID(graphic);
1275 int parameter[NUM_GFX_ARGS];
1278 /* if fallback to default artwork is done, also use the default parameters */
1279 if (image->fallback_to_default)
1280 parameter_raw = image->default_parameter;
1282 /* get integer values from string parameters */
1283 for (i = 0; i < NUM_GFX_ARGS; i++)
1284 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1285 image_config_suffix[i].token,
1286 image_config_suffix[i].type);
1288 set_graphic_parameters_ext(graphic, parameter, src_bitmaps);
1290 UPDATE_BUSY_STATE();
1293 static void set_cloned_graphic_parameters(int graphic)
1295 int fallback_graphic = IMG_CHAR_EXCLAM;
1296 int max_num_images = getImageListSize();
1297 int clone_graphic = graphic_info[graphic].clone_from;
1298 int num_references_followed = 1;
1300 while (graphic_info[clone_graphic].clone_from != -1 &&
1301 num_references_followed < max_num_images)
1303 clone_graphic = graphic_info[clone_graphic].clone_from;
1305 num_references_followed++;
1308 if (num_references_followed >= max_num_images)
1310 Error(ERR_INFO_LINE, "-");
1311 Error(ERR_INFO, "warning: error found in config file:");
1312 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1313 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1314 Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1315 Error(ERR_INFO, "custom graphic rejected for this element/action");
1317 if (graphic == fallback_graphic)
1318 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1320 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1321 Error(ERR_INFO_LINE, "-");
1323 graphic_info[graphic] = graphic_info[fallback_graphic];
1327 graphic_info[graphic] = graphic_info[clone_graphic];
1328 graphic_info[graphic].clone_from = clone_graphic;
1332 static void InitGraphicInfo()
1334 int fallback_graphic = IMG_CHAR_EXCLAM;
1335 int num_images = getImageListSize();
1338 /* use image size as default values for width and height for these images */
1339 static int full_size_graphics[] =
1344 IMG_BACKGROUND_ENVELOPE_1,
1345 IMG_BACKGROUND_ENVELOPE_2,
1346 IMG_BACKGROUND_ENVELOPE_3,
1347 IMG_BACKGROUND_ENVELOPE_4,
1348 IMG_BACKGROUND_REQUEST,
1351 IMG_BACKGROUND_TITLE_INITIAL,
1352 IMG_BACKGROUND_TITLE,
1353 IMG_BACKGROUND_MAIN,
1354 IMG_BACKGROUND_LEVELS,
1355 IMG_BACKGROUND_LEVELNR,
1356 IMG_BACKGROUND_SCORES,
1357 IMG_BACKGROUND_EDITOR,
1358 IMG_BACKGROUND_INFO,
1359 IMG_BACKGROUND_INFO_ELEMENTS,
1360 IMG_BACKGROUND_INFO_MUSIC,
1361 IMG_BACKGROUND_INFO_CREDITS,
1362 IMG_BACKGROUND_INFO_PROGRAM,
1363 IMG_BACKGROUND_INFO_VERSION,
1364 IMG_BACKGROUND_INFO_LEVELSET,
1365 IMG_BACKGROUND_SETUP,
1366 IMG_BACKGROUND_PLAYING,
1367 IMG_BACKGROUND_DOOR,
1368 IMG_BACKGROUND_TAPE,
1369 IMG_BACKGROUND_PANEL,
1370 IMG_BACKGROUND_PALETTE,
1371 IMG_BACKGROUND_TOOLBOX,
1373 IMG_TITLESCREEN_INITIAL_1,
1374 IMG_TITLESCREEN_INITIAL_2,
1375 IMG_TITLESCREEN_INITIAL_3,
1376 IMG_TITLESCREEN_INITIAL_4,
1377 IMG_TITLESCREEN_INITIAL_5,
1384 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1,
1385 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2,
1386 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3,
1387 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4,
1388 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5,
1389 IMG_BACKGROUND_TITLEMESSAGE_1,
1390 IMG_BACKGROUND_TITLEMESSAGE_2,
1391 IMG_BACKGROUND_TITLEMESSAGE_3,
1392 IMG_BACKGROUND_TITLEMESSAGE_4,
1393 IMG_BACKGROUND_TITLEMESSAGE_5,
1398 checked_free(graphic_info);
1400 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1402 /* initialize "use_image_size" flag with default value */
1403 for (i = 0; i < num_images; i++)
1404 graphic_info[i].use_image_size = FALSE;
1406 /* initialize "use_image_size" flag from static configuration above */
1407 for (i = 0; full_size_graphics[i] != -1; i++)
1408 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1410 /* first set all graphic paramaters ... */
1411 for (i = 0; i < num_images; i++)
1412 set_graphic_parameters(i);
1414 /* ... then copy these parameters for cloned graphics */
1415 for (i = 0; i < num_images; i++)
1416 if (graphic_info[i].clone_from != -1)
1417 set_cloned_graphic_parameters(i);
1419 for (i = 0; i < num_images; i++)
1424 int first_frame, last_frame;
1425 int src_bitmap_width, src_bitmap_height;
1427 /* now check if no animation frames are outside of the loaded image */
1429 if (graphic_info[i].bitmap == NULL)
1430 continue; /* skip check for optional images that are undefined */
1432 /* get image size (this can differ from the standard element tile size!) */
1433 width = graphic_info[i].width;
1434 height = graphic_info[i].height;
1436 /* get final bitmap size (with scaling, but without small images) */
1437 src_bitmap_width = graphic_info[i].src_image_width;
1438 src_bitmap_height = graphic_info[i].src_image_height;
1440 /* check if first animation frame is inside specified bitmap */
1443 getFixedGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1445 /* this avoids calculating wrong start position for out-of-bounds frame */
1446 src_x = graphic_info[i].src_x;
1447 src_y = graphic_info[i].src_y;
1449 if (src_x < 0 || src_y < 0 ||
1450 src_x + width > src_bitmap_width ||
1451 src_y + height > src_bitmap_height)
1453 Error(ERR_INFO_LINE, "-");
1454 Error(ERR_INFO, "warning: error found in config file:");
1455 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1456 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1457 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1459 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1460 src_x, src_y, src_bitmap_width, src_bitmap_height);
1461 Error(ERR_INFO, "custom graphic rejected for this element/action");
1463 if (i == fallback_graphic)
1464 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1466 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1467 Error(ERR_INFO_LINE, "-");
1469 graphic_info[i] = graphic_info[fallback_graphic];
1472 /* check if last animation frame is inside specified bitmap */
1474 last_frame = graphic_info[i].anim_frames - 1;
1475 getFixedGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1477 if (src_x < 0 || src_y < 0 ||
1478 src_x + width > src_bitmap_width ||
1479 src_y + height > src_bitmap_height)
1481 Error(ERR_INFO_LINE, "-");
1482 Error(ERR_INFO, "warning: error found in config file:");
1483 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1484 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1485 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1487 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1488 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1489 Error(ERR_INFO, "::: %d, %d", width, height);
1490 Error(ERR_INFO, "custom graphic rejected for this element/action");
1492 if (i == fallback_graphic)
1493 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1495 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1496 Error(ERR_INFO_LINE, "-");
1498 graphic_info[i] = graphic_info[fallback_graphic];
1503 static void InitGraphicCompatibilityInfo()
1505 struct FileInfo *fi_global_door =
1506 getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1507 int num_images = getImageListSize();
1510 /* the following compatibility handling is needed for the following case:
1511 versions up to 3.3.0.0 used one large bitmap "global.door" for various
1512 graphics mainly used for door and panel graphics, like editor, tape and
1513 in-game buttons with hard-coded bitmap positions and button sizes; as
1514 these graphics now have individual definitions, redefining "global.door"
1515 to change all these graphics at once like before does not work anymore
1516 (because all those individual definitions still have their default values);
1517 to solve this, remap all those individual definitions that are not
1518 redefined to the new bitmap of "global.door" if it was redefined */
1520 /* special compatibility handling if image "global.door" was redefined */
1521 if (fi_global_door->redefined)
1523 for (i = 0; i < num_images; i++)
1525 struct FileInfo *fi = getImageListEntryFromImageID(i);
1527 /* process only those images that still use the default settings */
1530 /* process all images which default to same image as "global.door" */
1531 if (strEqual(fi->default_filename, fi_global_door->default_filename))
1533 // printf("::: special treatment needed for token '%s'\n", fi->token);
1535 graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
1541 InitGraphicCompatibilityInfo_Doors();
1544 static void InitElementSoundInfo()
1546 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1547 int num_property_mappings = getSoundListPropertyMappingSize();
1550 /* set values to -1 to identify later as "uninitialized" values */
1551 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1552 for (act = 0; act < NUM_ACTIONS; act++)
1553 element_info[i].sound[act] = -1;
1555 /* initialize element/sound mapping from static configuration */
1556 for (i = 0; element_to_sound[i].element > -1; i++)
1558 int element = element_to_sound[i].element;
1559 int action = element_to_sound[i].action;
1560 int sound = element_to_sound[i].sound;
1561 boolean is_class = element_to_sound[i].is_class;
1564 action = ACTION_DEFAULT;
1567 element_info[element].sound[action] = sound;
1569 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1570 if (strEqual(element_info[j].class_name,
1571 element_info[element].class_name))
1572 element_info[j].sound[action] = sound;
1575 /* initialize element class/sound mapping from dynamic configuration */
1576 for (i = 0; i < num_property_mappings; i++)
1578 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1579 int action = property_mapping[i].ext1_index;
1580 int sound = property_mapping[i].artwork_index;
1582 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1586 action = ACTION_DEFAULT;
1588 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1589 if (strEqual(element_info[j].class_name,
1590 element_info[element_class].class_name))
1591 element_info[j].sound[action] = sound;
1594 /* initialize element/sound mapping from dynamic configuration */
1595 for (i = 0; i < num_property_mappings; i++)
1597 int element = property_mapping[i].base_index;
1598 int action = property_mapping[i].ext1_index;
1599 int sound = property_mapping[i].artwork_index;
1601 if (element >= MAX_NUM_ELEMENTS)
1605 action = ACTION_DEFAULT;
1607 element_info[element].sound[action] = sound;
1610 /* now set all '-1' values to element specific default values */
1611 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1613 for (act = 0; act < NUM_ACTIONS; act++)
1615 /* generic default action sound (defined by "[default]" directive) */
1616 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1618 /* look for special default action sound (classic game specific) */
1619 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1620 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1621 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1622 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1623 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1624 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1626 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1627 /* !!! make this better !!! */
1628 if (i == EL_EMPTY_SPACE)
1629 default_action_sound = element_info[EL_DEFAULT].sound[act];
1631 /* no sound for this specific action -- use default action sound */
1632 if (element_info[i].sound[act] == -1)
1633 element_info[i].sound[act] = default_action_sound;
1637 /* copy sound settings to some elements that are only stored in level file
1638 in native R'n'D levels, but are used by game engine in native EM levels */
1639 for (i = 0; copy_properties[i][0] != -1; i++)
1640 for (j = 1; j <= 4; j++)
1641 for (act = 0; act < NUM_ACTIONS; act++)
1642 element_info[copy_properties[i][j]].sound[act] =
1643 element_info[copy_properties[i][0]].sound[act];
1646 static void InitGameModeSoundInfo()
1650 /* set values to -1 to identify later as "uninitialized" values */
1651 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1654 /* initialize gamemode/sound mapping from static configuration */
1655 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1657 int gamemode = gamemode_to_sound[i].gamemode;
1658 int sound = gamemode_to_sound[i].sound;
1661 gamemode = GAME_MODE_DEFAULT;
1663 menu.sound[gamemode] = sound;
1666 /* now set all '-1' values to levelset specific default values */
1667 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1668 if (menu.sound[i] == -1)
1669 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1672 static void set_sound_parameters(int sound, char **parameter_raw)
1674 int parameter[NUM_SND_ARGS];
1677 /* get integer values from string parameters */
1678 for (i = 0; i < NUM_SND_ARGS; i++)
1680 get_parameter_value(parameter_raw[i],
1681 sound_config_suffix[i].token,
1682 sound_config_suffix[i].type);
1684 /* explicit loop mode setting in configuration overrides default value */
1685 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1686 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1688 /* sound volume to change the original volume when loading the sound file */
1689 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1691 /* sound priority to give certain sounds a higher or lower priority */
1692 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
1695 static void InitSoundInfo()
1697 int *sound_effect_properties;
1698 int num_sounds = getSoundListSize();
1701 checked_free(sound_info);
1703 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1704 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1706 /* initialize sound effect for all elements to "no sound" */
1707 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1708 for (j = 0; j < NUM_ACTIONS; j++)
1709 element_info[i].sound[j] = SND_UNDEFINED;
1711 for (i = 0; i < num_sounds; i++)
1713 struct FileInfo *sound = getSoundListEntry(i);
1714 int len_effect_text = strlen(sound->token);
1716 sound_effect_properties[i] = ACTION_OTHER;
1717 sound_info[i].loop = FALSE; /* default: play sound only once */
1719 /* determine all loop sounds and identify certain sound classes */
1721 for (j = 0; element_action_info[j].suffix; j++)
1723 int len_action_text = strlen(element_action_info[j].suffix);
1725 if (len_action_text < len_effect_text &&
1726 strEqual(&sound->token[len_effect_text - len_action_text],
1727 element_action_info[j].suffix))
1729 sound_effect_properties[i] = element_action_info[j].value;
1730 sound_info[i].loop = element_action_info[j].is_loop_sound;
1736 /* associate elements and some selected sound actions */
1738 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1740 if (element_info[j].class_name)
1742 int len_class_text = strlen(element_info[j].class_name);
1744 if (len_class_text + 1 < len_effect_text &&
1745 strncmp(sound->token,
1746 element_info[j].class_name, len_class_text) == 0 &&
1747 sound->token[len_class_text] == '.')
1749 int sound_action_value = sound_effect_properties[i];
1751 element_info[j].sound[sound_action_value] = i;
1756 set_sound_parameters(i, sound->parameter);
1759 free(sound_effect_properties);
1762 static void InitGameModeMusicInfo()
1764 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1765 int num_property_mappings = getMusicListPropertyMappingSize();
1766 int default_levelset_music = -1;
1769 /* set values to -1 to identify later as "uninitialized" values */
1770 for (i = 0; i < MAX_LEVELS; i++)
1771 levelset.music[i] = -1;
1772 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1775 /* initialize gamemode/music mapping from static configuration */
1776 for (i = 0; gamemode_to_music[i].music > -1; i++)
1778 int gamemode = gamemode_to_music[i].gamemode;
1779 int music = gamemode_to_music[i].music;
1782 gamemode = GAME_MODE_DEFAULT;
1784 menu.music[gamemode] = music;
1787 /* initialize gamemode/music mapping from dynamic configuration */
1788 for (i = 0; i < num_property_mappings; i++)
1790 int prefix = property_mapping[i].base_index;
1791 int gamemode = property_mapping[i].ext1_index;
1792 int level = property_mapping[i].ext2_index;
1793 int music = property_mapping[i].artwork_index;
1795 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1799 gamemode = GAME_MODE_DEFAULT;
1801 /* level specific music only allowed for in-game music */
1802 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1803 gamemode = GAME_MODE_PLAYING;
1808 default_levelset_music = music;
1811 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1812 levelset.music[level] = music;
1813 if (gamemode != GAME_MODE_PLAYING)
1814 menu.music[gamemode] = music;
1817 /* now set all '-1' values to menu specific default values */
1818 /* (undefined values of "levelset.music[]" might stay at "-1" to
1819 allow dynamic selection of music files from music directory!) */
1820 for (i = 0; i < MAX_LEVELS; i++)
1821 if (levelset.music[i] == -1)
1822 levelset.music[i] = default_levelset_music;
1823 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1824 if (menu.music[i] == -1)
1825 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1828 static void set_music_parameters(int music, char **parameter_raw)
1830 int parameter[NUM_MUS_ARGS];
1833 /* get integer values from string parameters */
1834 for (i = 0; i < NUM_MUS_ARGS; i++)
1836 get_parameter_value(parameter_raw[i],
1837 music_config_suffix[i].token,
1838 music_config_suffix[i].type);
1840 /* explicit loop mode setting in configuration overrides default value */
1841 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1842 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1845 static void InitMusicInfo()
1847 int num_music = getMusicListSize();
1850 checked_free(music_info);
1852 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1854 for (i = 0; i < num_music; i++)
1856 struct FileInfo *music = getMusicListEntry(i);
1857 int len_music_text = strlen(music->token);
1859 music_info[i].loop = TRUE; /* default: play music in loop mode */
1861 /* determine all loop music */
1863 for (j = 0; music_prefix_info[j].prefix; j++)
1865 int len_prefix_text = strlen(music_prefix_info[j].prefix);
1867 if (len_prefix_text < len_music_text &&
1868 strncmp(music->token,
1869 music_prefix_info[j].prefix, len_prefix_text) == 0)
1871 music_info[i].loop = music_prefix_info[j].is_loop_music;
1877 set_music_parameters(i, music->parameter);
1881 static void ReinitializeGraphics()
1883 print_timestamp_init("ReinitializeGraphics");
1885 InitGfxTileSizeInfo(game.tile_size, TILESIZE);
1887 InitGraphicInfo(); /* graphic properties mapping */
1888 print_timestamp_time("InitGraphicInfo");
1889 InitElementGraphicInfo(); /* element game graphic mapping */
1890 print_timestamp_time("InitElementGraphicInfo");
1891 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
1892 print_timestamp_time("InitElementSpecialGraphicInfo");
1894 InitElementSmallImages(); /* scale elements to all needed sizes */
1895 print_timestamp_time("InitElementSmallImages");
1896 InitScaledImages(); /* scale all other images, if needed */
1897 print_timestamp_time("InitScaledImages");
1898 InitFontGraphicInfo(); /* initialize text drawing functions */
1899 print_timestamp_time("InitFontGraphicInfo");
1901 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
1902 print_timestamp_time("InitGraphicInfo_EM");
1904 InitGraphicCompatibilityInfo();
1905 print_timestamp_time("InitGraphicCompatibilityInfo");
1907 SetMainBackgroundImage(IMG_BACKGROUND);
1908 print_timestamp_time("SetMainBackgroundImage");
1909 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1910 print_timestamp_time("SetDoorBackgroundImage");
1913 print_timestamp_time("InitGadgets");
1915 print_timestamp_time("InitToons");
1917 print_timestamp_time("InitDoors");
1919 print_timestamp_done("ReinitializeGraphics");
1922 static void ReinitializeSounds()
1924 InitSoundInfo(); /* sound properties mapping */
1925 InitElementSoundInfo(); /* element game sound mapping */
1926 InitGameModeSoundInfo(); /* game mode sound mapping */
1928 InitPlayLevelSound(); /* internal game sound settings */
1931 static void ReinitializeMusic()
1933 InitMusicInfo(); /* music properties mapping */
1934 InitGameModeMusicInfo(); /* game mode music mapping */
1937 static int get_special_property_bit(int element, int property_bit_nr)
1939 struct PropertyBitInfo
1945 static struct PropertyBitInfo pb_can_move_into_acid[] =
1947 /* the player may be able fall into acid when gravity is activated */
1952 { EL_SP_MURPHY, 0 },
1953 { EL_SOKOBAN_FIELD_PLAYER, 0 },
1955 /* all elements that can move may be able to also move into acid */
1958 { EL_BUG_RIGHT, 1 },
1961 { EL_SPACESHIP, 2 },
1962 { EL_SPACESHIP_LEFT, 2 },
1963 { EL_SPACESHIP_RIGHT, 2 },
1964 { EL_SPACESHIP_UP, 2 },
1965 { EL_SPACESHIP_DOWN, 2 },
1966 { EL_BD_BUTTERFLY, 3 },
1967 { EL_BD_BUTTERFLY_LEFT, 3 },
1968 { EL_BD_BUTTERFLY_RIGHT, 3 },
1969 { EL_BD_BUTTERFLY_UP, 3 },
1970 { EL_BD_BUTTERFLY_DOWN, 3 },
1971 { EL_BD_FIREFLY, 4 },
1972 { EL_BD_FIREFLY_LEFT, 4 },
1973 { EL_BD_FIREFLY_RIGHT, 4 },
1974 { EL_BD_FIREFLY_UP, 4 },
1975 { EL_BD_FIREFLY_DOWN, 4 },
1977 { EL_YAMYAM_LEFT, 5 },
1978 { EL_YAMYAM_RIGHT, 5 },
1979 { EL_YAMYAM_UP, 5 },
1980 { EL_YAMYAM_DOWN, 5 },
1981 { EL_DARK_YAMYAM, 6 },
1984 { EL_PACMAN_LEFT, 8 },
1985 { EL_PACMAN_RIGHT, 8 },
1986 { EL_PACMAN_UP, 8 },
1987 { EL_PACMAN_DOWN, 8 },
1989 { EL_MOLE_LEFT, 9 },
1990 { EL_MOLE_RIGHT, 9 },
1992 { EL_MOLE_DOWN, 9 },
1996 { EL_SATELLITE, 13 },
1997 { EL_SP_SNIKSNAK, 14 },
1998 { EL_SP_ELECTRON, 15 },
2001 { EL_EMC_ANDROID, 18 },
2006 static struct PropertyBitInfo pb_dont_collide_with[] =
2008 { EL_SP_SNIKSNAK, 0 },
2009 { EL_SP_ELECTRON, 1 },
2017 struct PropertyBitInfo *pb_info;
2020 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2021 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2026 struct PropertyBitInfo *pb_info = NULL;
2029 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2030 if (pb_definition[i].bit_nr == property_bit_nr)
2031 pb_info = pb_definition[i].pb_info;
2033 if (pb_info == NULL)
2036 for (i = 0; pb_info[i].element != -1; i++)
2037 if (pb_info[i].element == element)
2038 return pb_info[i].bit_nr;
2043 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2044 boolean property_value)
2046 int bit_nr = get_special_property_bit(element, property_bit_nr);
2051 *bitfield |= (1 << bit_nr);
2053 *bitfield &= ~(1 << bit_nr);
2057 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2059 int bit_nr = get_special_property_bit(element, property_bit_nr);
2062 return ((*bitfield & (1 << bit_nr)) != 0);
2067 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2069 static int group_nr;
2070 static struct ElementGroupInfo *group;
2071 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2074 if (actual_group == NULL) /* not yet initialized */
2077 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
2079 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2080 group_element - EL_GROUP_START + 1);
2082 /* replace element which caused too deep recursion by question mark */
2083 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2088 if (recursion_depth == 0) /* initialization */
2090 group = actual_group;
2091 group_nr = GROUP_NR(group_element);
2093 group->num_elements_resolved = 0;
2094 group->choice_pos = 0;
2096 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2097 element_info[i].in_group[group_nr] = FALSE;
2100 for (i = 0; i < actual_group->num_elements; i++)
2102 int element = actual_group->element[i];
2104 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2107 if (IS_GROUP_ELEMENT(element))
2108 ResolveGroupElementExt(element, recursion_depth + 1);
2111 group->element_resolved[group->num_elements_resolved++] = element;
2112 element_info[element].in_group[group_nr] = TRUE;
2117 void ResolveGroupElement(int group_element)
2119 ResolveGroupElementExt(group_element, 0);
2122 void InitElementPropertiesStatic()
2124 static boolean clipboard_elements_initialized = FALSE;
2126 static int ep_diggable[] =
2131 EL_SP_BUGGY_BASE_ACTIVATING,
2134 EL_INVISIBLE_SAND_ACTIVE,
2137 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2138 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2143 EL_SP_BUGGY_BASE_ACTIVE,
2150 static int ep_collectible_only[] =
2172 EL_DYNABOMB_INCREASE_NUMBER,
2173 EL_DYNABOMB_INCREASE_SIZE,
2174 EL_DYNABOMB_INCREASE_POWER,
2192 /* !!! handle separately !!! */
2193 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2199 static int ep_dont_run_into[] =
2201 /* same elements as in 'ep_dont_touch' */
2207 /* same elements as in 'ep_dont_collide_with' */
2219 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2224 EL_SP_BUGGY_BASE_ACTIVE,
2231 static int ep_dont_collide_with[] =
2233 /* same elements as in 'ep_dont_touch' */
2250 static int ep_dont_touch[] =
2260 static int ep_indestructible[] =
2264 EL_ACID_POOL_TOPLEFT,
2265 EL_ACID_POOL_TOPRIGHT,
2266 EL_ACID_POOL_BOTTOMLEFT,
2267 EL_ACID_POOL_BOTTOM,
2268 EL_ACID_POOL_BOTTOMRIGHT,
2269 EL_SP_HARDWARE_GRAY,
2270 EL_SP_HARDWARE_GREEN,
2271 EL_SP_HARDWARE_BLUE,
2273 EL_SP_HARDWARE_YELLOW,
2274 EL_SP_HARDWARE_BASE_1,
2275 EL_SP_HARDWARE_BASE_2,
2276 EL_SP_HARDWARE_BASE_3,
2277 EL_SP_HARDWARE_BASE_4,
2278 EL_SP_HARDWARE_BASE_5,
2279 EL_SP_HARDWARE_BASE_6,
2280 EL_INVISIBLE_STEELWALL,
2281 EL_INVISIBLE_STEELWALL_ACTIVE,
2282 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2283 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2284 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2285 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2286 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2287 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2288 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2289 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2290 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2291 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2292 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2293 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2295 EL_LIGHT_SWITCH_ACTIVE,
2296 EL_SIGN_EXCLAMATION,
2297 EL_SIGN_RADIOACTIVITY,
2304 EL_SIGN_ENTRY_FORBIDDEN,
2305 EL_SIGN_EMERGENCY_EXIT,
2313 EL_STEEL_EXIT_CLOSED,
2315 EL_STEEL_EXIT_OPENING,
2316 EL_STEEL_EXIT_CLOSING,
2317 EL_EM_STEEL_EXIT_CLOSED,
2318 EL_EM_STEEL_EXIT_OPEN,
2319 EL_EM_STEEL_EXIT_OPENING,
2320 EL_EM_STEEL_EXIT_CLOSING,
2321 EL_DC_STEELWALL_1_LEFT,
2322 EL_DC_STEELWALL_1_RIGHT,
2323 EL_DC_STEELWALL_1_TOP,
2324 EL_DC_STEELWALL_1_BOTTOM,
2325 EL_DC_STEELWALL_1_HORIZONTAL,
2326 EL_DC_STEELWALL_1_VERTICAL,
2327 EL_DC_STEELWALL_1_TOPLEFT,
2328 EL_DC_STEELWALL_1_TOPRIGHT,
2329 EL_DC_STEELWALL_1_BOTTOMLEFT,
2330 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2331 EL_DC_STEELWALL_1_TOPLEFT_2,
2332 EL_DC_STEELWALL_1_TOPRIGHT_2,
2333 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2334 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2335 EL_DC_STEELWALL_2_LEFT,
2336 EL_DC_STEELWALL_2_RIGHT,
2337 EL_DC_STEELWALL_2_TOP,
2338 EL_DC_STEELWALL_2_BOTTOM,
2339 EL_DC_STEELWALL_2_HORIZONTAL,
2340 EL_DC_STEELWALL_2_VERTICAL,
2341 EL_DC_STEELWALL_2_MIDDLE,
2342 EL_DC_STEELWALL_2_SINGLE,
2343 EL_STEELWALL_SLIPPERY,
2357 EL_GATE_1_GRAY_ACTIVE,
2358 EL_GATE_2_GRAY_ACTIVE,
2359 EL_GATE_3_GRAY_ACTIVE,
2360 EL_GATE_4_GRAY_ACTIVE,
2369 EL_EM_GATE_1_GRAY_ACTIVE,
2370 EL_EM_GATE_2_GRAY_ACTIVE,
2371 EL_EM_GATE_3_GRAY_ACTIVE,
2372 EL_EM_GATE_4_GRAY_ACTIVE,
2381 EL_EMC_GATE_5_GRAY_ACTIVE,
2382 EL_EMC_GATE_6_GRAY_ACTIVE,
2383 EL_EMC_GATE_7_GRAY_ACTIVE,
2384 EL_EMC_GATE_8_GRAY_ACTIVE,
2386 EL_DC_GATE_WHITE_GRAY,
2387 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2388 EL_DC_GATE_FAKE_GRAY,
2390 EL_SWITCHGATE_OPENING,
2391 EL_SWITCHGATE_CLOSED,
2392 EL_SWITCHGATE_CLOSING,
2393 EL_DC_SWITCHGATE_SWITCH_UP,
2394 EL_DC_SWITCHGATE_SWITCH_DOWN,
2396 EL_TIMEGATE_OPENING,
2398 EL_TIMEGATE_CLOSING,
2399 EL_DC_TIMEGATE_SWITCH,
2400 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2404 EL_TUBE_VERTICAL_LEFT,
2405 EL_TUBE_VERTICAL_RIGHT,
2406 EL_TUBE_HORIZONTAL_UP,
2407 EL_TUBE_HORIZONTAL_DOWN,
2412 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2413 EL_EXPANDABLE_STEELWALL_VERTICAL,
2414 EL_EXPANDABLE_STEELWALL_ANY,
2419 static int ep_slippery[] =
2433 EL_ROBOT_WHEEL_ACTIVE,
2439 EL_ACID_POOL_TOPLEFT,
2440 EL_ACID_POOL_TOPRIGHT,
2450 EL_STEELWALL_SLIPPERY,
2453 EL_EMC_WALL_SLIPPERY_1,
2454 EL_EMC_WALL_SLIPPERY_2,
2455 EL_EMC_WALL_SLIPPERY_3,
2456 EL_EMC_WALL_SLIPPERY_4,
2458 EL_EMC_MAGIC_BALL_ACTIVE,
2463 static int ep_can_change[] =
2468 static int ep_can_move[] =
2470 /* same elements as in 'pb_can_move_into_acid' */
2493 static int ep_can_fall[] =
2507 EL_QUICKSAND_FAST_FULL,
2509 EL_BD_MAGIC_WALL_FULL,
2510 EL_DC_MAGIC_WALL_FULL,
2524 static int ep_can_smash_player[] =
2550 static int ep_can_smash_enemies[] =
2559 static int ep_can_smash_everything[] =
2568 static int ep_explodes_by_fire[] =
2570 /* same elements as in 'ep_explodes_impact' */
2575 /* same elements as in 'ep_explodes_smashed' */
2585 EL_EM_DYNAMITE_ACTIVE,
2586 EL_DYNABOMB_PLAYER_1_ACTIVE,
2587 EL_DYNABOMB_PLAYER_2_ACTIVE,
2588 EL_DYNABOMB_PLAYER_3_ACTIVE,
2589 EL_DYNABOMB_PLAYER_4_ACTIVE,
2590 EL_DYNABOMB_INCREASE_NUMBER,
2591 EL_DYNABOMB_INCREASE_SIZE,
2592 EL_DYNABOMB_INCREASE_POWER,
2593 EL_SP_DISK_RED_ACTIVE,
2607 static int ep_explodes_smashed[] =
2609 /* same elements as in 'ep_explodes_impact' */
2623 static int ep_explodes_impact[] =
2632 static int ep_walkable_over[] =
2636 EL_SOKOBAN_FIELD_EMPTY,
2643 EL_EM_STEEL_EXIT_OPEN,
2644 EL_EM_STEEL_EXIT_OPENING,
2653 EL_GATE_1_GRAY_ACTIVE,
2654 EL_GATE_2_GRAY_ACTIVE,
2655 EL_GATE_3_GRAY_ACTIVE,
2656 EL_GATE_4_GRAY_ACTIVE,
2664 static int ep_walkable_inside[] =
2669 EL_TUBE_VERTICAL_LEFT,
2670 EL_TUBE_VERTICAL_RIGHT,
2671 EL_TUBE_HORIZONTAL_UP,
2672 EL_TUBE_HORIZONTAL_DOWN,
2681 static int ep_walkable_under[] =
2686 static int ep_passable_over[] =
2696 EL_EM_GATE_1_GRAY_ACTIVE,
2697 EL_EM_GATE_2_GRAY_ACTIVE,
2698 EL_EM_GATE_3_GRAY_ACTIVE,
2699 EL_EM_GATE_4_GRAY_ACTIVE,
2708 EL_EMC_GATE_5_GRAY_ACTIVE,
2709 EL_EMC_GATE_6_GRAY_ACTIVE,
2710 EL_EMC_GATE_7_GRAY_ACTIVE,
2711 EL_EMC_GATE_8_GRAY_ACTIVE,
2713 EL_DC_GATE_WHITE_GRAY,
2714 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2721 static int ep_passable_inside[] =
2727 EL_SP_PORT_HORIZONTAL,
2728 EL_SP_PORT_VERTICAL,
2730 EL_SP_GRAVITY_PORT_LEFT,
2731 EL_SP_GRAVITY_PORT_RIGHT,
2732 EL_SP_GRAVITY_PORT_UP,
2733 EL_SP_GRAVITY_PORT_DOWN,
2734 EL_SP_GRAVITY_ON_PORT_LEFT,
2735 EL_SP_GRAVITY_ON_PORT_RIGHT,
2736 EL_SP_GRAVITY_ON_PORT_UP,
2737 EL_SP_GRAVITY_ON_PORT_DOWN,
2738 EL_SP_GRAVITY_OFF_PORT_LEFT,
2739 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2740 EL_SP_GRAVITY_OFF_PORT_UP,
2741 EL_SP_GRAVITY_OFF_PORT_DOWN,
2746 static int ep_passable_under[] =
2751 static int ep_droppable[] =
2756 static int ep_explodes_1x1_old[] =
2761 static int ep_pushable[] =
2773 EL_SOKOBAN_FIELD_FULL,
2782 static int ep_explodes_cross_old[] =
2787 static int ep_protected[] =
2789 /* same elements as in 'ep_walkable_inside' */
2793 EL_TUBE_VERTICAL_LEFT,
2794 EL_TUBE_VERTICAL_RIGHT,
2795 EL_TUBE_HORIZONTAL_UP,
2796 EL_TUBE_HORIZONTAL_DOWN,
2802 /* same elements as in 'ep_passable_over' */
2811 EL_EM_GATE_1_GRAY_ACTIVE,
2812 EL_EM_GATE_2_GRAY_ACTIVE,
2813 EL_EM_GATE_3_GRAY_ACTIVE,
2814 EL_EM_GATE_4_GRAY_ACTIVE,
2823 EL_EMC_GATE_5_GRAY_ACTIVE,
2824 EL_EMC_GATE_6_GRAY_ACTIVE,
2825 EL_EMC_GATE_7_GRAY_ACTIVE,
2826 EL_EMC_GATE_8_GRAY_ACTIVE,
2828 EL_DC_GATE_WHITE_GRAY,
2829 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2833 /* same elements as in 'ep_passable_inside' */
2838 EL_SP_PORT_HORIZONTAL,
2839 EL_SP_PORT_VERTICAL,
2841 EL_SP_GRAVITY_PORT_LEFT,
2842 EL_SP_GRAVITY_PORT_RIGHT,
2843 EL_SP_GRAVITY_PORT_UP,
2844 EL_SP_GRAVITY_PORT_DOWN,
2845 EL_SP_GRAVITY_ON_PORT_LEFT,
2846 EL_SP_GRAVITY_ON_PORT_RIGHT,
2847 EL_SP_GRAVITY_ON_PORT_UP,
2848 EL_SP_GRAVITY_ON_PORT_DOWN,
2849 EL_SP_GRAVITY_OFF_PORT_LEFT,
2850 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2851 EL_SP_GRAVITY_OFF_PORT_UP,
2852 EL_SP_GRAVITY_OFF_PORT_DOWN,
2857 static int ep_throwable[] =
2862 static int ep_can_explode[] =
2864 /* same elements as in 'ep_explodes_impact' */
2869 /* same elements as in 'ep_explodes_smashed' */
2875 /* elements that can explode by explosion or by dragonfire */
2879 EL_EM_DYNAMITE_ACTIVE,
2880 EL_DYNABOMB_PLAYER_1_ACTIVE,
2881 EL_DYNABOMB_PLAYER_2_ACTIVE,
2882 EL_DYNABOMB_PLAYER_3_ACTIVE,
2883 EL_DYNABOMB_PLAYER_4_ACTIVE,
2884 EL_DYNABOMB_INCREASE_NUMBER,
2885 EL_DYNABOMB_INCREASE_SIZE,
2886 EL_DYNABOMB_INCREASE_POWER,
2887 EL_SP_DISK_RED_ACTIVE,
2895 /* elements that can explode only by explosion */
2901 static int ep_gravity_reachable[] =
2907 EL_INVISIBLE_SAND_ACTIVE,
2912 EL_SP_PORT_HORIZONTAL,
2913 EL_SP_PORT_VERTICAL,
2915 EL_SP_GRAVITY_PORT_LEFT,
2916 EL_SP_GRAVITY_PORT_RIGHT,
2917 EL_SP_GRAVITY_PORT_UP,
2918 EL_SP_GRAVITY_PORT_DOWN,
2919 EL_SP_GRAVITY_ON_PORT_LEFT,
2920 EL_SP_GRAVITY_ON_PORT_RIGHT,
2921 EL_SP_GRAVITY_ON_PORT_UP,
2922 EL_SP_GRAVITY_ON_PORT_DOWN,
2923 EL_SP_GRAVITY_OFF_PORT_LEFT,
2924 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2925 EL_SP_GRAVITY_OFF_PORT_UP,
2926 EL_SP_GRAVITY_OFF_PORT_DOWN,
2932 static int ep_player[] =
2939 EL_SOKOBAN_FIELD_PLAYER,
2945 static int ep_can_pass_magic_wall[] =
2959 static int ep_can_pass_dc_magic_wall[] =
2975 static int ep_switchable[] =
2979 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2980 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2981 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2982 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2983 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2984 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2985 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2986 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2987 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2988 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2989 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2990 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2991 EL_SWITCHGATE_SWITCH_UP,
2992 EL_SWITCHGATE_SWITCH_DOWN,
2993 EL_DC_SWITCHGATE_SWITCH_UP,
2994 EL_DC_SWITCHGATE_SWITCH_DOWN,
2996 EL_LIGHT_SWITCH_ACTIVE,
2998 EL_DC_TIMEGATE_SWITCH,
2999 EL_BALLOON_SWITCH_LEFT,
3000 EL_BALLOON_SWITCH_RIGHT,
3001 EL_BALLOON_SWITCH_UP,
3002 EL_BALLOON_SWITCH_DOWN,
3003 EL_BALLOON_SWITCH_ANY,
3004 EL_BALLOON_SWITCH_NONE,
3007 EL_EMC_MAGIC_BALL_SWITCH,
3008 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3013 static int ep_bd_element[] =
3047 static int ep_sp_element[] =
3049 /* should always be valid */
3052 /* standard classic Supaplex elements */
3059 EL_SP_HARDWARE_GRAY,
3067 EL_SP_GRAVITY_PORT_RIGHT,
3068 EL_SP_GRAVITY_PORT_DOWN,
3069 EL_SP_GRAVITY_PORT_LEFT,
3070 EL_SP_GRAVITY_PORT_UP,
3075 EL_SP_PORT_VERTICAL,
3076 EL_SP_PORT_HORIZONTAL,
3082 EL_SP_HARDWARE_BASE_1,
3083 EL_SP_HARDWARE_GREEN,
3084 EL_SP_HARDWARE_BLUE,
3086 EL_SP_HARDWARE_YELLOW,
3087 EL_SP_HARDWARE_BASE_2,
3088 EL_SP_HARDWARE_BASE_3,
3089 EL_SP_HARDWARE_BASE_4,
3090 EL_SP_HARDWARE_BASE_5,
3091 EL_SP_HARDWARE_BASE_6,
3095 /* additional elements that appeared in newer Supaplex levels */
3098 /* additional gravity port elements (not switching, but setting gravity) */
3099 EL_SP_GRAVITY_ON_PORT_LEFT,
3100 EL_SP_GRAVITY_ON_PORT_RIGHT,
3101 EL_SP_GRAVITY_ON_PORT_UP,
3102 EL_SP_GRAVITY_ON_PORT_DOWN,
3103 EL_SP_GRAVITY_OFF_PORT_LEFT,
3104 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3105 EL_SP_GRAVITY_OFF_PORT_UP,
3106 EL_SP_GRAVITY_OFF_PORT_DOWN,
3108 /* more than one Murphy in a level results in an inactive clone */
3111 /* runtime Supaplex elements */
3112 EL_SP_DISK_RED_ACTIVE,
3113 EL_SP_TERMINAL_ACTIVE,
3114 EL_SP_BUGGY_BASE_ACTIVATING,
3115 EL_SP_BUGGY_BASE_ACTIVE,
3122 static int ep_sb_element[] =
3127 EL_SOKOBAN_FIELD_EMPTY,
3128 EL_SOKOBAN_FIELD_FULL,
3129 EL_SOKOBAN_FIELD_PLAYER,
3134 EL_INVISIBLE_STEELWALL,
3139 static int ep_gem[] =
3151 static int ep_food_dark_yamyam[] =
3179 static int ep_food_penguin[] =
3193 static int ep_food_pig[] =
3205 static int ep_historic_wall[] =
3216 EL_GATE_1_GRAY_ACTIVE,
3217 EL_GATE_2_GRAY_ACTIVE,
3218 EL_GATE_3_GRAY_ACTIVE,
3219 EL_GATE_4_GRAY_ACTIVE,
3228 EL_EM_GATE_1_GRAY_ACTIVE,
3229 EL_EM_GATE_2_GRAY_ACTIVE,
3230 EL_EM_GATE_3_GRAY_ACTIVE,
3231 EL_EM_GATE_4_GRAY_ACTIVE,
3238 EL_EXPANDABLE_WALL_HORIZONTAL,
3239 EL_EXPANDABLE_WALL_VERTICAL,
3240 EL_EXPANDABLE_WALL_ANY,
3241 EL_EXPANDABLE_WALL_GROWING,
3242 EL_BD_EXPANDABLE_WALL,
3249 EL_SP_HARDWARE_GRAY,
3250 EL_SP_HARDWARE_GREEN,
3251 EL_SP_HARDWARE_BLUE,
3253 EL_SP_HARDWARE_YELLOW,
3254 EL_SP_HARDWARE_BASE_1,
3255 EL_SP_HARDWARE_BASE_2,
3256 EL_SP_HARDWARE_BASE_3,
3257 EL_SP_HARDWARE_BASE_4,
3258 EL_SP_HARDWARE_BASE_5,
3259 EL_SP_HARDWARE_BASE_6,
3261 EL_SP_TERMINAL_ACTIVE,
3264 EL_INVISIBLE_STEELWALL,
3265 EL_INVISIBLE_STEELWALL_ACTIVE,
3267 EL_INVISIBLE_WALL_ACTIVE,
3268 EL_STEELWALL_SLIPPERY,
3285 static int ep_historic_solid[] =
3289 EL_EXPANDABLE_WALL_HORIZONTAL,
3290 EL_EXPANDABLE_WALL_VERTICAL,
3291 EL_EXPANDABLE_WALL_ANY,
3292 EL_BD_EXPANDABLE_WALL,
3305 EL_QUICKSAND_FILLING,
3306 EL_QUICKSAND_EMPTYING,
3308 EL_MAGIC_WALL_ACTIVE,
3309 EL_MAGIC_WALL_EMPTYING,
3310 EL_MAGIC_WALL_FILLING,
3314 EL_BD_MAGIC_WALL_ACTIVE,
3315 EL_BD_MAGIC_WALL_EMPTYING,
3316 EL_BD_MAGIC_WALL_FULL,
3317 EL_BD_MAGIC_WALL_FILLING,
3318 EL_BD_MAGIC_WALL_DEAD,
3327 EL_SP_TERMINAL_ACTIVE,
3331 EL_INVISIBLE_WALL_ACTIVE,
3332 EL_SWITCHGATE_SWITCH_UP,
3333 EL_SWITCHGATE_SWITCH_DOWN,
3334 EL_DC_SWITCHGATE_SWITCH_UP,
3335 EL_DC_SWITCHGATE_SWITCH_DOWN,
3337 EL_TIMEGATE_SWITCH_ACTIVE,
3338 EL_DC_TIMEGATE_SWITCH,
3339 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3351 /* the following elements are a direct copy of "indestructible" elements,
3352 except "EL_ACID", which is "indestructible", but not "solid"! */
3357 EL_ACID_POOL_TOPLEFT,
3358 EL_ACID_POOL_TOPRIGHT,
3359 EL_ACID_POOL_BOTTOMLEFT,
3360 EL_ACID_POOL_BOTTOM,
3361 EL_ACID_POOL_BOTTOMRIGHT,
3362 EL_SP_HARDWARE_GRAY,
3363 EL_SP_HARDWARE_GREEN,
3364 EL_SP_HARDWARE_BLUE,
3366 EL_SP_HARDWARE_YELLOW,
3367 EL_SP_HARDWARE_BASE_1,
3368 EL_SP_HARDWARE_BASE_2,
3369 EL_SP_HARDWARE_BASE_3,
3370 EL_SP_HARDWARE_BASE_4,
3371 EL_SP_HARDWARE_BASE_5,
3372 EL_SP_HARDWARE_BASE_6,
3373 EL_INVISIBLE_STEELWALL,
3374 EL_INVISIBLE_STEELWALL_ACTIVE,
3375 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3376 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3377 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3378 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3379 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3380 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3381 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3382 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3383 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3384 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3385 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3386 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3388 EL_LIGHT_SWITCH_ACTIVE,
3389 EL_SIGN_EXCLAMATION,
3390 EL_SIGN_RADIOACTIVITY,
3397 EL_SIGN_ENTRY_FORBIDDEN,
3398 EL_SIGN_EMERGENCY_EXIT,
3406 EL_STEEL_EXIT_CLOSED,
3408 EL_DC_STEELWALL_1_LEFT,
3409 EL_DC_STEELWALL_1_RIGHT,
3410 EL_DC_STEELWALL_1_TOP,
3411 EL_DC_STEELWALL_1_BOTTOM,
3412 EL_DC_STEELWALL_1_HORIZONTAL,
3413 EL_DC_STEELWALL_1_VERTICAL,
3414 EL_DC_STEELWALL_1_TOPLEFT,
3415 EL_DC_STEELWALL_1_TOPRIGHT,
3416 EL_DC_STEELWALL_1_BOTTOMLEFT,
3417 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3418 EL_DC_STEELWALL_1_TOPLEFT_2,
3419 EL_DC_STEELWALL_1_TOPRIGHT_2,
3420 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3421 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3422 EL_DC_STEELWALL_2_LEFT,
3423 EL_DC_STEELWALL_2_RIGHT,
3424 EL_DC_STEELWALL_2_TOP,
3425 EL_DC_STEELWALL_2_BOTTOM,
3426 EL_DC_STEELWALL_2_HORIZONTAL,
3427 EL_DC_STEELWALL_2_VERTICAL,
3428 EL_DC_STEELWALL_2_MIDDLE,
3429 EL_DC_STEELWALL_2_SINGLE,
3430 EL_STEELWALL_SLIPPERY,
3444 EL_GATE_1_GRAY_ACTIVE,
3445 EL_GATE_2_GRAY_ACTIVE,
3446 EL_GATE_3_GRAY_ACTIVE,
3447 EL_GATE_4_GRAY_ACTIVE,
3456 EL_EM_GATE_1_GRAY_ACTIVE,
3457 EL_EM_GATE_2_GRAY_ACTIVE,
3458 EL_EM_GATE_3_GRAY_ACTIVE,
3459 EL_EM_GATE_4_GRAY_ACTIVE,
3461 EL_SWITCHGATE_OPENING,
3462 EL_SWITCHGATE_CLOSED,
3463 EL_SWITCHGATE_CLOSING,
3465 EL_TIMEGATE_OPENING,
3467 EL_TIMEGATE_CLOSING,
3471 EL_TUBE_VERTICAL_LEFT,
3472 EL_TUBE_VERTICAL_RIGHT,
3473 EL_TUBE_HORIZONTAL_UP,
3474 EL_TUBE_HORIZONTAL_DOWN,
3483 static int ep_classic_enemy[] =
3500 static int ep_belt[] =
3502 EL_CONVEYOR_BELT_1_LEFT,
3503 EL_CONVEYOR_BELT_1_MIDDLE,
3504 EL_CONVEYOR_BELT_1_RIGHT,
3505 EL_CONVEYOR_BELT_2_LEFT,
3506 EL_CONVEYOR_BELT_2_MIDDLE,
3507 EL_CONVEYOR_BELT_2_RIGHT,
3508 EL_CONVEYOR_BELT_3_LEFT,
3509 EL_CONVEYOR_BELT_3_MIDDLE,
3510 EL_CONVEYOR_BELT_3_RIGHT,
3511 EL_CONVEYOR_BELT_4_LEFT,
3512 EL_CONVEYOR_BELT_4_MIDDLE,
3513 EL_CONVEYOR_BELT_4_RIGHT,
3518 static int ep_belt_active[] =
3520 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3521 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3522 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3523 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3524 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3525 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3526 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3527 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3528 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3529 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3530 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3531 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3536 static int ep_belt_switch[] =
3538 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3539 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3540 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3541 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3542 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3543 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3544 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3545 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3546 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3547 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3548 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3549 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3554 static int ep_tube[] =
3561 EL_TUBE_HORIZONTAL_UP,
3562 EL_TUBE_HORIZONTAL_DOWN,
3564 EL_TUBE_VERTICAL_LEFT,
3565 EL_TUBE_VERTICAL_RIGHT,
3571 static int ep_acid_pool[] =
3573 EL_ACID_POOL_TOPLEFT,
3574 EL_ACID_POOL_TOPRIGHT,
3575 EL_ACID_POOL_BOTTOMLEFT,
3576 EL_ACID_POOL_BOTTOM,
3577 EL_ACID_POOL_BOTTOMRIGHT,
3582 static int ep_keygate[] =
3592 EL_GATE_1_GRAY_ACTIVE,
3593 EL_GATE_2_GRAY_ACTIVE,
3594 EL_GATE_3_GRAY_ACTIVE,
3595 EL_GATE_4_GRAY_ACTIVE,
3604 EL_EM_GATE_1_GRAY_ACTIVE,
3605 EL_EM_GATE_2_GRAY_ACTIVE,
3606 EL_EM_GATE_3_GRAY_ACTIVE,
3607 EL_EM_GATE_4_GRAY_ACTIVE,
3616 EL_EMC_GATE_5_GRAY_ACTIVE,
3617 EL_EMC_GATE_6_GRAY_ACTIVE,
3618 EL_EMC_GATE_7_GRAY_ACTIVE,
3619 EL_EMC_GATE_8_GRAY_ACTIVE,
3621 EL_DC_GATE_WHITE_GRAY,
3622 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3627 static int ep_amoeboid[] =
3639 static int ep_amoebalive[] =
3650 static int ep_has_editor_content[] =
3656 EL_SOKOBAN_FIELD_PLAYER,
3673 static int ep_can_turn_each_move[] =
3675 /* !!! do something with this one !!! */
3679 static int ep_can_grow[] =
3693 static int ep_active_bomb[] =
3696 EL_EM_DYNAMITE_ACTIVE,
3697 EL_DYNABOMB_PLAYER_1_ACTIVE,
3698 EL_DYNABOMB_PLAYER_2_ACTIVE,
3699 EL_DYNABOMB_PLAYER_3_ACTIVE,
3700 EL_DYNABOMB_PLAYER_4_ACTIVE,
3701 EL_SP_DISK_RED_ACTIVE,
3706 static int ep_inactive[] =
3716 EL_QUICKSAND_FAST_EMPTY,
3739 EL_GATE_1_GRAY_ACTIVE,
3740 EL_GATE_2_GRAY_ACTIVE,
3741 EL_GATE_3_GRAY_ACTIVE,
3742 EL_GATE_4_GRAY_ACTIVE,
3751 EL_EM_GATE_1_GRAY_ACTIVE,
3752 EL_EM_GATE_2_GRAY_ACTIVE,
3753 EL_EM_GATE_3_GRAY_ACTIVE,
3754 EL_EM_GATE_4_GRAY_ACTIVE,
3763 EL_EMC_GATE_5_GRAY_ACTIVE,
3764 EL_EMC_GATE_6_GRAY_ACTIVE,
3765 EL_EMC_GATE_7_GRAY_ACTIVE,
3766 EL_EMC_GATE_8_GRAY_ACTIVE,
3768 EL_DC_GATE_WHITE_GRAY,
3769 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3770 EL_DC_GATE_FAKE_GRAY,
3773 EL_INVISIBLE_STEELWALL,
3781 EL_WALL_EMERALD_YELLOW,
3782 EL_DYNABOMB_INCREASE_NUMBER,
3783 EL_DYNABOMB_INCREASE_SIZE,
3784 EL_DYNABOMB_INCREASE_POWER,
3788 EL_SOKOBAN_FIELD_EMPTY,
3789 EL_SOKOBAN_FIELD_FULL,
3790 EL_WALL_EMERALD_RED,
3791 EL_WALL_EMERALD_PURPLE,
3792 EL_ACID_POOL_TOPLEFT,
3793 EL_ACID_POOL_TOPRIGHT,
3794 EL_ACID_POOL_BOTTOMLEFT,
3795 EL_ACID_POOL_BOTTOM,
3796 EL_ACID_POOL_BOTTOMRIGHT,
3800 EL_BD_MAGIC_WALL_DEAD,
3802 EL_DC_MAGIC_WALL_DEAD,
3803 EL_AMOEBA_TO_DIAMOND,
3811 EL_SP_GRAVITY_PORT_RIGHT,
3812 EL_SP_GRAVITY_PORT_DOWN,
3813 EL_SP_GRAVITY_PORT_LEFT,
3814 EL_SP_GRAVITY_PORT_UP,
3815 EL_SP_PORT_HORIZONTAL,
3816 EL_SP_PORT_VERTICAL,
3827 EL_SP_HARDWARE_GRAY,
3828 EL_SP_HARDWARE_GREEN,
3829 EL_SP_HARDWARE_BLUE,
3831 EL_SP_HARDWARE_YELLOW,
3832 EL_SP_HARDWARE_BASE_1,
3833 EL_SP_HARDWARE_BASE_2,
3834 EL_SP_HARDWARE_BASE_3,
3835 EL_SP_HARDWARE_BASE_4,
3836 EL_SP_HARDWARE_BASE_5,
3837 EL_SP_HARDWARE_BASE_6,
3838 EL_SP_GRAVITY_ON_PORT_LEFT,
3839 EL_SP_GRAVITY_ON_PORT_RIGHT,
3840 EL_SP_GRAVITY_ON_PORT_UP,
3841 EL_SP_GRAVITY_ON_PORT_DOWN,
3842 EL_SP_GRAVITY_OFF_PORT_LEFT,
3843 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3844 EL_SP_GRAVITY_OFF_PORT_UP,
3845 EL_SP_GRAVITY_OFF_PORT_DOWN,
3846 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3847 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3848 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3849 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3850 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3851 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3852 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3853 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3854 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3855 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3856 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3857 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3858 EL_SIGN_EXCLAMATION,
3859 EL_SIGN_RADIOACTIVITY,
3866 EL_SIGN_ENTRY_FORBIDDEN,
3867 EL_SIGN_EMERGENCY_EXIT,
3875 EL_DC_STEELWALL_1_LEFT,
3876 EL_DC_STEELWALL_1_RIGHT,
3877 EL_DC_STEELWALL_1_TOP,
3878 EL_DC_STEELWALL_1_BOTTOM,
3879 EL_DC_STEELWALL_1_HORIZONTAL,
3880 EL_DC_STEELWALL_1_VERTICAL,
3881 EL_DC_STEELWALL_1_TOPLEFT,
3882 EL_DC_STEELWALL_1_TOPRIGHT,
3883 EL_DC_STEELWALL_1_BOTTOMLEFT,
3884 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3885 EL_DC_STEELWALL_1_TOPLEFT_2,
3886 EL_DC_STEELWALL_1_TOPRIGHT_2,
3887 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3888 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3889 EL_DC_STEELWALL_2_LEFT,
3890 EL_DC_STEELWALL_2_RIGHT,
3891 EL_DC_STEELWALL_2_TOP,
3892 EL_DC_STEELWALL_2_BOTTOM,
3893 EL_DC_STEELWALL_2_HORIZONTAL,
3894 EL_DC_STEELWALL_2_VERTICAL,
3895 EL_DC_STEELWALL_2_MIDDLE,
3896 EL_DC_STEELWALL_2_SINGLE,
3897 EL_STEELWALL_SLIPPERY,
3902 EL_EMC_WALL_SLIPPERY_1,
3903 EL_EMC_WALL_SLIPPERY_2,
3904 EL_EMC_WALL_SLIPPERY_3,
3905 EL_EMC_WALL_SLIPPERY_4,
3926 static int ep_em_slippery_wall[] =
3931 static int ep_gfx_crumbled[] =
3942 static int ep_editor_cascade_active[] =
3944 EL_INTERNAL_CASCADE_BD_ACTIVE,
3945 EL_INTERNAL_CASCADE_EM_ACTIVE,
3946 EL_INTERNAL_CASCADE_EMC_ACTIVE,
3947 EL_INTERNAL_CASCADE_RND_ACTIVE,
3948 EL_INTERNAL_CASCADE_SB_ACTIVE,
3949 EL_INTERNAL_CASCADE_SP_ACTIVE,
3950 EL_INTERNAL_CASCADE_DC_ACTIVE,
3951 EL_INTERNAL_CASCADE_DX_ACTIVE,
3952 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
3953 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
3954 EL_INTERNAL_CASCADE_CE_ACTIVE,
3955 EL_INTERNAL_CASCADE_GE_ACTIVE,
3956 EL_INTERNAL_CASCADE_REF_ACTIVE,
3957 EL_INTERNAL_CASCADE_USER_ACTIVE,
3958 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
3963 static int ep_editor_cascade_inactive[] =
3965 EL_INTERNAL_CASCADE_BD,
3966 EL_INTERNAL_CASCADE_EM,
3967 EL_INTERNAL_CASCADE_EMC,
3968 EL_INTERNAL_CASCADE_RND,
3969 EL_INTERNAL_CASCADE_SB,
3970 EL_INTERNAL_CASCADE_SP,
3971 EL_INTERNAL_CASCADE_DC,
3972 EL_INTERNAL_CASCADE_DX,
3973 EL_INTERNAL_CASCADE_CHARS,
3974 EL_INTERNAL_CASCADE_STEEL_CHARS,
3975 EL_INTERNAL_CASCADE_CE,
3976 EL_INTERNAL_CASCADE_GE,
3977 EL_INTERNAL_CASCADE_REF,
3978 EL_INTERNAL_CASCADE_USER,
3979 EL_INTERNAL_CASCADE_DYNAMIC,
3984 static int ep_obsolete[] =
3988 EL_EM_KEY_1_FILE_OBSOLETE,
3989 EL_EM_KEY_2_FILE_OBSOLETE,
3990 EL_EM_KEY_3_FILE_OBSOLETE,
3991 EL_EM_KEY_4_FILE_OBSOLETE,
3992 EL_ENVELOPE_OBSOLETE,
4001 } element_properties[] =
4003 { ep_diggable, EP_DIGGABLE },
4004 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4005 { ep_dont_run_into, EP_DONT_RUN_INTO },
4006 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4007 { ep_dont_touch, EP_DONT_TOUCH },
4008 { ep_indestructible, EP_INDESTRUCTIBLE },
4009 { ep_slippery, EP_SLIPPERY },
4010 { ep_can_change, EP_CAN_CHANGE },
4011 { ep_can_move, EP_CAN_MOVE },
4012 { ep_can_fall, EP_CAN_FALL },
4013 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4014 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4015 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4016 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4017 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4018 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4019 { ep_walkable_over, EP_WALKABLE_OVER },
4020 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4021 { ep_walkable_under, EP_WALKABLE_UNDER },
4022 { ep_passable_over, EP_PASSABLE_OVER },
4023 { ep_passable_inside, EP_PASSABLE_INSIDE },
4024 { ep_passable_under, EP_PASSABLE_UNDER },
4025 { ep_droppable, EP_DROPPABLE },
4026 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4027 { ep_pushable, EP_PUSHABLE },
4028 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4029 { ep_protected, EP_PROTECTED },
4030 { ep_throwable, EP_THROWABLE },
4031 { ep_can_explode, EP_CAN_EXPLODE },
4032 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4034 { ep_player, EP_PLAYER },
4035 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4036 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4037 { ep_switchable, EP_SWITCHABLE },
4038 { ep_bd_element, EP_BD_ELEMENT },
4039 { ep_sp_element, EP_SP_ELEMENT },
4040 { ep_sb_element, EP_SB_ELEMENT },
4042 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4043 { ep_food_penguin, EP_FOOD_PENGUIN },
4044 { ep_food_pig, EP_FOOD_PIG },
4045 { ep_historic_wall, EP_HISTORIC_WALL },
4046 { ep_historic_solid, EP_HISTORIC_SOLID },
4047 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4048 { ep_belt, EP_BELT },
4049 { ep_belt_active, EP_BELT_ACTIVE },
4050 { ep_belt_switch, EP_BELT_SWITCH },
4051 { ep_tube, EP_TUBE },
4052 { ep_acid_pool, EP_ACID_POOL },
4053 { ep_keygate, EP_KEYGATE },
4054 { ep_amoeboid, EP_AMOEBOID },
4055 { ep_amoebalive, EP_AMOEBALIVE },
4056 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4057 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4058 { ep_can_grow, EP_CAN_GROW },
4059 { ep_active_bomb, EP_ACTIVE_BOMB },
4060 { ep_inactive, EP_INACTIVE },
4062 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4064 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4066 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4067 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4069 { ep_obsolete, EP_OBSOLETE },
4076 /* always start with reliable default values (element has no properties) */
4077 /* (but never initialize clipboard elements after the very first time) */
4078 /* (to be able to use clipboard elements between several levels) */
4079 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4080 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4081 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4082 SET_PROPERTY(i, j, FALSE);
4084 /* set all base element properties from above array definitions */
4085 for (i = 0; element_properties[i].elements != NULL; i++)
4086 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4087 SET_PROPERTY((element_properties[i].elements)[j],
4088 element_properties[i].property, TRUE);
4090 /* copy properties to some elements that are only stored in level file */
4091 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4092 for (j = 0; copy_properties[j][0] != -1; j++)
4093 if (HAS_PROPERTY(copy_properties[j][0], i))
4094 for (k = 1; k <= 4; k++)
4095 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4097 /* set static element properties that are not listed in array definitions */
4098 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4099 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4101 clipboard_elements_initialized = TRUE;
4104 void InitElementPropertiesEngine(int engine_version)
4106 static int no_wall_properties[] =
4109 EP_COLLECTIBLE_ONLY,
4111 EP_DONT_COLLIDE_WITH,
4114 EP_CAN_SMASH_PLAYER,
4115 EP_CAN_SMASH_ENEMIES,
4116 EP_CAN_SMASH_EVERYTHING,
4121 EP_FOOD_DARK_YAMYAM,
4137 /* important: after initialization in InitElementPropertiesStatic(), the
4138 elements are not again initialized to a default value; therefore all
4139 changes have to make sure that they leave the element with a defined
4140 property (which means that conditional property changes must be set to
4141 a reliable default value before) */
4143 /* resolve group elements */
4144 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4145 ResolveGroupElement(EL_GROUP_START + i);
4147 /* set all special, combined or engine dependent element properties */
4148 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4150 /* do not change (already initialized) clipboard elements here */
4151 if (IS_CLIPBOARD_ELEMENT(i))
4154 /* ---------- INACTIVE ------------------------------------------------- */
4155 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4156 i <= EL_CHAR_END) ||
4157 (i >= EL_STEEL_CHAR_START &&
4158 i <= EL_STEEL_CHAR_END)));
4160 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4161 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4162 IS_WALKABLE_INSIDE(i) ||
4163 IS_WALKABLE_UNDER(i)));
4165 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4166 IS_PASSABLE_INSIDE(i) ||
4167 IS_PASSABLE_UNDER(i)));
4169 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4170 IS_PASSABLE_OVER(i)));
4172 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4173 IS_PASSABLE_INSIDE(i)));
4175 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4176 IS_PASSABLE_UNDER(i)));
4178 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4181 /* ---------- COLLECTIBLE ---------------------------------------------- */
4182 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4186 /* ---------- SNAPPABLE ------------------------------------------------ */
4187 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4188 IS_COLLECTIBLE(i) ||
4192 /* ---------- WALL ----------------------------------------------------- */
4193 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4195 for (j = 0; no_wall_properties[j] != -1; j++)
4196 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4197 i >= EL_FIRST_RUNTIME_UNREAL)
4198 SET_PROPERTY(i, EP_WALL, FALSE);
4200 if (IS_HISTORIC_WALL(i))
4201 SET_PROPERTY(i, EP_WALL, TRUE);
4203 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4204 if (engine_version < VERSION_IDENT(2,2,0,0))
4205 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4207 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4209 !IS_COLLECTIBLE(i)));
4211 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4212 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4213 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4215 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4216 IS_INDESTRUCTIBLE(i)));
4218 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4220 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4221 else if (engine_version < VERSION_IDENT(2,2,0,0))
4222 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4224 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4228 if (IS_CUSTOM_ELEMENT(i))
4230 /* these are additional properties which are initially false when set */
4232 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4234 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4235 if (DONT_COLLIDE_WITH(i))
4236 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4238 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4239 if (CAN_SMASH_EVERYTHING(i))
4240 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4241 if (CAN_SMASH_ENEMIES(i))
4242 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4245 /* ---------- CAN_SMASH ------------------------------------------------ */
4246 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4247 CAN_SMASH_ENEMIES(i) ||
4248 CAN_SMASH_EVERYTHING(i)));
4250 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4251 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4252 EXPLODES_BY_FIRE(i)));
4254 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4255 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4256 EXPLODES_SMASHED(i)));
4258 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4259 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4260 EXPLODES_IMPACT(i)));
4262 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4263 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4265 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4266 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4267 i == EL_BLACK_ORB));
4269 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4270 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4272 IS_CUSTOM_ELEMENT(i)));
4274 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4275 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4276 i == EL_SP_ELECTRON));
4278 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4279 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4280 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4281 getMoveIntoAcidProperty(&level, i));
4283 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4284 if (MAYBE_DONT_COLLIDE_WITH(i))
4285 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4286 getDontCollideWithProperty(&level, i));
4288 /* ---------- SP_PORT -------------------------------------------------- */
4289 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4290 IS_PASSABLE_INSIDE(i)));
4292 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4293 for (j = 0; j < level.num_android_clone_elements; j++)
4294 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4296 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4298 /* ---------- CAN_CHANGE ----------------------------------------------- */
4299 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4300 for (j = 0; j < element_info[i].num_change_pages; j++)
4301 if (element_info[i].change_page[j].can_change)
4302 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4304 /* ---------- HAS_ACTION ----------------------------------------------- */
4305 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4306 for (j = 0; j < element_info[i].num_change_pages; j++)
4307 if (element_info[i].change_page[j].has_action)
4308 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4310 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4311 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4314 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4315 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4316 element_info[i].crumbled[ACTION_DEFAULT] !=
4317 element_info[i].graphic[ACTION_DEFAULT]);
4319 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4320 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4321 IS_EDITOR_CASCADE_INACTIVE(i)));
4324 /* dynamically adjust element properties according to game engine version */
4326 static int ep_em_slippery_wall[] =
4331 EL_EXPANDABLE_WALL_HORIZONTAL,
4332 EL_EXPANDABLE_WALL_VERTICAL,
4333 EL_EXPANDABLE_WALL_ANY,
4334 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4335 EL_EXPANDABLE_STEELWALL_VERTICAL,
4336 EL_EXPANDABLE_STEELWALL_ANY,
4337 EL_EXPANDABLE_STEELWALL_GROWING,
4341 static int ep_em_explodes_by_fire[] =
4344 EL_EM_DYNAMITE_ACTIVE,
4349 /* special EM style gems behaviour */
4350 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4351 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4352 level.em_slippery_gems);
4354 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4355 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4356 (level.em_slippery_gems &&
4357 engine_version > VERSION_IDENT(2,0,1,0)));
4359 /* special EM style explosion behaviour regarding chain reactions */
4360 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4361 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4362 level.em_explodes_by_fire);
4365 /* this is needed because some graphics depend on element properties */
4366 if (game_status == GAME_MODE_PLAYING)
4367 InitElementGraphicInfo();
4370 void InitElementPropertiesAfterLoading(int engine_version)
4374 /* set some other uninitialized values of custom elements in older levels */
4375 if (engine_version < VERSION_IDENT(3,1,0,0))
4377 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4379 int element = EL_CUSTOM_START + i;
4381 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4383 element_info[element].explosion_delay = 17;
4384 element_info[element].ignition_delay = 8;
4389 void InitElementPropertiesGfxElement()
4393 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4395 struct ElementInfo *ei = &element_info[i];
4397 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4401 static void InitGlobal()
4406 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4408 /* check if element_name_info entry defined for each element in "main.h" */
4409 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4410 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4412 element_info[i].token_name = element_name_info[i].token_name;
4413 element_info[i].class_name = element_name_info[i].class_name;
4414 element_info[i].editor_description= element_name_info[i].editor_description;
4417 /* create hash from image config list */
4418 image_config_hash = newSetupFileHash();
4419 for (i = 0; image_config[i].token != NULL; i++)
4420 setHashEntry(image_config_hash,
4421 image_config[i].token,
4422 image_config[i].value);
4424 /* create hash from element token list */
4425 element_token_hash = newSetupFileHash();
4426 for (i = 0; element_name_info[i].token_name != NULL; i++)
4427 setHashEntry(element_token_hash,
4428 element_name_info[i].token_name,
4431 /* create hash from graphic token list */
4432 graphic_token_hash = newSetupFileHash();
4433 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4434 if (strSuffix(image_config[i].value, ".png") ||
4435 strSuffix(image_config[i].value, ".pcx") ||
4436 strSuffix(image_config[i].value, ".wav") ||
4437 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4438 setHashEntry(graphic_token_hash,
4439 image_config[i].token,
4440 int2str(graphic++, 0));
4442 /* create hash from font token list */
4443 font_token_hash = newSetupFileHash();
4444 for (i = 0; font_info[i].token_name != NULL; i++)
4445 setHashEntry(font_token_hash,
4446 font_info[i].token_name,
4449 /* always start with reliable default values (all elements) */
4450 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4451 ActiveElement[i] = i;
4453 /* now add all entries that have an active state (active elements) */
4454 for (i = 0; element_with_active_state[i].element != -1; i++)
4456 int element = element_with_active_state[i].element;
4457 int element_active = element_with_active_state[i].element_active;
4459 ActiveElement[element] = element_active;
4462 /* always start with reliable default values (all buttons) */
4463 for (i = 0; i < NUM_IMAGE_FILES; i++)
4464 ActiveButton[i] = i;
4466 /* now add all entries that have an active state (active buttons) */
4467 for (i = 0; button_with_active_state[i].button != -1; i++)
4469 int button = button_with_active_state[i].button;
4470 int button_active = button_with_active_state[i].button_active;
4472 ActiveButton[button] = button_active;
4475 /* always start with reliable default values (all fonts) */
4476 for (i = 0; i < NUM_FONTS; i++)
4479 /* now add all entries that have an active state (active fonts) */
4480 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4482 int font = font_with_active_state[i].font_nr;
4483 int font_active = font_with_active_state[i].font_nr_active;
4485 ActiveFont[font] = font_active;
4488 global.autoplay_leveldir = NULL;
4489 global.convert_leveldir = NULL;
4490 global.create_images_dir = NULL;
4492 global.frames_per_second = 0;
4493 global.fps_slowdown = FALSE;
4494 global.fps_slowdown_factor = 1;
4496 global.border_status = GAME_MODE_MAIN;
4498 global.use_envelope_request = FALSE;
4501 void Execute_Command(char *command)
4505 if (strEqual(command, "print graphicsinfo.conf"))
4507 printf("# You can configure additional/alternative image files here.\n");
4508 printf("# (The entries below are default and therefore commented out.)\n");
4510 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4512 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4515 for (i = 0; image_config[i].token != NULL; i++)
4516 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
4517 image_config[i].value));
4521 else if (strEqual(command, "print soundsinfo.conf"))
4523 printf("# You can configure additional/alternative sound files here.\n");
4524 printf("# (The entries below are default and therefore commented out.)\n");
4526 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4528 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4531 for (i = 0; sound_config[i].token != NULL; i++)
4532 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4533 sound_config[i].value));
4537 else if (strEqual(command, "print musicinfo.conf"))
4539 printf("# You can configure additional/alternative music files here.\n");
4540 printf("# (The entries below are default and therefore commented out.)\n");
4542 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4544 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4547 for (i = 0; music_config[i].token != NULL; i++)
4548 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
4549 music_config[i].value));
4553 else if (strEqual(command, "print editorsetup.conf"))
4555 printf("# You can configure your personal editor element list here.\n");
4556 printf("# (The entries below are default and therefore commented out.)\n");
4559 /* this is needed to be able to check element list for cascade elements */
4560 InitElementPropertiesStatic();
4561 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4563 PrintEditorElementList();
4567 else if (strEqual(command, "print helpanim.conf"))
4569 printf("# You can configure different element help animations here.\n");
4570 printf("# (The entries below are default and therefore commented out.)\n");
4573 for (i = 0; helpanim_config[i].token != NULL; i++)
4575 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4576 helpanim_config[i].value));
4578 if (strEqual(helpanim_config[i].token, "end"))
4584 else if (strEqual(command, "print helptext.conf"))
4586 printf("# You can configure different element help text here.\n");
4587 printf("# (The entries below are default and therefore commented out.)\n");
4590 for (i = 0; helptext_config[i].token != NULL; i++)
4591 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4592 helptext_config[i].value));
4596 else if (strPrefix(command, "dump level "))
4598 char *filename = &command[11];
4600 if (!fileExists(filename))
4601 Error(ERR_EXIT, "cannot open file '%s'", filename);
4603 LoadLevelFromFilename(&level, filename);
4608 else if (strPrefix(command, "dump tape "))
4610 char *filename = &command[10];
4612 if (!fileExists(filename))
4613 Error(ERR_EXIT, "cannot open file '%s'", filename);
4615 LoadTapeFromFilename(filename);
4620 else if (strPrefix(command, "autoplay "))
4622 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
4624 while (*str_ptr != '\0') /* continue parsing string */
4626 /* cut leading whitespace from string, replace it by string terminator */
4627 while (*str_ptr == ' ' || *str_ptr == '\t')
4630 if (*str_ptr == '\0') /* end of string reached */
4633 if (global.autoplay_leveldir == NULL) /* read level set string */
4635 global.autoplay_leveldir = str_ptr;
4636 global.autoplay_all = TRUE; /* default: play all tapes */
4638 for (i = 0; i < MAX_TAPES_PER_SET; i++)
4639 global.autoplay_level[i] = FALSE;
4641 else /* read level number string */
4643 int level_nr = atoi(str_ptr); /* get level_nr value */
4645 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
4646 global.autoplay_level[level_nr] = TRUE;
4648 global.autoplay_all = FALSE;
4651 /* advance string pointer to the next whitespace (or end of string) */
4652 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
4656 else if (strPrefix(command, "convert "))
4658 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
4659 char *str_ptr = strchr(str_copy, ' ');
4661 global.convert_leveldir = str_copy;
4662 global.convert_level_nr = -1;
4664 if (str_ptr != NULL) /* level number follows */
4666 *str_ptr++ = '\0'; /* terminate leveldir string */
4667 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
4670 else if (strPrefix(command, "create images "))
4672 global.create_images_dir = getStringCopy(&command[14]);
4674 if (access(global.create_images_dir, W_OK) != 0)
4675 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
4676 global.create_images_dir);
4680 #if defined(TARGET_SDL2)
4681 else if (strEqual(command, "SDL_ListModes"))
4683 SDL_Init(SDL_INIT_VIDEO);
4685 int num_displays = SDL_GetNumVideoDisplays();
4687 // check if there are any displays available
4688 if (num_displays < 0)
4690 printf("No displays available: %s\n", SDL_GetError());
4695 for (i = 0; i < num_displays; i++)
4697 int num_modes = SDL_GetNumDisplayModes(i);
4700 printf("Available display modes for display %d:\n", i);
4702 // check if there are any display modes available for this display
4705 printf("No display modes available for display %d: %s\n",
4711 for (j = 0; j < num_modes; j++)
4713 SDL_DisplayMode mode;
4715 if (SDL_GetDisplayMode(i, j, &mode) < 0)
4717 printf("Cannot get display mode %d for display %d: %s\n",
4718 j, i, SDL_GetError());
4723 printf("- %d x %d\n", mode.w, mode.h);
4729 #elif defined(TARGET_SDL)
4730 else if (strEqual(command, "SDL_ListModes"))
4735 SDL_Init(SDL_INIT_VIDEO);
4737 /* get available fullscreen/hardware modes */
4738 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
4740 /* check if there are any modes available */
4743 printf("No modes available!\n");
4748 /* check if our resolution is restricted */
4749 if (modes == (SDL_Rect **)-1)
4751 printf("All resolutions available.\n");
4755 printf("Available display modes:\n");
4757 for (i = 0; modes[i]; i++)
4758 printf("- %d x %d\n", modes[i]->w, modes[i]->h);
4768 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4772 static void InitSetup()
4774 LoadSetup(); /* global setup info */
4776 /* set some options from setup file */
4778 if (setup.options.verbose)
4779 options.verbose = TRUE;
4782 static void InitGameInfo()
4784 game.restart_level = FALSE;
4787 static void InitPlayerInfo()
4791 /* choose default local player */
4792 local_player = &stored_player[0];
4794 for (i = 0; i < MAX_PLAYERS; i++)
4795 stored_player[i].connected = FALSE;
4797 local_player->connected = TRUE;
4800 static void InitArtworkInfo()
4805 static char *get_string_in_brackets(char *string)
4807 char *string_in_brackets = checked_malloc(strlen(string) + 3);
4809 sprintf(string_in_brackets, "[%s]", string);
4811 return string_in_brackets;
4814 static char *get_level_id_suffix(int id_nr)
4816 char *id_suffix = checked_malloc(1 + 3 + 1);
4818 if (id_nr < 0 || id_nr > 999)
4821 sprintf(id_suffix, ".%03d", id_nr);
4826 static void InitArtworkConfig()
4828 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
4829 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
4830 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
4831 static char *action_id_suffix[NUM_ACTIONS + 1];
4832 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
4833 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
4834 static char *level_id_suffix[MAX_LEVELS + 1];
4835 static char *dummy[1] = { NULL };
4836 static char *ignore_generic_tokens[] =
4842 static char **ignore_image_tokens;
4843 static char **ignore_sound_tokens;
4844 static char **ignore_music_tokens;
4845 int num_ignore_generic_tokens;
4846 int num_ignore_image_tokens;
4847 int num_ignore_sound_tokens;
4848 int num_ignore_music_tokens;
4851 /* dynamically determine list of generic tokens to be ignored */
4852 num_ignore_generic_tokens = 0;
4853 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
4854 num_ignore_generic_tokens++;
4856 /* dynamically determine list of image tokens to be ignored */
4857 num_ignore_image_tokens = num_ignore_generic_tokens;
4858 for (i = 0; image_config_vars[i].token != NULL; i++)
4859 num_ignore_image_tokens++;
4860 ignore_image_tokens =
4861 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
4862 for (i = 0; i < num_ignore_generic_tokens; i++)
4863 ignore_image_tokens[i] = ignore_generic_tokens[i];
4864 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
4865 ignore_image_tokens[num_ignore_generic_tokens + i] =
4866 image_config_vars[i].token;
4867 ignore_image_tokens[num_ignore_image_tokens] = NULL;
4869 /* dynamically determine list of sound tokens to be ignored */
4870 num_ignore_sound_tokens = num_ignore_generic_tokens;
4871 ignore_sound_tokens =
4872 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
4873 for (i = 0; i < num_ignore_generic_tokens; i++)
4874 ignore_sound_tokens[i] = ignore_generic_tokens[i];
4875 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
4877 /* dynamically determine list of music tokens to be ignored */
4878 num_ignore_music_tokens = num_ignore_generic_tokens;
4879 ignore_music_tokens =
4880 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
4881 for (i = 0; i < num_ignore_generic_tokens; i++)
4882 ignore_music_tokens[i] = ignore_generic_tokens[i];
4883 ignore_music_tokens[num_ignore_music_tokens] = NULL;
4885 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4886 image_id_prefix[i] = element_info[i].token_name;
4887 for (i = 0; i < NUM_FONTS; i++)
4888 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
4889 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
4891 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4892 sound_id_prefix[i] = element_info[i].token_name;
4893 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4894 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
4895 get_string_in_brackets(element_info[i].class_name);
4896 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
4898 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
4899 music_id_prefix[i] = music_prefix_info[i].prefix;
4900 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
4902 for (i = 0; i < NUM_ACTIONS; i++)
4903 action_id_suffix[i] = element_action_info[i].suffix;
4904 action_id_suffix[NUM_ACTIONS] = NULL;
4906 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
4907 direction_id_suffix[i] = element_direction_info[i].suffix;
4908 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
4910 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
4911 special_id_suffix[i] = special_suffix_info[i].suffix;
4912 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
4914 for (i = 0; i < MAX_LEVELS; i++)
4915 level_id_suffix[i] = get_level_id_suffix(i);
4916 level_id_suffix[MAX_LEVELS] = NULL;
4918 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
4919 image_id_prefix, action_id_suffix, direction_id_suffix,
4920 special_id_suffix, ignore_image_tokens);
4921 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
4922 sound_id_prefix, action_id_suffix, dummy,
4923 special_id_suffix, ignore_sound_tokens);
4924 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
4925 music_id_prefix, special_id_suffix, level_id_suffix,
4926 dummy, ignore_music_tokens);
4929 static void InitMixer()
4936 void InitGfxBuffers()
4938 /* create additional image buffers for double-buffering and cross-fading */
4939 ReCreateBitmap(&bitmap_db_store, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
4940 ReCreateBitmap(&bitmap_db_cross, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
4941 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE, DEFAULT_DEPTH);
4942 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE, DEFAULT_DEPTH);
4943 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE, DEFAULT_DEPTH);
4944 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE, DEFAULT_DEPTH);
4945 ReCreateBitmap(&bitmap_db_toons, FULL_SXSIZE, FULL_SYSIZE, DEFAULT_DEPTH);
4947 /* initialize screen properties */
4948 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
4949 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
4951 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
4952 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
4953 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
4954 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
4955 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
4956 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
4958 InitGfxBuffers_EM();
4959 InitGfxBuffers_SP();
4964 struct GraphicInfo *graphic_info_last = graphic_info;
4965 char *filename_font_initial = NULL;
4966 char *filename_anim_initial = NULL;
4967 Bitmap *bitmap_font_initial = NULL;
4971 /* determine settings for initial font (for displaying startup messages) */
4972 for (i = 0; image_config[i].token != NULL; i++)
4974 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4976 char font_token[128];
4979 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
4980 len_font_token = strlen(font_token);
4982 if (strEqual(image_config[i].token, font_token))
4983 filename_font_initial = image_config[i].value;
4984 else if (strlen(image_config[i].token) > len_font_token &&
4985 strncmp(image_config[i].token, font_token, len_font_token) == 0)
4987 if (strEqual(&image_config[i].token[len_font_token], ".x"))
4988 font_initial[j].src_x = atoi(image_config[i].value);
4989 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
4990 font_initial[j].src_y = atoi(image_config[i].value);
4991 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
4992 font_initial[j].width = atoi(image_config[i].value);
4993 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
4994 font_initial[j].height = atoi(image_config[i].value);
4999 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5001 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5002 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5005 if (filename_font_initial == NULL) /* should not happen */
5006 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5009 InitGfxCustomArtworkInfo();
5011 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5013 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5014 font_initial[j].bitmap = bitmap_font_initial;
5016 InitFontGraphicInfo();
5018 font_height = getFontHeight(FC_RED);
5020 DrawInitTextAlways(getProgramInitString(), 20, FC_YELLOW);
5021 DrawInitTextAlways(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
5022 DrawInitTextAlways(PROGRAM_WEBSITE_STRING, WIN_YSIZE - 20 - font_height,
5025 DrawInitTextAlways("Loading graphics", 120, FC_GREEN);
5027 /* initialize busy animation with default values */
5028 int parameter[NUM_GFX_ARGS];
5029 for (i = 0; i < NUM_GFX_ARGS; i++)
5030 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5031 image_config_suffix[i].token,
5032 image_config_suffix[i].type);
5034 /* determine settings for busy animation (when displaying startup messages) */
5035 for (i = 0; image_config[i].token != NULL; i++)
5037 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5038 int len_anim_token = strlen(anim_token);
5040 if (strEqual(image_config[i].token, anim_token))
5041 filename_anim_initial = image_config[i].value;
5042 else if (strlen(image_config[i].token) > len_anim_token &&
5043 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5045 for (j = 0; image_config_suffix[j].token != NULL; j++)
5047 if (strEqual(&image_config[i].token[len_anim_token],
5048 image_config_suffix[j].token))
5050 get_graphic_parameter_value(image_config[i].value,
5051 image_config_suffix[j].token,
5052 image_config_suffix[j].type);
5057 #if defined(CREATE_SPECIAL_EDITION_RND_JUE)
5058 filename_anim_initial = "loading.pcx";
5060 parameter[GFX_ARG_X] = 0;
5061 parameter[GFX_ARG_Y] = 0;
5062 parameter[GFX_ARG_WIDTH] = 128;
5063 parameter[GFX_ARG_HEIGHT] = 40;
5064 parameter[GFX_ARG_FRAMES] = 32;
5065 parameter[GFX_ARG_DELAY] = 4;
5066 parameter[GFX_ARG_FRAMES_PER_LINE] = ARG_UNDEFINED_VALUE;
5069 if (filename_anim_initial == NULL) /* should not happen */
5070 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5072 anim_initial.bitmaps =
5073 checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5075 anim_initial.bitmaps[IMG_BITMAP_STANDARD] =
5076 LoadCustomImage(filename_anim_initial);
5078 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
5080 set_graphic_parameters_ext(0, parameter, anim_initial.bitmaps);
5082 graphic_info = graphic_info_last;
5084 init.busy.width = anim_initial.width;
5085 init.busy.height = anim_initial.height;
5087 InitMenuDesignSettings_Static();
5088 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5090 /* use copy of busy animation to prevent change while reloading artwork */
5094 void RedrawBackground()
5096 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
5097 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
5099 redraw_mask = REDRAW_ALL;
5102 void InitGfxBackground()
5106 fieldbuffer = bitmap_db_field;
5107 SetDrawtoField(DRAW_BACKBUFFER);
5109 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5111 for (x = 0; x < MAX_BUF_XSIZE; x++)
5112 for (y = 0; y < MAX_BUF_YSIZE; y++)
5115 redraw_mask = REDRAW_ALL;
5118 static void InitLevelInfo()
5120 LoadLevelInfo(); /* global level info */
5121 LoadLevelSetup_LastSeries(); /* last played series info */
5122 LoadLevelSetup_SeriesInfo(); /* last played level info */
5125 static void InitLevelArtworkInfo()
5127 LoadLevelArtworkInfo();
5130 static void InitImages()
5132 print_timestamp_init("InitImages");
5135 printf("::: leveldir_current->identifier == '%s'\n",
5136 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5137 printf("::: leveldir_current->graphics_path == '%s'\n",
5138 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5139 printf("::: leveldir_current->graphics_set == '%s'\n",
5140 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5141 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5142 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5145 setLevelArtworkDir(artwork.gfx_first);
5148 printf("::: leveldir_current->identifier == '%s'\n",
5149 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5150 printf("::: leveldir_current->graphics_path == '%s'\n",
5151 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5152 printf("::: leveldir_current->graphics_set == '%s'\n",
5153 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5154 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5155 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5159 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5160 leveldir_current->identifier,
5161 artwork.gfx_current_identifier,
5162 artwork.gfx_current->identifier,
5163 leveldir_current->graphics_set,
5164 leveldir_current->graphics_path);
5167 UPDATE_BUSY_STATE();
5169 ReloadCustomImages();
5170 print_timestamp_time("ReloadCustomImages");
5172 UPDATE_BUSY_STATE();
5174 LoadCustomElementDescriptions();
5175 print_timestamp_time("LoadCustomElementDescriptions");
5177 UPDATE_BUSY_STATE();
5179 LoadMenuDesignSettings();
5180 print_timestamp_time("LoadMenuDesignSettings");
5182 UPDATE_BUSY_STATE();
5184 ReinitializeGraphics();
5185 print_timestamp_time("ReinitializeGraphics");
5187 UPDATE_BUSY_STATE();
5189 print_timestamp_done("InitImages");
5192 static void InitSound(char *identifier)
5194 print_timestamp_init("InitSound");
5196 if (identifier == NULL)
5197 identifier = artwork.snd_current->identifier;
5199 /* set artwork path to send it to the sound server process */
5200 setLevelArtworkDir(artwork.snd_first);
5202 InitReloadCustomSounds(identifier);
5203 print_timestamp_time("InitReloadCustomSounds");
5205 ReinitializeSounds();
5206 print_timestamp_time("ReinitializeSounds");
5208 print_timestamp_done("InitSound");
5211 static void InitMusic(char *identifier)
5213 print_timestamp_init("InitMusic");
5215 if (identifier == NULL)
5216 identifier = artwork.mus_current->identifier;
5218 /* set artwork path to send it to the sound server process */
5219 setLevelArtworkDir(artwork.mus_first);
5221 InitReloadCustomMusic(identifier);
5222 print_timestamp_time("InitReloadCustomMusic");
5224 ReinitializeMusic();
5225 print_timestamp_time("ReinitializeMusic");
5227 print_timestamp_done("InitMusic");
5230 void InitNetworkServer()
5232 #if defined(NETWORK_AVALIABLE)
5236 if (!options.network)
5239 #if defined(NETWORK_AVALIABLE)
5240 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5242 if (!ConnectToServer(options.server_host, options.server_port))
5243 Error(ERR_EXIT, "cannot connect to network game server");
5245 SendToServer_PlayerName(setup.player_name);
5246 SendToServer_ProtocolVersion();
5249 SendToServer_NrWanted(nr_wanted);
5253 static boolean CheckArtworkConfigForCustomElements(char *filename)
5255 SetupFileHash *setup_file_hash;
5256 boolean redefined_ce_found = FALSE;
5258 /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */
5260 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5262 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5264 char *token = HASH_ITERATION_TOKEN(itr);
5266 if (strPrefix(token, "custom_"))
5268 redefined_ce_found = TRUE;
5273 END_HASH_ITERATION(setup_file_hash, itr)
5275 freeSetupFileHash(setup_file_hash);
5278 return redefined_ce_found;
5281 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5283 char *filename_base, *filename_local;
5284 boolean redefined_ce_found = FALSE;
5286 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5289 printf("::: leveldir_current->identifier == '%s'\n",
5290 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5291 printf("::: leveldir_current->graphics_path == '%s'\n",
5292 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5293 printf("::: leveldir_current->graphics_set == '%s'\n",
5294 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5295 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5296 leveldir_current == NULL ? "[NULL]" :
5297 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5300 /* first look for special artwork configured in level series config */
5301 filename_base = getCustomArtworkLevelConfigFilename(type);
5304 printf("::: filename_base == '%s'\n", filename_base);
5307 if (fileExists(filename_base))
5308 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5310 filename_local = getCustomArtworkConfigFilename(type);
5313 printf("::: filename_local == '%s'\n", filename_local);
5316 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5317 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5320 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5323 return redefined_ce_found;
5326 static void InitOverrideArtwork()
5328 boolean redefined_ce_found = FALSE;
5330 /* to check if this level set redefines any CEs, do not use overriding */
5331 gfx.override_level_graphics = FALSE;
5332 gfx.override_level_sounds = FALSE;
5333 gfx.override_level_music = FALSE;
5335 /* now check if this level set has definitions for custom elements */
5336 if (setup.override_level_graphics == AUTO ||
5337 setup.override_level_sounds == AUTO ||
5338 setup.override_level_music == AUTO)
5339 redefined_ce_found =
5340 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5341 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5342 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5345 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5348 if (redefined_ce_found)
5350 /* this level set has CE definitions: change "AUTO" to "FALSE" */
5351 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5352 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
5353 gfx.override_level_music = (setup.override_level_music == TRUE);
5357 /* this level set has no CE definitions: change "AUTO" to "TRUE" */
5358 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5359 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
5360 gfx.override_level_music = (setup.override_level_music != FALSE);
5364 printf("::: => %d, %d, %d\n",
5365 gfx.override_level_graphics,
5366 gfx.override_level_sounds,
5367 gfx.override_level_music);
5371 static char *getNewArtworkIdentifier(int type)
5373 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5374 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5375 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5376 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5377 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5378 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5379 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5380 char *leveldir_identifier = leveldir_current->identifier;
5381 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
5382 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5383 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5384 char *artwork_current_identifier;
5385 char *artwork_new_identifier = NULL; /* default: nothing has changed */
5387 /* leveldir_current may be invalid (level group, parent link) */
5388 if (!validLevelSeries(leveldir_current))
5391 /* 1st step: determine artwork set to be activated in descending order:
5392 --------------------------------------------------------------------
5393 1. setup artwork (when configured to override everything else)
5394 2. artwork set configured in "levelinfo.conf" of current level set
5395 (artwork in level directory will have priority when loading later)
5396 3. artwork in level directory (stored in artwork sub-directory)
5397 4. setup artwork (currently configured in setup menu) */
5399 if (setup_override_artwork)
5400 artwork_current_identifier = setup_artwork_set;
5401 else if (leveldir_artwork_set != NULL)
5402 artwork_current_identifier = leveldir_artwork_set;
5403 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5404 artwork_current_identifier = leveldir_identifier;
5406 artwork_current_identifier = setup_artwork_set;
5409 /* 2nd step: check if it is really needed to reload artwork set
5410 ------------------------------------------------------------ */
5412 /* ---------- reload if level set and also artwork set has changed ------- */
5413 if (leveldir_current_identifier[type] != leveldir_identifier &&
5414 (last_has_level_artwork_set[type] || has_level_artwork_set))
5415 artwork_new_identifier = artwork_current_identifier;
5417 leveldir_current_identifier[type] = leveldir_identifier;
5418 last_has_level_artwork_set[type] = has_level_artwork_set;
5420 /* ---------- reload if "override artwork" setting has changed ----------- */
5421 if (last_override_level_artwork[type] != setup_override_artwork)
5422 artwork_new_identifier = artwork_current_identifier;
5424 last_override_level_artwork[type] = setup_override_artwork;
5426 /* ---------- reload if current artwork identifier has changed ----------- */
5427 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5428 artwork_current_identifier))
5429 artwork_new_identifier = artwork_current_identifier;
5431 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5433 /* ---------- do not reload directly after starting ---------------------- */
5434 if (!initialized[type])
5435 artwork_new_identifier = NULL;
5437 initialized[type] = TRUE;
5439 return artwork_new_identifier;
5442 void ReloadCustomArtwork(int force_reload)
5444 int last_game_status = game_status; /* save current game status */
5445 char *gfx_new_identifier;
5446 char *snd_new_identifier;
5447 char *mus_new_identifier;
5448 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5449 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5450 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5451 boolean reload_needed;
5453 InitOverrideArtwork();
5455 force_reload_gfx |= AdjustGraphicsForEMC();
5457 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5458 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5459 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5461 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
5462 snd_new_identifier != NULL || force_reload_snd ||
5463 mus_new_identifier != NULL || force_reload_mus);
5468 print_timestamp_init("ReloadCustomArtwork");
5470 game_status = GAME_MODE_LOADING;
5472 FadeOut(REDRAW_ALL);
5474 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5475 print_timestamp_time("ClearRectangle");
5479 if (gfx_new_identifier != NULL || force_reload_gfx)
5482 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5483 artwork.gfx_current_identifier,
5485 artwork.gfx_current->identifier,
5486 leveldir_current->graphics_set);
5490 print_timestamp_time("InitImages");
5493 if (snd_new_identifier != NULL || force_reload_snd)
5495 InitSound(snd_new_identifier);
5496 print_timestamp_time("InitSound");
5499 if (mus_new_identifier != NULL || force_reload_mus)
5501 InitMusic(mus_new_identifier);
5502 print_timestamp_time("InitMusic");
5505 game_status = last_game_status; /* restore current game status */
5507 init_last = init; /* switch to new busy animation */
5509 FadeOut(REDRAW_ALL);
5513 /* force redraw of (open or closed) door graphics */
5514 SetDoorState(DOOR_OPEN_ALL);
5515 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5517 FadeSetEnterScreen();
5518 FadeSkipNextFadeOut();
5520 print_timestamp_done("ReloadCustomArtwork");
5522 LimitScreenUpdates(FALSE);
5525 void KeyboardAutoRepeatOffUnlessAutoplay()
5527 if (global.autoplay_leveldir == NULL)
5528 KeyboardAutoRepeatOff();
5531 void DisplayExitMessage(char *format, va_list ap)
5533 // check if draw buffer and fonts for exit message are already available
5534 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
5537 int font_1 = FC_RED;
5538 int font_2 = FC_YELLOW;
5539 int font_3 = FC_BLUE;
5540 int font_width = getFontWidth(font_2);
5541 int font_height = getFontHeight(font_2);
5544 int sxsize = WIN_XSIZE - 2 * sx;
5545 int sysize = WIN_YSIZE - 2 * sy;
5546 int line_length = sxsize / font_width;
5547 int max_lines = sysize / font_height;
5548 int num_lines_printed;
5552 gfx.sxsize = sxsize;
5553 gfx.sysize = sysize;
5557 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5559 DrawTextSCentered(sy, font_1, "Fatal error:");
5560 sy += 3 * font_height;;
5563 DrawTextBufferVA(sx, sy, format, ap, font_2,
5564 line_length, line_length, max_lines,
5565 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5566 sy += (num_lines_printed + 3) * font_height;
5568 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
5569 sy += 3 * font_height;
5572 DrawTextBuffer(sx, sy, program.error_filename, font_2,
5573 line_length, line_length, max_lines,
5574 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5576 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
5578 redraw_mask = REDRAW_ALL;
5582 /* deactivate toons on error message screen */
5583 setup.toons = FALSE;
5585 WaitForEventToContinue();
5589 /* ========================================================================= */
5591 /* ========================================================================= */
5595 print_timestamp_init("OpenAll");
5597 game_status = GAME_MODE_LOADING;
5601 InitGlobal(); /* initialize some global variables */
5603 print_timestamp_time("[init global stuff]");
5605 if (options.execute_command)
5606 Execute_Command(options.execute_command);
5608 if (options.serveronly)
5610 #if defined(PLATFORM_UNIX)
5611 NetworkServer(options.server_port, options.serveronly);
5613 Error(ERR_WARN, "networking only supported in Unix version");
5616 exit(0); /* never reached, server loops forever */
5621 print_timestamp_time("[init setup/config stuff (1)]");
5624 print_timestamp_time("[init setup/config stuff (2)]");
5626 print_timestamp_time("[init setup/config stuff (3)]");
5627 InitArtworkInfo(); /* needed before loading gfx, sound & music */
5628 print_timestamp_time("[init setup/config stuff (4)]");
5629 InitArtworkConfig(); /* needed before forking sound child process */
5630 print_timestamp_time("[init setup/config stuff (5)]");
5632 print_timestamp_time("[init setup/config stuff (6)]");
5634 InitRND(NEW_RANDOMIZE);
5635 InitSimpleRandom(NEW_RANDOMIZE);
5639 print_timestamp_time("[init setup/config stuff]");
5642 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
5644 InitEventFilter(FilterEvents);
5646 print_timestamp_time("[init video stuff]");
5648 InitElementPropertiesStatic();
5649 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5650 InitElementPropertiesGfxElement();
5652 print_timestamp_time("[init element properties stuff]");
5656 print_timestamp_time("InitGfx");
5659 print_timestamp_time("InitLevelInfo");
5661 InitLevelArtworkInfo();
5662 print_timestamp_time("InitLevelArtworkInfo");
5664 InitOverrideArtwork(); /* needs to know current level directory */
5665 print_timestamp_time("InitOverrideArtwork");
5667 InitImages(); /* needs to know current level directory */
5668 print_timestamp_time("InitImages");
5670 InitSound(NULL); /* needs to know current level directory */
5671 print_timestamp_time("InitSound");
5673 InitMusic(NULL); /* needs to know current level directory */
5674 print_timestamp_time("InitMusic");
5676 InitGfxBackground();
5681 if (global.autoplay_leveldir)
5686 else if (global.convert_leveldir)
5691 else if (global.create_images_dir)
5693 CreateLevelSketchImages();
5697 game_status = GAME_MODE_MAIN;
5699 FadeSetEnterScreen();
5700 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
5701 FadeSkipNextFadeOut();
5703 print_timestamp_time("[post-artwork]");
5705 print_timestamp_done("OpenAll");
5709 InitNetworkServer();
5712 Error(ERR_DEBUG, "::: SDL_GetBasePath() == '%s'",
5714 Error(ERR_DEBUG, "::: SDL_GetPrefPath() == '%s'",
5715 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
5716 #if defined(PLATFORM_ANDROID)
5717 Error(ERR_DEBUG, "::: SDL_AndroidGetInternalStoragePath() == '%s'",
5718 SDL_AndroidGetInternalStoragePath());
5719 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStoragePath() == '%s'",
5720 SDL_AndroidGetExternalStoragePath());
5721 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStorageState() == '%s'",
5722 (SDL_AndroidGetExternalStorageState() ==
5723 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "read" :
5724 SDL_AndroidGetExternalStorageState() ==
5725 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "write" : "not available"));
5730 void CloseAllAndExit(int exit_value)
5735 CloseAudio(); /* called after freeing sounds (needed for SDL) */
5742 #if defined(TARGET_SDL)
5743 #if defined(TARGET_SDL2)
5745 // set a flag to tell the network server thread to quit and wait for it
5746 // using SDL_WaitThread()
5748 if (network_server) /* terminate network server */
5749 SDL_KillThread(server_thread);
5753 CloseVideoDisplay();
5754 ClosePlatformDependentStuff();
5756 if (exit_value != 0)
5758 /* fall back to default level set (current set may have caused an error) */
5759 SaveLevelSetup_LastSeries_Deactivate();
5761 /* tell user where to find error log file which may contain more details */
5762 // (error notification now directly displayed on screen inside R'n'D
5763 // NotifyUserAboutErrorFile(); /* currently only works for Windows */