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 CreateImageWithSmallImages(graphic, graphic_info[graphic].scale_up_factor,
157 graphic_info[graphic].tile_size);
160 void InitElementSmallImages()
162 print_timestamp_init("InitElementSmallImages");
164 static int special_graphics[] =
166 IMG_EDITOR_ELEMENT_BORDER,
167 IMG_EDITOR_ELEMENT_BORDER_INPUT,
168 IMG_EDITOR_CASCADE_LIST,
169 IMG_EDITOR_CASCADE_LIST_ACTIVE,
172 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
173 int num_property_mappings = getImageListPropertyMappingSize();
176 print_timestamp_time("getImageListPropertyMapping/Size");
178 print_timestamp_init("InitElementSmallImagesScaledUp (1)");
179 /* initialize normal images from static configuration */
180 for (i = 0; element_to_graphic[i].element > -1; i++)
181 InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
182 print_timestamp_done("InitElementSmallImagesScaledUp (1)");
184 /* initialize special images from static configuration */
185 for (i = 0; element_to_special_graphic[i].element > -1; i++)
186 InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
187 print_timestamp_time("InitElementSmallImagesScaledUp (2)");
189 /* initialize images from dynamic configuration (may be elements or other) */
190 for (i = 0; i < num_property_mappings; i++)
191 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
192 print_timestamp_time("InitElementSmallImagesScaledUp (3)");
194 /* initialize special images from above list (non-element images) */
195 for (i = 0; special_graphics[i] > -1; i++)
196 InitElementSmallImagesScaledUp(special_graphics[i]);
197 print_timestamp_time("InitElementSmallImagesScaledUp (4)");
199 print_timestamp_done("InitElementSmallImages");
202 void InitScaledImages()
206 /* scale normal images from static configuration, if not already scaled */
207 for (i = 0; i < NUM_IMAGE_FILES; i++)
208 ScaleImage(i, graphic_info[i].scale_up_factor);
212 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
213 void SetBitmaps_EM(Bitmap **em_bitmap)
215 em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
216 em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].bitmap;
221 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
222 void SetBitmaps_SP(Bitmap **sp_bitmap)
224 *sp_bitmap = graphic_info[IMG_SP_OBJECTS].bitmap;
228 static int getFontBitmapID(int font_nr)
232 /* (special case: do not use special font for GAME_MODE_LOADING) */
233 if (game_status >= GAME_MODE_TITLE_INITIAL &&
234 game_status <= GAME_MODE_PSEUDO_PREVIEW)
235 special = game_status;
236 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
237 special = GFX_SPECIAL_ARG_MAIN;
240 return font_info[font_nr].special_bitmap_id[special];
245 static int getFontFromToken(char *token)
247 char *value = getHashEntry(font_token_hash, token);
252 /* if font not found, use reliable default value */
253 return FONT_INITIAL_1;
256 void InitFontGraphicInfo()
258 static struct FontBitmapInfo *font_bitmap_info = NULL;
259 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
260 int num_property_mappings = getImageListPropertyMappingSize();
261 int num_font_bitmaps = NUM_FONTS;
264 if (graphic_info == NULL) /* still at startup phase */
266 InitFontInfo(font_initial, NUM_INITIAL_FONTS,
267 getFontBitmapID, getFontFromToken);
272 /* ---------- initialize font graphic definitions ---------- */
274 /* always start with reliable default values (normal font graphics) */
275 for (i = 0; i < NUM_FONTS; i++)
276 font_info[i].graphic = IMG_FONT_INITIAL_1;
278 /* initialize normal font/graphic mapping from static configuration */
279 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
281 int font_nr = font_to_graphic[i].font_nr;
282 int special = font_to_graphic[i].special;
283 int graphic = font_to_graphic[i].graphic;
288 font_info[font_nr].graphic = graphic;
291 /* always start with reliable default values (special font graphics) */
292 for (i = 0; i < NUM_FONTS; i++)
294 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
296 font_info[i].special_graphic[j] = font_info[i].graphic;
297 font_info[i].special_bitmap_id[j] = i;
301 /* initialize special font/graphic mapping from static configuration */
302 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
304 int font_nr = font_to_graphic[i].font_nr;
305 int special = font_to_graphic[i].special;
306 int graphic = font_to_graphic[i].graphic;
307 int base_graphic = font2baseimg(font_nr);
309 if (IS_SPECIAL_GFX_ARG(special))
311 boolean base_redefined =
312 getImageListEntryFromImageID(base_graphic)->redefined;
313 boolean special_redefined =
314 getImageListEntryFromImageID(graphic)->redefined;
315 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
317 /* if the base font ("font.title_1", for example) has been redefined,
318 but not the special font ("font.title_1.LEVELS", for example), do not
319 use an existing (in this case considered obsolete) special font
320 anymore, but use the automatically determined default font */
321 /* special case: cloned special fonts must be explicitly redefined,
322 but are not automatically redefined by redefining base font */
323 if (base_redefined && !special_redefined && !special_cloned)
326 font_info[font_nr].special_graphic[special] = graphic;
327 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
332 /* initialize special font/graphic mapping from dynamic configuration */
333 for (i = 0; i < num_property_mappings; i++)
335 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
336 int special = property_mapping[i].ext3_index;
337 int graphic = property_mapping[i].artwork_index;
342 if (IS_SPECIAL_GFX_ARG(special))
344 font_info[font_nr].special_graphic[special] = graphic;
345 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
350 /* correct special font/graphic mapping for cloned fonts for downwards
351 compatibility of PREVIEW fonts -- this is only needed for implicit
352 redefinition of special font by redefined base font, and only if other
353 fonts are cloned from this special font (like in the "Zelda" level set) */
354 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
356 int font_nr = font_to_graphic[i].font_nr;
357 int special = font_to_graphic[i].special;
358 int graphic = font_to_graphic[i].graphic;
360 if (IS_SPECIAL_GFX_ARG(special))
362 boolean special_redefined =
363 getImageListEntryFromImageID(graphic)->redefined;
364 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
366 if (special_cloned && !special_redefined)
370 for (j = 0; font_to_graphic[j].font_nr > -1; j++)
372 int font_nr2 = font_to_graphic[j].font_nr;
373 int special2 = font_to_graphic[j].special;
374 int graphic2 = font_to_graphic[j].graphic;
376 if (IS_SPECIAL_GFX_ARG(special2) &&
377 graphic2 == graphic_info[graphic].clone_from)
379 font_info[font_nr].special_graphic[special] =
380 font_info[font_nr2].special_graphic[special2];
381 font_info[font_nr].special_bitmap_id[special] =
382 font_info[font_nr2].special_bitmap_id[special2];
389 /* reset non-redefined ".active" font graphics if normal font is redefined */
390 /* (this different treatment is needed because normal and active fonts are
391 independently defined ("active" is not a property of font definitions!) */
392 for (i = 0; i < NUM_FONTS; i++)
394 int font_nr_base = i;
395 int font_nr_active = FONT_ACTIVE(font_nr_base);
397 /* check only those fonts with exist as normal and ".active" variant */
398 if (font_nr_base != font_nr_active)
400 int base_graphic = font_info[font_nr_base].graphic;
401 int active_graphic = font_info[font_nr_active].graphic;
402 boolean base_redefined =
403 getImageListEntryFromImageID(base_graphic)->redefined;
404 boolean active_redefined =
405 getImageListEntryFromImageID(active_graphic)->redefined;
407 /* if the base font ("font.menu_1", for example) has been redefined,
408 but not the active font ("font.menu_1.active", for example), do not
409 use an existing (in this case considered obsolete) active font
410 anymore, but use the automatically determined default font */
411 if (base_redefined && !active_redefined)
412 font_info[font_nr_active].graphic = base_graphic;
414 /* now also check each "special" font (which may be the same as above) */
415 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
417 int base_graphic = font_info[font_nr_base].special_graphic[j];
418 int active_graphic = font_info[font_nr_active].special_graphic[j];
419 boolean base_redefined =
420 getImageListEntryFromImageID(base_graphic)->redefined;
421 boolean active_redefined =
422 getImageListEntryFromImageID(active_graphic)->redefined;
424 /* same as above, but check special graphic definitions, for example:
425 redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN" */
426 if (base_redefined && !active_redefined)
428 font_info[font_nr_active].special_graphic[j] =
429 font_info[font_nr_base].special_graphic[j];
430 font_info[font_nr_active].special_bitmap_id[j] =
431 font_info[font_nr_base].special_bitmap_id[j];
437 /* ---------- initialize font bitmap array ---------- */
439 if (font_bitmap_info != NULL)
440 FreeFontInfo(font_bitmap_info);
443 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
445 /* ---------- initialize font bitmap definitions ---------- */
447 for (i = 0; i < NUM_FONTS; i++)
449 if (i < NUM_INITIAL_FONTS)
451 font_bitmap_info[i] = font_initial[i];
455 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
457 int font_bitmap_id = font_info[i].special_bitmap_id[j];
458 int graphic = font_info[i].special_graphic[j];
460 /* set 'graphic_info' for font entries, if uninitialized (guessed) */
461 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
463 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
464 graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
467 /* copy font relevant information from graphics information */
468 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
469 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
470 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
471 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
472 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
474 font_bitmap_info[font_bitmap_id].draw_xoffset =
475 graphic_info[graphic].draw_xoffset;
476 font_bitmap_info[font_bitmap_id].draw_yoffset =
477 graphic_info[graphic].draw_yoffset;
479 font_bitmap_info[font_bitmap_id].num_chars =
480 graphic_info[graphic].anim_frames;
481 font_bitmap_info[font_bitmap_id].num_chars_per_line =
482 graphic_info[graphic].anim_frames_per_line;
486 InitFontInfo(font_bitmap_info, num_font_bitmaps,
487 getFontBitmapID, getFontFromToken);
490 void InitElementGraphicInfo()
492 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
493 int num_property_mappings = getImageListPropertyMappingSize();
496 if (graphic_info == NULL) /* still at startup phase */
499 /* set values to -1 to identify later as "uninitialized" values */
500 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
502 for (act = 0; act < NUM_ACTIONS; act++)
504 element_info[i].graphic[act] = -1;
505 element_info[i].crumbled[act] = -1;
507 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
509 element_info[i].direction_graphic[act][dir] = -1;
510 element_info[i].direction_crumbled[act][dir] = -1;
517 /* initialize normal element/graphic mapping from static configuration */
518 for (i = 0; element_to_graphic[i].element > -1; i++)
520 int element = element_to_graphic[i].element;
521 int action = element_to_graphic[i].action;
522 int direction = element_to_graphic[i].direction;
523 boolean crumbled = element_to_graphic[i].crumbled;
524 int graphic = element_to_graphic[i].graphic;
525 int base_graphic = el2baseimg(element);
527 if (graphic_info[graphic].bitmap == NULL)
530 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
533 boolean base_redefined =
534 getImageListEntryFromImageID(base_graphic)->redefined;
535 boolean act_dir_redefined =
536 getImageListEntryFromImageID(graphic)->redefined;
538 /* if the base graphic ("emerald", for example) has been redefined,
539 but not the action graphic ("emerald.falling", for example), do not
540 use an existing (in this case considered obsolete) action graphic
541 anymore, but use the automatically determined default graphic */
542 if (base_redefined && !act_dir_redefined)
547 action = ACTION_DEFAULT;
552 element_info[element].direction_crumbled[action][direction] = graphic;
554 element_info[element].crumbled[action] = graphic;
559 element_info[element].direction_graphic[action][direction] = graphic;
561 element_info[element].graphic[action] = graphic;
565 /* initialize normal element/graphic mapping from dynamic configuration */
566 for (i = 0; i < num_property_mappings; i++)
568 int element = property_mapping[i].base_index;
569 int action = property_mapping[i].ext1_index;
570 int direction = property_mapping[i].ext2_index;
571 int special = property_mapping[i].ext3_index;
572 int graphic = property_mapping[i].artwork_index;
573 boolean crumbled = FALSE;
575 if (special == GFX_SPECIAL_ARG_CRUMBLED)
581 if (graphic_info[graphic].bitmap == NULL)
584 if (element >= MAX_NUM_ELEMENTS || special != -1)
588 action = ACTION_DEFAULT;
593 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
594 element_info[element].direction_crumbled[action][dir] = -1;
597 element_info[element].direction_crumbled[action][direction] = graphic;
599 element_info[element].crumbled[action] = graphic;
604 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
605 element_info[element].direction_graphic[action][dir] = -1;
608 element_info[element].direction_graphic[action][direction] = graphic;
610 element_info[element].graphic[action] = graphic;
614 /* now copy all graphics that are defined to be cloned from other graphics */
615 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
617 int graphic = element_info[i].graphic[ACTION_DEFAULT];
618 int crumbled_like, diggable_like;
623 crumbled_like = graphic_info[graphic].crumbled_like;
624 diggable_like = graphic_info[graphic].diggable_like;
626 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
628 for (act = 0; act < NUM_ACTIONS; act++)
629 element_info[i].crumbled[act] =
630 element_info[crumbled_like].crumbled[act];
631 for (act = 0; act < NUM_ACTIONS; act++)
632 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
633 element_info[i].direction_crumbled[act][dir] =
634 element_info[crumbled_like].direction_crumbled[act][dir];
637 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
639 element_info[i].graphic[ACTION_DIGGING] =
640 element_info[diggable_like].graphic[ACTION_DIGGING];
641 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
642 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
643 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
647 /* set hardcoded definitions for some runtime elements without graphic */
648 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
650 /* set hardcoded definitions for some internal elements without graphic */
651 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
653 if (IS_EDITOR_CASCADE_INACTIVE(i))
654 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
655 else if (IS_EDITOR_CASCADE_ACTIVE(i))
656 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
659 /* now set all undefined/invalid graphics to -1 to set to default after it */
660 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
662 for (act = 0; act < NUM_ACTIONS; act++)
666 graphic = element_info[i].graphic[act];
667 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
668 element_info[i].graphic[act] = -1;
670 graphic = element_info[i].crumbled[act];
671 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
672 element_info[i].crumbled[act] = -1;
674 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
676 graphic = element_info[i].direction_graphic[act][dir];
677 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
678 element_info[i].direction_graphic[act][dir] = -1;
680 graphic = element_info[i].direction_crumbled[act][dir];
681 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
682 element_info[i].direction_crumbled[act][dir] = -1;
689 /* adjust graphics with 2nd tile for movement according to direction
690 (do this before correcting '-1' values to minimize calculations) */
691 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
693 for (act = 0; act < NUM_ACTIONS; act++)
695 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
697 int graphic = element_info[i].direction_graphic[act][dir];
698 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
700 if (act == ACTION_FALLING) /* special case */
701 graphic = element_info[i].graphic[act];
704 graphic_info[graphic].double_movement &&
705 graphic_info[graphic].swap_double_tiles != 0)
707 struct GraphicInfo *g = &graphic_info[graphic];
708 int src_x_front = g->src_x;
709 int src_y_front = g->src_y;
710 int src_x_back = g->src_x + g->offset2_x;
711 int src_y_back = g->src_y + g->offset2_y;
712 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
714 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
715 src_y_front < src_y_back);
716 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
717 boolean swap_movement_tiles_autodetected =
718 (!frames_are_ordered_diagonally &&
719 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
720 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
721 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
722 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
725 /* swap frontside and backside graphic tile coordinates, if needed */
726 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
728 /* get current (wrong) backside tile coordinates */
729 getFixedGraphicSourceExt(graphic, 0, &dummy,
730 &src_x_back, &src_y_back, TRUE);
732 /* set frontside tile coordinates to backside tile coordinates */
733 g->src_x = src_x_back;
734 g->src_y = src_y_back;
736 /* invert tile offset to point to new backside tile coordinates */
740 /* do not swap front and backside tiles again after correction */
741 g->swap_double_tiles = 0;
750 /* now set all '-1' values to element specific default values */
751 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
753 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
754 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
755 int default_direction_graphic[NUM_DIRECTIONS_FULL];
756 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
758 if (default_graphic == -1)
759 default_graphic = IMG_UNKNOWN;
761 if (default_crumbled == -1)
762 default_crumbled = default_graphic;
764 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
766 default_direction_graphic[dir] =
767 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
768 default_direction_crumbled[dir] =
769 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
771 if (default_direction_graphic[dir] == -1)
772 default_direction_graphic[dir] = default_graphic;
774 if (default_direction_crumbled[dir] == -1)
775 default_direction_crumbled[dir] = default_direction_graphic[dir];
778 for (act = 0; act < NUM_ACTIONS; act++)
780 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
781 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
782 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
783 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
784 act == ACTION_TURNING_FROM_RIGHT ||
785 act == ACTION_TURNING_FROM_UP ||
786 act == ACTION_TURNING_FROM_DOWN);
788 /* generic default action graphic (defined by "[default]" directive) */
789 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
790 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
791 int default_remove_graphic = IMG_EMPTY;
793 if (act_remove && default_action_graphic != -1)
794 default_remove_graphic = default_action_graphic;
796 /* look for special default action graphic (classic game specific) */
797 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
798 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
799 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
800 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
801 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
802 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
804 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
805 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
806 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
807 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
808 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
809 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
811 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
812 /* !!! make this better !!! */
813 if (i == EL_EMPTY_SPACE)
815 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
816 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
819 if (default_action_graphic == -1)
820 default_action_graphic = default_graphic;
822 if (default_action_crumbled == -1)
823 default_action_crumbled = default_action_graphic;
825 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
827 /* use action graphic as the default direction graphic, if undefined */
828 int default_action_direction_graphic = element_info[i].graphic[act];
829 int default_action_direction_crumbled = element_info[i].crumbled[act];
831 /* no graphic for current action -- use default direction graphic */
832 if (default_action_direction_graphic == -1)
833 default_action_direction_graphic =
834 (act_remove ? default_remove_graphic :
836 element_info[i].direction_graphic[ACTION_TURNING][dir] :
837 default_action_graphic != default_graphic ?
838 default_action_graphic :
839 default_direction_graphic[dir]);
841 if (element_info[i].direction_graphic[act][dir] == -1)
842 element_info[i].direction_graphic[act][dir] =
843 default_action_direction_graphic;
845 if (default_action_direction_crumbled == -1)
846 default_action_direction_crumbled =
847 element_info[i].direction_graphic[act][dir];
849 if (element_info[i].direction_crumbled[act][dir] == -1)
850 element_info[i].direction_crumbled[act][dir] =
851 default_action_direction_crumbled;
854 /* no graphic for this specific action -- use default action graphic */
855 if (element_info[i].graphic[act] == -1)
856 element_info[i].graphic[act] =
857 (act_remove ? default_remove_graphic :
858 act_turning ? element_info[i].graphic[ACTION_TURNING] :
859 default_action_graphic);
861 if (element_info[i].crumbled[act] == -1)
862 element_info[i].crumbled[act] = element_info[i].graphic[act];
869 void InitElementSpecialGraphicInfo()
871 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
872 int num_property_mappings = getImageListPropertyMappingSize();
875 /* always start with reliable default values */
876 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
877 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
878 element_info[i].special_graphic[j] =
879 element_info[i].graphic[ACTION_DEFAULT];
881 /* initialize special element/graphic mapping from static configuration */
882 for (i = 0; element_to_special_graphic[i].element > -1; i++)
884 int element = element_to_special_graphic[i].element;
885 int special = element_to_special_graphic[i].special;
886 int graphic = element_to_special_graphic[i].graphic;
887 int base_graphic = el2baseimg(element);
888 boolean base_redefined =
889 getImageListEntryFromImageID(base_graphic)->redefined;
890 boolean special_redefined =
891 getImageListEntryFromImageID(graphic)->redefined;
893 /* if the base graphic ("emerald", for example) has been redefined,
894 but not the special graphic ("emerald.EDITOR", for example), do not
895 use an existing (in this case considered obsolete) special graphic
896 anymore, but use the automatically created (down-scaled) graphic */
897 if (base_redefined && !special_redefined)
900 element_info[element].special_graphic[special] = graphic;
903 /* initialize special element/graphic mapping from dynamic configuration */
904 for (i = 0; i < num_property_mappings; i++)
906 int element = property_mapping[i].base_index;
907 int action = property_mapping[i].ext1_index;
908 int direction = property_mapping[i].ext2_index;
909 int special = property_mapping[i].ext3_index;
910 int graphic = property_mapping[i].artwork_index;
912 /* for action ".active", replace element with active element, if exists */
913 if (action == ACTION_ACTIVE && element != ELEMENT_ACTIVE(element))
915 element = ELEMENT_ACTIVE(element);
919 if (element >= MAX_NUM_ELEMENTS)
922 /* do not change special graphic if action or direction was specified */
923 if (action != -1 || direction != -1)
926 if (IS_SPECIAL_GFX_ARG(special))
927 element_info[element].special_graphic[special] = graphic;
930 /* now set all undefined/invalid graphics to default */
931 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
932 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
933 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
934 element_info[i].special_graphic[j] =
935 element_info[i].graphic[ACTION_DEFAULT];
938 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
940 if (type != TYPE_ELEMENT && type != TYPE_GRAPHIC)
941 return get_parameter_value(value_raw, suffix, type);
943 if (strEqual(value_raw, ARG_UNDEFINED))
944 return ARG_UNDEFINED_VALUE;
946 if (type == TYPE_ELEMENT)
948 char *value = getHashEntry(element_token_hash, value_raw);
950 return (value != NULL ? atoi(value) : EL_UNDEFINED);
952 else if (type == TYPE_GRAPHIC)
954 char *value = getHashEntry(graphic_token_hash, value_raw);
956 return (value != NULL ? atoi(value) : IMG_UNDEFINED);
962 static int get_scaled_graphic_width(int graphic)
964 int original_width = getOriginalImageWidthFromImageID(graphic);
965 int scale_up_factor = graphic_info[graphic].scale_up_factor;
967 return original_width * scale_up_factor;
970 static int get_scaled_graphic_height(int graphic)
972 int original_height = getOriginalImageHeightFromImageID(graphic);
973 int scale_up_factor = graphic_info[graphic].scale_up_factor;
975 return original_height * scale_up_factor;
978 static void set_graphic_parameters_ext(int graphic, int *parameter,
981 struct GraphicInfo *g = &graphic_info[graphic];
982 int anim_frames_per_row = 1, anim_frames_per_col = 1;
983 int anim_frames_per_line = 1;
985 /* always start with reliable default values */
986 g->src_image_width = 0;
987 g->src_image_height = 0;
990 g->width = TILEX; /* default for element graphics */
991 g->height = TILEY; /* default for element graphics */
992 g->offset_x = 0; /* one or both of these values ... */
993 g->offset_y = 0; /* ... will be corrected later */
994 g->offset2_x = 0; /* one or both of these values ... */
995 g->offset2_y = 0; /* ... will be corrected later */
996 g->swap_double_tiles = -1; /* auto-detect tile swapping */
997 g->crumbled_like = -1; /* do not use clone element */
998 g->diggable_like = -1; /* do not use clone element */
999 g->border_size = TILEX / 8; /* "CRUMBLED" border size */
1000 g->scale_up_factor = 1; /* default: no scaling up */
1001 g->tile_size = TILESIZE; /* default: standard tile size */
1002 g->clone_from = -1; /* do not use clone graphic */
1003 g->anim_delay_fixed = 0;
1004 g->anim_delay_random = 0;
1005 g->post_delay_fixed = 0;
1006 g->post_delay_random = 0;
1007 g->fade_mode = FADE_MODE_DEFAULT;
1011 g->align = ALIGN_CENTER; /* default for title screens */
1012 g->valign = VALIGN_MIDDLE; /* default for title screens */
1013 g->sort_priority = 0; /* default for title screens */
1015 g->style = STYLE_DEFAULT;
1017 g->bitmap = src_bitmap;
1019 /* optional zoom factor for scaling up the image to a larger size */
1020 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1021 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1022 if (g->scale_up_factor < 1)
1023 g->scale_up_factor = 1; /* no scaling */
1025 /* optional tile size for using non-standard image size */
1026 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1028 g->tile_size = parameter[GFX_ARG_TILE_SIZE];
1031 // CHECK: should tile sizes less than standard tile size be allowed?
1032 if (g->tile_size < TILESIZE)
1033 g->tile_size = TILESIZE; /* standard tile size */
1037 // CHECK: when setting tile size, should this set width and height?
1038 g->width = g->tile_size;
1039 g->height = g->tile_size;
1043 if (g->use_image_size)
1045 /* set new default bitmap size (with scaling, but without small images) */
1046 g->width = get_scaled_graphic_width(graphic);
1047 g->height = get_scaled_graphic_height(graphic);
1050 /* optional x and y tile position of animation frame sequence */
1051 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1052 g->src_x = parameter[GFX_ARG_XPOS] * TILEX;
1053 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1054 g->src_y = parameter[GFX_ARG_YPOS] * TILEY;
1056 /* optional x and y pixel position of animation frame sequence */
1057 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1058 g->src_x = parameter[GFX_ARG_X];
1059 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1060 g->src_y = parameter[GFX_ARG_Y];
1062 /* optional width and height of each animation frame */
1063 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1064 g->width = parameter[GFX_ARG_WIDTH];
1065 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1066 g->height = parameter[GFX_ARG_HEIGHT];
1072 Error(ERR_INFO_LINE, "-");
1073 Error(ERR_WARN, "invalid value %d for '%s.width' (fallback done to %d)",
1074 g->width, getTokenFromImageID(graphic), TILEX);
1075 Error(ERR_INFO_LINE, "-");
1077 g->width = TILEX; /* will be checked to be inside bitmap later */
1082 Error(ERR_INFO_LINE, "-");
1083 Error(ERR_WARN, "invalid value %d for '%s.height' (fallback done to %d)",
1084 g->height, getTokenFromImageID(graphic), TILEY);
1085 Error(ERR_INFO_LINE, "-");
1087 g->height = TILEY; /* will be checked to be inside bitmap later */
1093 /* get final bitmap size (with scaling, but without small images) */
1094 int src_image_width = get_scaled_graphic_width(graphic);
1095 int src_image_height = get_scaled_graphic_height(graphic);
1097 if (src_image_width == 0 || src_image_height == 0)
1099 /* only happens when loaded outside artwork system (like "global.busy") */
1100 src_image_width = src_bitmap->width;
1101 src_image_height = src_bitmap->height;
1104 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1106 anim_frames_per_row = src_image_width / g->tile_size;
1107 anim_frames_per_col = src_image_height / g->tile_size;
1111 anim_frames_per_row = src_image_width / g->width;
1112 anim_frames_per_col = src_image_height / g->height;
1115 g->src_image_width = src_image_width;
1116 g->src_image_height = src_image_height;
1119 /* correct x or y offset dependent of vertical or horizontal frame order */
1120 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1122 g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1123 parameter[GFX_ARG_OFFSET] : g->height);
1124 anim_frames_per_line = anim_frames_per_col;
1126 else /* frames are ordered horizontally */
1128 g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1129 parameter[GFX_ARG_OFFSET] : g->width);
1130 anim_frames_per_line = anim_frames_per_row;
1133 /* optionally, the x and y offset of frames can be specified directly */
1134 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1135 g->offset_x = parameter[GFX_ARG_XOFFSET];
1136 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1137 g->offset_y = parameter[GFX_ARG_YOFFSET];
1139 /* optionally, moving animations may have separate start and end graphics */
1140 g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1142 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1143 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1145 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1146 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1147 g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1148 parameter[GFX_ARG_2ND_OFFSET] : g->height);
1149 else /* frames are ordered horizontally */
1150 g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1151 parameter[GFX_ARG_2ND_OFFSET] : g->width);
1153 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1154 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1155 g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1156 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1157 g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1159 /* optionally, the second movement tile can be specified as start tile */
1160 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1161 g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1163 /* automatically determine correct number of frames, if not defined */
1164 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1165 g->anim_frames = parameter[GFX_ARG_FRAMES];
1166 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1167 g->anim_frames = anim_frames_per_row;
1168 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1169 g->anim_frames = anim_frames_per_col;
1173 if (g->anim_frames == 0) /* frames must be at least 1 */
1176 g->anim_frames_per_line =
1177 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1178 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1180 g->anim_delay = parameter[GFX_ARG_DELAY];
1181 if (g->anim_delay == 0) /* delay must be at least 1 */
1184 g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1186 /* automatically determine correct start frame, if not defined */
1187 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1188 g->anim_start_frame = 0;
1189 else if (g->anim_mode & ANIM_REVERSE)
1190 g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1192 g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1194 /* animation synchronized with global frame counter, not move position */
1195 g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1197 /* optional element for cloning crumble graphics */
1198 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1199 g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1201 /* optional element for cloning digging graphics */
1202 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1203 g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1205 /* optional border size for "crumbling" diggable graphics */
1206 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1207 g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1209 /* this is only used for player "boring" and "sleeping" actions */
1210 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1211 g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1212 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1213 g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1214 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1215 g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1216 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1217 g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1219 /* this is only used for toon animations */
1220 g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1221 g->step_delay = parameter[GFX_ARG_STEP_DELAY];
1223 /* this is only used for drawing font characters */
1224 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1225 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1227 /* this is only used for drawing envelope graphics */
1228 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1230 /* optional graphic for cloning all graphics settings */
1231 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1232 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1234 /* optional settings for drawing title screens and title messages */
1235 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1236 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1237 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1238 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1239 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1240 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1241 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1242 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1243 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1244 g->align = parameter[GFX_ARG_ALIGN];
1245 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1246 g->valign = parameter[GFX_ARG_VALIGN];
1247 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1248 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1250 if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
1251 g->class = parameter[GFX_ARG_CLASS];
1252 if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
1253 g->style = parameter[GFX_ARG_STYLE];
1255 /* this is only used for drawing menu buttons and text */
1256 g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
1257 g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
1258 g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
1259 g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
1262 static void set_graphic_parameters(int graphic)
1264 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1265 char **parameter_raw = image->parameter;
1266 Bitmap *src_bitmap = getBitmapFromImageID(graphic);
1267 int parameter[NUM_GFX_ARGS];
1270 /* if fallback to default artwork is done, also use the default parameters */
1271 if (image->fallback_to_default)
1272 parameter_raw = image->default_parameter;
1274 /* get integer values from string parameters */
1275 for (i = 0; i < NUM_GFX_ARGS; i++)
1276 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1277 image_config_suffix[i].token,
1278 image_config_suffix[i].type);
1280 set_graphic_parameters_ext(graphic, parameter, src_bitmap);
1282 UPDATE_BUSY_STATE();
1285 static void set_cloned_graphic_parameters(int graphic)
1287 int fallback_graphic = IMG_CHAR_EXCLAM;
1288 int max_num_images = getImageListSize();
1289 int clone_graphic = graphic_info[graphic].clone_from;
1290 int num_references_followed = 1;
1292 while (graphic_info[clone_graphic].clone_from != -1 &&
1293 num_references_followed < max_num_images)
1295 clone_graphic = graphic_info[clone_graphic].clone_from;
1297 num_references_followed++;
1300 if (num_references_followed >= max_num_images)
1302 Error(ERR_INFO_LINE, "-");
1303 Error(ERR_INFO, "warning: error found in config file:");
1304 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1305 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1306 Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1307 Error(ERR_INFO, "custom graphic rejected for this element/action");
1309 if (graphic == fallback_graphic)
1310 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1312 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1313 Error(ERR_INFO_LINE, "-");
1315 graphic_info[graphic] = graphic_info[fallback_graphic];
1319 graphic_info[graphic] = graphic_info[clone_graphic];
1320 graphic_info[graphic].clone_from = clone_graphic;
1324 static void InitGraphicInfo()
1326 int fallback_graphic = IMG_CHAR_EXCLAM;
1327 int num_images = getImageListSize();
1330 /* use image size as default values for width and height for these images */
1331 static int full_size_graphics[] =
1336 IMG_BACKGROUND_ENVELOPE_1,
1337 IMG_BACKGROUND_ENVELOPE_2,
1338 IMG_BACKGROUND_ENVELOPE_3,
1339 IMG_BACKGROUND_ENVELOPE_4,
1340 IMG_BACKGROUND_REQUEST,
1343 IMG_BACKGROUND_TITLE_INITIAL,
1344 IMG_BACKGROUND_TITLE,
1345 IMG_BACKGROUND_MAIN,
1346 IMG_BACKGROUND_LEVELS,
1347 IMG_BACKGROUND_LEVELNR,
1348 IMG_BACKGROUND_SCORES,
1349 IMG_BACKGROUND_EDITOR,
1350 IMG_BACKGROUND_INFO,
1351 IMG_BACKGROUND_INFO_ELEMENTS,
1352 IMG_BACKGROUND_INFO_MUSIC,
1353 IMG_BACKGROUND_INFO_CREDITS,
1354 IMG_BACKGROUND_INFO_PROGRAM,
1355 IMG_BACKGROUND_INFO_VERSION,
1356 IMG_BACKGROUND_INFO_LEVELSET,
1357 IMG_BACKGROUND_SETUP,
1358 IMG_BACKGROUND_PLAYING,
1359 IMG_BACKGROUND_DOOR,
1360 IMG_BACKGROUND_TAPE,
1361 IMG_BACKGROUND_PANEL,
1362 IMG_BACKGROUND_PALETTE,
1363 IMG_BACKGROUND_TOOLBOX,
1365 IMG_TITLESCREEN_INITIAL_1,
1366 IMG_TITLESCREEN_INITIAL_2,
1367 IMG_TITLESCREEN_INITIAL_3,
1368 IMG_TITLESCREEN_INITIAL_4,
1369 IMG_TITLESCREEN_INITIAL_5,
1376 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1,
1377 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2,
1378 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3,
1379 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4,
1380 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5,
1381 IMG_BACKGROUND_TITLEMESSAGE_1,
1382 IMG_BACKGROUND_TITLEMESSAGE_2,
1383 IMG_BACKGROUND_TITLEMESSAGE_3,
1384 IMG_BACKGROUND_TITLEMESSAGE_4,
1385 IMG_BACKGROUND_TITLEMESSAGE_5,
1390 checked_free(graphic_info);
1392 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1394 /* initialize "use_image_size" flag with default value */
1395 for (i = 0; i < num_images; i++)
1396 graphic_info[i].use_image_size = FALSE;
1398 /* initialize "use_image_size" flag from static configuration above */
1399 for (i = 0; full_size_graphics[i] != -1; i++)
1400 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1402 /* first set all graphic paramaters ... */
1403 for (i = 0; i < num_images; i++)
1404 set_graphic_parameters(i);
1406 /* ... then copy these parameters for cloned graphics */
1407 for (i = 0; i < num_images; i++)
1408 if (graphic_info[i].clone_from != -1)
1409 set_cloned_graphic_parameters(i);
1411 for (i = 0; i < num_images; i++)
1416 int first_frame, last_frame;
1417 int src_bitmap_width, src_bitmap_height;
1419 /* now check if no animation frames are outside of the loaded image */
1421 if (graphic_info[i].bitmap == NULL)
1422 continue; /* skip check for optional images that are undefined */
1424 /* get image size (this can differ from the standard element tile size!) */
1425 width = graphic_info[i].width;
1426 height = graphic_info[i].height;
1428 /* get final bitmap size (with scaling, but without small images) */
1429 src_bitmap_width = graphic_info[i].src_image_width;
1430 src_bitmap_height = graphic_info[i].src_image_height;
1432 /* check if first animation frame is inside specified bitmap */
1435 getFixedGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1437 /* this avoids calculating wrong start position for out-of-bounds frame */
1438 src_x = graphic_info[i].src_x;
1439 src_y = graphic_info[i].src_y;
1441 if (src_x < 0 || src_y < 0 ||
1442 src_x + width > src_bitmap_width ||
1443 src_y + height > src_bitmap_height)
1445 Error(ERR_INFO_LINE, "-");
1446 Error(ERR_INFO, "warning: error found in config file:");
1447 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1448 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1449 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1451 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1452 src_x, src_y, src_bitmap_width, src_bitmap_height);
1453 Error(ERR_INFO, "custom graphic rejected for this element/action");
1455 if (i == fallback_graphic)
1456 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1458 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1459 Error(ERR_INFO_LINE, "-");
1461 graphic_info[i] = graphic_info[fallback_graphic];
1464 /* check if last animation frame is inside specified bitmap */
1466 last_frame = graphic_info[i].anim_frames - 1;
1467 getFixedGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1469 if (src_x < 0 || src_y < 0 ||
1470 src_x + width > src_bitmap_width ||
1471 src_y + height > src_bitmap_height)
1473 Error(ERR_INFO_LINE, "-");
1474 Error(ERR_INFO, "warning: error found in config file:");
1475 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1476 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1477 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1479 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1480 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1481 Error(ERR_INFO, "::: %d, %d", width, height);
1482 Error(ERR_INFO, "custom graphic rejected for this element/action");
1484 if (i == fallback_graphic)
1485 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1487 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1488 Error(ERR_INFO_LINE, "-");
1490 graphic_info[i] = graphic_info[fallback_graphic];
1495 static void InitGraphicCompatibilityInfo()
1497 struct FileInfo *fi_global_door =
1498 getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1499 int num_images = getImageListSize();
1502 /* the following compatibility handling is needed for the following case:
1503 versions up to 3.3.0.0 used one large bitmap "global.door" for various
1504 graphics mainly used for door and panel graphics, like editor, tape and
1505 in-game buttons with hard-coded bitmap positions and button sizes; as
1506 these graphics now have individual definitions, redefining "global.door"
1507 to change all these graphics at once like before does not work anymore
1508 (because all those individual definitions still have their default values);
1509 to solve this, remap all those individual definitions that are not
1510 redefined to the new bitmap of "global.door" if it was redefined */
1512 /* special compatibility handling if image "global.door" was redefined */
1513 if (fi_global_door->redefined)
1515 for (i = 0; i < num_images; i++)
1517 struct FileInfo *fi = getImageListEntryFromImageID(i);
1519 /* process only those images that still use the default settings */
1522 /* process all images which default to same image as "global.door" */
1523 if (strEqual(fi->default_filename, fi_global_door->default_filename))
1525 // printf("::: special treatment needed for token '%s'\n", fi->token);
1527 graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
1533 InitGraphicCompatibilityInfo_Doors();
1536 static void InitElementSoundInfo()
1538 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1539 int num_property_mappings = getSoundListPropertyMappingSize();
1542 /* set values to -1 to identify later as "uninitialized" values */
1543 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1544 for (act = 0; act < NUM_ACTIONS; act++)
1545 element_info[i].sound[act] = -1;
1547 /* initialize element/sound mapping from static configuration */
1548 for (i = 0; element_to_sound[i].element > -1; i++)
1550 int element = element_to_sound[i].element;
1551 int action = element_to_sound[i].action;
1552 int sound = element_to_sound[i].sound;
1553 boolean is_class = element_to_sound[i].is_class;
1556 action = ACTION_DEFAULT;
1559 element_info[element].sound[action] = sound;
1561 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1562 if (strEqual(element_info[j].class_name,
1563 element_info[element].class_name))
1564 element_info[j].sound[action] = sound;
1567 /* initialize element class/sound mapping from dynamic configuration */
1568 for (i = 0; i < num_property_mappings; i++)
1570 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1571 int action = property_mapping[i].ext1_index;
1572 int sound = property_mapping[i].artwork_index;
1574 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1578 action = ACTION_DEFAULT;
1580 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1581 if (strEqual(element_info[j].class_name,
1582 element_info[element_class].class_name))
1583 element_info[j].sound[action] = sound;
1586 /* initialize element/sound mapping from dynamic configuration */
1587 for (i = 0; i < num_property_mappings; i++)
1589 int element = property_mapping[i].base_index;
1590 int action = property_mapping[i].ext1_index;
1591 int sound = property_mapping[i].artwork_index;
1593 if (element >= MAX_NUM_ELEMENTS)
1597 action = ACTION_DEFAULT;
1599 element_info[element].sound[action] = sound;
1602 /* now set all '-1' values to element specific default values */
1603 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1605 for (act = 0; act < NUM_ACTIONS; act++)
1607 /* generic default action sound (defined by "[default]" directive) */
1608 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1610 /* look for special default action sound (classic game specific) */
1611 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1612 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1613 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1614 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1615 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1616 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1618 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1619 /* !!! make this better !!! */
1620 if (i == EL_EMPTY_SPACE)
1621 default_action_sound = element_info[EL_DEFAULT].sound[act];
1623 /* no sound for this specific action -- use default action sound */
1624 if (element_info[i].sound[act] == -1)
1625 element_info[i].sound[act] = default_action_sound;
1629 /* copy sound settings to some elements that are only stored in level file
1630 in native R'n'D levels, but are used by game engine in native EM levels */
1631 for (i = 0; copy_properties[i][0] != -1; i++)
1632 for (j = 1; j <= 4; j++)
1633 for (act = 0; act < NUM_ACTIONS; act++)
1634 element_info[copy_properties[i][j]].sound[act] =
1635 element_info[copy_properties[i][0]].sound[act];
1638 static void InitGameModeSoundInfo()
1642 /* set values to -1 to identify later as "uninitialized" values */
1643 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1646 /* initialize gamemode/sound mapping from static configuration */
1647 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1649 int gamemode = gamemode_to_sound[i].gamemode;
1650 int sound = gamemode_to_sound[i].sound;
1653 gamemode = GAME_MODE_DEFAULT;
1655 menu.sound[gamemode] = sound;
1658 /* now set all '-1' values to levelset specific default values */
1659 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1660 if (menu.sound[i] == -1)
1661 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1664 static void set_sound_parameters(int sound, char **parameter_raw)
1666 int parameter[NUM_SND_ARGS];
1669 /* get integer values from string parameters */
1670 for (i = 0; i < NUM_SND_ARGS; i++)
1672 get_parameter_value(parameter_raw[i],
1673 sound_config_suffix[i].token,
1674 sound_config_suffix[i].type);
1676 /* explicit loop mode setting in configuration overrides default value */
1677 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1678 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1680 /* sound volume to change the original volume when loading the sound file */
1681 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1683 /* sound priority to give certain sounds a higher or lower priority */
1684 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
1687 static void InitSoundInfo()
1689 int *sound_effect_properties;
1690 int num_sounds = getSoundListSize();
1693 checked_free(sound_info);
1695 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1696 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1698 /* initialize sound effect for all elements to "no sound" */
1699 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1700 for (j = 0; j < NUM_ACTIONS; j++)
1701 element_info[i].sound[j] = SND_UNDEFINED;
1703 for (i = 0; i < num_sounds; i++)
1705 struct FileInfo *sound = getSoundListEntry(i);
1706 int len_effect_text = strlen(sound->token);
1708 sound_effect_properties[i] = ACTION_OTHER;
1709 sound_info[i].loop = FALSE; /* default: play sound only once */
1711 /* determine all loop sounds and identify certain sound classes */
1713 for (j = 0; element_action_info[j].suffix; j++)
1715 int len_action_text = strlen(element_action_info[j].suffix);
1717 if (len_action_text < len_effect_text &&
1718 strEqual(&sound->token[len_effect_text - len_action_text],
1719 element_action_info[j].suffix))
1721 sound_effect_properties[i] = element_action_info[j].value;
1722 sound_info[i].loop = element_action_info[j].is_loop_sound;
1728 /* associate elements and some selected sound actions */
1730 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1732 if (element_info[j].class_name)
1734 int len_class_text = strlen(element_info[j].class_name);
1736 if (len_class_text + 1 < len_effect_text &&
1737 strncmp(sound->token,
1738 element_info[j].class_name, len_class_text) == 0 &&
1739 sound->token[len_class_text] == '.')
1741 int sound_action_value = sound_effect_properties[i];
1743 element_info[j].sound[sound_action_value] = i;
1748 set_sound_parameters(i, sound->parameter);
1751 free(sound_effect_properties);
1754 static void InitGameModeMusicInfo()
1756 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1757 int num_property_mappings = getMusicListPropertyMappingSize();
1758 int default_levelset_music = -1;
1761 /* set values to -1 to identify later as "uninitialized" values */
1762 for (i = 0; i < MAX_LEVELS; i++)
1763 levelset.music[i] = -1;
1764 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1767 /* initialize gamemode/music mapping from static configuration */
1768 for (i = 0; gamemode_to_music[i].music > -1; i++)
1770 int gamemode = gamemode_to_music[i].gamemode;
1771 int music = gamemode_to_music[i].music;
1774 gamemode = GAME_MODE_DEFAULT;
1776 menu.music[gamemode] = music;
1779 /* initialize gamemode/music mapping from dynamic configuration */
1780 for (i = 0; i < num_property_mappings; i++)
1782 int prefix = property_mapping[i].base_index;
1783 int gamemode = property_mapping[i].ext1_index;
1784 int level = property_mapping[i].ext2_index;
1785 int music = property_mapping[i].artwork_index;
1787 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1791 gamemode = GAME_MODE_DEFAULT;
1793 /* level specific music only allowed for in-game music */
1794 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1795 gamemode = GAME_MODE_PLAYING;
1800 default_levelset_music = music;
1803 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1804 levelset.music[level] = music;
1805 if (gamemode != GAME_MODE_PLAYING)
1806 menu.music[gamemode] = music;
1809 /* now set all '-1' values to menu specific default values */
1810 /* (undefined values of "levelset.music[]" might stay at "-1" to
1811 allow dynamic selection of music files from music directory!) */
1812 for (i = 0; i < MAX_LEVELS; i++)
1813 if (levelset.music[i] == -1)
1814 levelset.music[i] = default_levelset_music;
1815 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1816 if (menu.music[i] == -1)
1817 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1820 static void set_music_parameters(int music, char **parameter_raw)
1822 int parameter[NUM_MUS_ARGS];
1825 /* get integer values from string parameters */
1826 for (i = 0; i < NUM_MUS_ARGS; i++)
1828 get_parameter_value(parameter_raw[i],
1829 music_config_suffix[i].token,
1830 music_config_suffix[i].type);
1832 /* explicit loop mode setting in configuration overrides default value */
1833 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1834 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1837 static void InitMusicInfo()
1839 int num_music = getMusicListSize();
1842 checked_free(music_info);
1844 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1846 for (i = 0; i < num_music; i++)
1848 struct FileInfo *music = getMusicListEntry(i);
1849 int len_music_text = strlen(music->token);
1851 music_info[i].loop = TRUE; /* default: play music in loop mode */
1853 /* determine all loop music */
1855 for (j = 0; music_prefix_info[j].prefix; j++)
1857 int len_prefix_text = strlen(music_prefix_info[j].prefix);
1859 if (len_prefix_text < len_music_text &&
1860 strncmp(music->token,
1861 music_prefix_info[j].prefix, len_prefix_text) == 0)
1863 music_info[i].loop = music_prefix_info[j].is_loop_music;
1869 set_music_parameters(i, music->parameter);
1873 static void ReinitializeGraphics()
1875 print_timestamp_init("ReinitializeGraphics");
1877 InitGfxTileSizeInfo(game.tile_size, TILESIZE);
1879 InitGraphicInfo(); /* graphic properties mapping */
1880 print_timestamp_time("InitGraphicInfo");
1881 InitElementGraphicInfo(); /* element game graphic mapping */
1882 print_timestamp_time("InitElementGraphicInfo");
1883 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
1884 print_timestamp_time("InitElementSpecialGraphicInfo");
1886 InitElementSmallImages(); /* scale elements to all needed sizes */
1887 print_timestamp_time("InitElementSmallImages");
1888 InitScaledImages(); /* scale all other images, if needed */
1889 print_timestamp_time("InitScaledImages");
1890 InitFontGraphicInfo(); /* initialize text drawing functions */
1891 print_timestamp_time("InitFontGraphicInfo");
1893 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
1894 print_timestamp_time("InitGraphicInfo_EM");
1896 InitGraphicCompatibilityInfo();
1897 print_timestamp_time("InitGraphicCompatibilityInfo");
1899 SetMainBackgroundImage(IMG_BACKGROUND);
1900 print_timestamp_time("SetMainBackgroundImage");
1901 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1902 print_timestamp_time("SetDoorBackgroundImage");
1905 print_timestamp_time("InitGadgets");
1907 print_timestamp_time("InitToons");
1909 print_timestamp_time("InitDoors");
1911 print_timestamp_done("ReinitializeGraphics");
1914 static void ReinitializeSounds()
1916 InitSoundInfo(); /* sound properties mapping */
1917 InitElementSoundInfo(); /* element game sound mapping */
1918 InitGameModeSoundInfo(); /* game mode sound mapping */
1920 InitPlayLevelSound(); /* internal game sound settings */
1923 static void ReinitializeMusic()
1925 InitMusicInfo(); /* music properties mapping */
1926 InitGameModeMusicInfo(); /* game mode music mapping */
1929 static int get_special_property_bit(int element, int property_bit_nr)
1931 struct PropertyBitInfo
1937 static struct PropertyBitInfo pb_can_move_into_acid[] =
1939 /* the player may be able fall into acid when gravity is activated */
1944 { EL_SP_MURPHY, 0 },
1945 { EL_SOKOBAN_FIELD_PLAYER, 0 },
1947 /* all elements that can move may be able to also move into acid */
1950 { EL_BUG_RIGHT, 1 },
1953 { EL_SPACESHIP, 2 },
1954 { EL_SPACESHIP_LEFT, 2 },
1955 { EL_SPACESHIP_RIGHT, 2 },
1956 { EL_SPACESHIP_UP, 2 },
1957 { EL_SPACESHIP_DOWN, 2 },
1958 { EL_BD_BUTTERFLY, 3 },
1959 { EL_BD_BUTTERFLY_LEFT, 3 },
1960 { EL_BD_BUTTERFLY_RIGHT, 3 },
1961 { EL_BD_BUTTERFLY_UP, 3 },
1962 { EL_BD_BUTTERFLY_DOWN, 3 },
1963 { EL_BD_FIREFLY, 4 },
1964 { EL_BD_FIREFLY_LEFT, 4 },
1965 { EL_BD_FIREFLY_RIGHT, 4 },
1966 { EL_BD_FIREFLY_UP, 4 },
1967 { EL_BD_FIREFLY_DOWN, 4 },
1969 { EL_YAMYAM_LEFT, 5 },
1970 { EL_YAMYAM_RIGHT, 5 },
1971 { EL_YAMYAM_UP, 5 },
1972 { EL_YAMYAM_DOWN, 5 },
1973 { EL_DARK_YAMYAM, 6 },
1976 { EL_PACMAN_LEFT, 8 },
1977 { EL_PACMAN_RIGHT, 8 },
1978 { EL_PACMAN_UP, 8 },
1979 { EL_PACMAN_DOWN, 8 },
1981 { EL_MOLE_LEFT, 9 },
1982 { EL_MOLE_RIGHT, 9 },
1984 { EL_MOLE_DOWN, 9 },
1988 { EL_SATELLITE, 13 },
1989 { EL_SP_SNIKSNAK, 14 },
1990 { EL_SP_ELECTRON, 15 },
1993 { EL_EMC_ANDROID, 18 },
1998 static struct PropertyBitInfo pb_dont_collide_with[] =
2000 { EL_SP_SNIKSNAK, 0 },
2001 { EL_SP_ELECTRON, 1 },
2009 struct PropertyBitInfo *pb_info;
2012 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2013 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2018 struct PropertyBitInfo *pb_info = NULL;
2021 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2022 if (pb_definition[i].bit_nr == property_bit_nr)
2023 pb_info = pb_definition[i].pb_info;
2025 if (pb_info == NULL)
2028 for (i = 0; pb_info[i].element != -1; i++)
2029 if (pb_info[i].element == element)
2030 return pb_info[i].bit_nr;
2035 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2036 boolean property_value)
2038 int bit_nr = get_special_property_bit(element, property_bit_nr);
2043 *bitfield |= (1 << bit_nr);
2045 *bitfield &= ~(1 << bit_nr);
2049 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2051 int bit_nr = get_special_property_bit(element, property_bit_nr);
2054 return ((*bitfield & (1 << bit_nr)) != 0);
2059 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2061 static int group_nr;
2062 static struct ElementGroupInfo *group;
2063 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2066 if (actual_group == NULL) /* not yet initialized */
2069 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
2071 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2072 group_element - EL_GROUP_START + 1);
2074 /* replace element which caused too deep recursion by question mark */
2075 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2080 if (recursion_depth == 0) /* initialization */
2082 group = actual_group;
2083 group_nr = GROUP_NR(group_element);
2085 group->num_elements_resolved = 0;
2086 group->choice_pos = 0;
2088 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2089 element_info[i].in_group[group_nr] = FALSE;
2092 for (i = 0; i < actual_group->num_elements; i++)
2094 int element = actual_group->element[i];
2096 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2099 if (IS_GROUP_ELEMENT(element))
2100 ResolveGroupElementExt(element, recursion_depth + 1);
2103 group->element_resolved[group->num_elements_resolved++] = element;
2104 element_info[element].in_group[group_nr] = TRUE;
2109 void ResolveGroupElement(int group_element)
2111 ResolveGroupElementExt(group_element, 0);
2114 void InitElementPropertiesStatic()
2116 static boolean clipboard_elements_initialized = FALSE;
2118 static int ep_diggable[] =
2123 EL_SP_BUGGY_BASE_ACTIVATING,
2126 EL_INVISIBLE_SAND_ACTIVE,
2129 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2130 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2135 EL_SP_BUGGY_BASE_ACTIVE,
2142 static int ep_collectible_only[] =
2164 EL_DYNABOMB_INCREASE_NUMBER,
2165 EL_DYNABOMB_INCREASE_SIZE,
2166 EL_DYNABOMB_INCREASE_POWER,
2184 /* !!! handle separately !!! */
2185 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2191 static int ep_dont_run_into[] =
2193 /* same elements as in 'ep_dont_touch' */
2199 /* same elements as in 'ep_dont_collide_with' */
2211 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2216 EL_SP_BUGGY_BASE_ACTIVE,
2223 static int ep_dont_collide_with[] =
2225 /* same elements as in 'ep_dont_touch' */
2242 static int ep_dont_touch[] =
2252 static int ep_indestructible[] =
2256 EL_ACID_POOL_TOPLEFT,
2257 EL_ACID_POOL_TOPRIGHT,
2258 EL_ACID_POOL_BOTTOMLEFT,
2259 EL_ACID_POOL_BOTTOM,
2260 EL_ACID_POOL_BOTTOMRIGHT,
2261 EL_SP_HARDWARE_GRAY,
2262 EL_SP_HARDWARE_GREEN,
2263 EL_SP_HARDWARE_BLUE,
2265 EL_SP_HARDWARE_YELLOW,
2266 EL_SP_HARDWARE_BASE_1,
2267 EL_SP_HARDWARE_BASE_2,
2268 EL_SP_HARDWARE_BASE_3,
2269 EL_SP_HARDWARE_BASE_4,
2270 EL_SP_HARDWARE_BASE_5,
2271 EL_SP_HARDWARE_BASE_6,
2272 EL_INVISIBLE_STEELWALL,
2273 EL_INVISIBLE_STEELWALL_ACTIVE,
2274 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2275 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2276 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2277 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2278 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2279 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2280 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2281 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2282 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2283 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2284 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2285 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2287 EL_LIGHT_SWITCH_ACTIVE,
2288 EL_SIGN_EXCLAMATION,
2289 EL_SIGN_RADIOACTIVITY,
2296 EL_SIGN_ENTRY_FORBIDDEN,
2297 EL_SIGN_EMERGENCY_EXIT,
2305 EL_STEEL_EXIT_CLOSED,
2307 EL_STEEL_EXIT_OPENING,
2308 EL_STEEL_EXIT_CLOSING,
2309 EL_EM_STEEL_EXIT_CLOSED,
2310 EL_EM_STEEL_EXIT_OPEN,
2311 EL_EM_STEEL_EXIT_OPENING,
2312 EL_EM_STEEL_EXIT_CLOSING,
2313 EL_DC_STEELWALL_1_LEFT,
2314 EL_DC_STEELWALL_1_RIGHT,
2315 EL_DC_STEELWALL_1_TOP,
2316 EL_DC_STEELWALL_1_BOTTOM,
2317 EL_DC_STEELWALL_1_HORIZONTAL,
2318 EL_DC_STEELWALL_1_VERTICAL,
2319 EL_DC_STEELWALL_1_TOPLEFT,
2320 EL_DC_STEELWALL_1_TOPRIGHT,
2321 EL_DC_STEELWALL_1_BOTTOMLEFT,
2322 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2323 EL_DC_STEELWALL_1_TOPLEFT_2,
2324 EL_DC_STEELWALL_1_TOPRIGHT_2,
2325 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2326 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2327 EL_DC_STEELWALL_2_LEFT,
2328 EL_DC_STEELWALL_2_RIGHT,
2329 EL_DC_STEELWALL_2_TOP,
2330 EL_DC_STEELWALL_2_BOTTOM,
2331 EL_DC_STEELWALL_2_HORIZONTAL,
2332 EL_DC_STEELWALL_2_VERTICAL,
2333 EL_DC_STEELWALL_2_MIDDLE,
2334 EL_DC_STEELWALL_2_SINGLE,
2335 EL_STEELWALL_SLIPPERY,
2349 EL_GATE_1_GRAY_ACTIVE,
2350 EL_GATE_2_GRAY_ACTIVE,
2351 EL_GATE_3_GRAY_ACTIVE,
2352 EL_GATE_4_GRAY_ACTIVE,
2361 EL_EM_GATE_1_GRAY_ACTIVE,
2362 EL_EM_GATE_2_GRAY_ACTIVE,
2363 EL_EM_GATE_3_GRAY_ACTIVE,
2364 EL_EM_GATE_4_GRAY_ACTIVE,
2373 EL_EMC_GATE_5_GRAY_ACTIVE,
2374 EL_EMC_GATE_6_GRAY_ACTIVE,
2375 EL_EMC_GATE_7_GRAY_ACTIVE,
2376 EL_EMC_GATE_8_GRAY_ACTIVE,
2378 EL_DC_GATE_WHITE_GRAY,
2379 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2380 EL_DC_GATE_FAKE_GRAY,
2382 EL_SWITCHGATE_OPENING,
2383 EL_SWITCHGATE_CLOSED,
2384 EL_SWITCHGATE_CLOSING,
2385 EL_DC_SWITCHGATE_SWITCH_UP,
2386 EL_DC_SWITCHGATE_SWITCH_DOWN,
2388 EL_TIMEGATE_OPENING,
2390 EL_TIMEGATE_CLOSING,
2391 EL_DC_TIMEGATE_SWITCH,
2392 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2396 EL_TUBE_VERTICAL_LEFT,
2397 EL_TUBE_VERTICAL_RIGHT,
2398 EL_TUBE_HORIZONTAL_UP,
2399 EL_TUBE_HORIZONTAL_DOWN,
2404 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2405 EL_EXPANDABLE_STEELWALL_VERTICAL,
2406 EL_EXPANDABLE_STEELWALL_ANY,
2411 static int ep_slippery[] =
2425 EL_ROBOT_WHEEL_ACTIVE,
2431 EL_ACID_POOL_TOPLEFT,
2432 EL_ACID_POOL_TOPRIGHT,
2442 EL_STEELWALL_SLIPPERY,
2445 EL_EMC_WALL_SLIPPERY_1,
2446 EL_EMC_WALL_SLIPPERY_2,
2447 EL_EMC_WALL_SLIPPERY_3,
2448 EL_EMC_WALL_SLIPPERY_4,
2450 EL_EMC_MAGIC_BALL_ACTIVE,
2455 static int ep_can_change[] =
2460 static int ep_can_move[] =
2462 /* same elements as in 'pb_can_move_into_acid' */
2485 static int ep_can_fall[] =
2499 EL_QUICKSAND_FAST_FULL,
2501 EL_BD_MAGIC_WALL_FULL,
2502 EL_DC_MAGIC_WALL_FULL,
2516 static int ep_can_smash_player[] =
2542 static int ep_can_smash_enemies[] =
2551 static int ep_can_smash_everything[] =
2560 static int ep_explodes_by_fire[] =
2562 /* same elements as in 'ep_explodes_impact' */
2567 /* same elements as in 'ep_explodes_smashed' */
2577 EL_EM_DYNAMITE_ACTIVE,
2578 EL_DYNABOMB_PLAYER_1_ACTIVE,
2579 EL_DYNABOMB_PLAYER_2_ACTIVE,
2580 EL_DYNABOMB_PLAYER_3_ACTIVE,
2581 EL_DYNABOMB_PLAYER_4_ACTIVE,
2582 EL_DYNABOMB_INCREASE_NUMBER,
2583 EL_DYNABOMB_INCREASE_SIZE,
2584 EL_DYNABOMB_INCREASE_POWER,
2585 EL_SP_DISK_RED_ACTIVE,
2599 static int ep_explodes_smashed[] =
2601 /* same elements as in 'ep_explodes_impact' */
2615 static int ep_explodes_impact[] =
2624 static int ep_walkable_over[] =
2628 EL_SOKOBAN_FIELD_EMPTY,
2635 EL_EM_STEEL_EXIT_OPEN,
2636 EL_EM_STEEL_EXIT_OPENING,
2645 EL_GATE_1_GRAY_ACTIVE,
2646 EL_GATE_2_GRAY_ACTIVE,
2647 EL_GATE_3_GRAY_ACTIVE,
2648 EL_GATE_4_GRAY_ACTIVE,
2656 static int ep_walkable_inside[] =
2661 EL_TUBE_VERTICAL_LEFT,
2662 EL_TUBE_VERTICAL_RIGHT,
2663 EL_TUBE_HORIZONTAL_UP,
2664 EL_TUBE_HORIZONTAL_DOWN,
2673 static int ep_walkable_under[] =
2678 static int ep_passable_over[] =
2688 EL_EM_GATE_1_GRAY_ACTIVE,
2689 EL_EM_GATE_2_GRAY_ACTIVE,
2690 EL_EM_GATE_3_GRAY_ACTIVE,
2691 EL_EM_GATE_4_GRAY_ACTIVE,
2700 EL_EMC_GATE_5_GRAY_ACTIVE,
2701 EL_EMC_GATE_6_GRAY_ACTIVE,
2702 EL_EMC_GATE_7_GRAY_ACTIVE,
2703 EL_EMC_GATE_8_GRAY_ACTIVE,
2705 EL_DC_GATE_WHITE_GRAY,
2706 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2713 static int ep_passable_inside[] =
2719 EL_SP_PORT_HORIZONTAL,
2720 EL_SP_PORT_VERTICAL,
2722 EL_SP_GRAVITY_PORT_LEFT,
2723 EL_SP_GRAVITY_PORT_RIGHT,
2724 EL_SP_GRAVITY_PORT_UP,
2725 EL_SP_GRAVITY_PORT_DOWN,
2726 EL_SP_GRAVITY_ON_PORT_LEFT,
2727 EL_SP_GRAVITY_ON_PORT_RIGHT,
2728 EL_SP_GRAVITY_ON_PORT_UP,
2729 EL_SP_GRAVITY_ON_PORT_DOWN,
2730 EL_SP_GRAVITY_OFF_PORT_LEFT,
2731 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2732 EL_SP_GRAVITY_OFF_PORT_UP,
2733 EL_SP_GRAVITY_OFF_PORT_DOWN,
2738 static int ep_passable_under[] =
2743 static int ep_droppable[] =
2748 static int ep_explodes_1x1_old[] =
2753 static int ep_pushable[] =
2765 EL_SOKOBAN_FIELD_FULL,
2774 static int ep_explodes_cross_old[] =
2779 static int ep_protected[] =
2781 /* same elements as in 'ep_walkable_inside' */
2785 EL_TUBE_VERTICAL_LEFT,
2786 EL_TUBE_VERTICAL_RIGHT,
2787 EL_TUBE_HORIZONTAL_UP,
2788 EL_TUBE_HORIZONTAL_DOWN,
2794 /* same elements as in 'ep_passable_over' */
2803 EL_EM_GATE_1_GRAY_ACTIVE,
2804 EL_EM_GATE_2_GRAY_ACTIVE,
2805 EL_EM_GATE_3_GRAY_ACTIVE,
2806 EL_EM_GATE_4_GRAY_ACTIVE,
2815 EL_EMC_GATE_5_GRAY_ACTIVE,
2816 EL_EMC_GATE_6_GRAY_ACTIVE,
2817 EL_EMC_GATE_7_GRAY_ACTIVE,
2818 EL_EMC_GATE_8_GRAY_ACTIVE,
2820 EL_DC_GATE_WHITE_GRAY,
2821 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2825 /* same elements as in 'ep_passable_inside' */
2830 EL_SP_PORT_HORIZONTAL,
2831 EL_SP_PORT_VERTICAL,
2833 EL_SP_GRAVITY_PORT_LEFT,
2834 EL_SP_GRAVITY_PORT_RIGHT,
2835 EL_SP_GRAVITY_PORT_UP,
2836 EL_SP_GRAVITY_PORT_DOWN,
2837 EL_SP_GRAVITY_ON_PORT_LEFT,
2838 EL_SP_GRAVITY_ON_PORT_RIGHT,
2839 EL_SP_GRAVITY_ON_PORT_UP,
2840 EL_SP_GRAVITY_ON_PORT_DOWN,
2841 EL_SP_GRAVITY_OFF_PORT_LEFT,
2842 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2843 EL_SP_GRAVITY_OFF_PORT_UP,
2844 EL_SP_GRAVITY_OFF_PORT_DOWN,
2849 static int ep_throwable[] =
2854 static int ep_can_explode[] =
2856 /* same elements as in 'ep_explodes_impact' */
2861 /* same elements as in 'ep_explodes_smashed' */
2867 /* elements that can explode by explosion or by dragonfire */
2871 EL_EM_DYNAMITE_ACTIVE,
2872 EL_DYNABOMB_PLAYER_1_ACTIVE,
2873 EL_DYNABOMB_PLAYER_2_ACTIVE,
2874 EL_DYNABOMB_PLAYER_3_ACTIVE,
2875 EL_DYNABOMB_PLAYER_4_ACTIVE,
2876 EL_DYNABOMB_INCREASE_NUMBER,
2877 EL_DYNABOMB_INCREASE_SIZE,
2878 EL_DYNABOMB_INCREASE_POWER,
2879 EL_SP_DISK_RED_ACTIVE,
2887 /* elements that can explode only by explosion */
2893 static int ep_gravity_reachable[] =
2899 EL_INVISIBLE_SAND_ACTIVE,
2904 EL_SP_PORT_HORIZONTAL,
2905 EL_SP_PORT_VERTICAL,
2907 EL_SP_GRAVITY_PORT_LEFT,
2908 EL_SP_GRAVITY_PORT_RIGHT,
2909 EL_SP_GRAVITY_PORT_UP,
2910 EL_SP_GRAVITY_PORT_DOWN,
2911 EL_SP_GRAVITY_ON_PORT_LEFT,
2912 EL_SP_GRAVITY_ON_PORT_RIGHT,
2913 EL_SP_GRAVITY_ON_PORT_UP,
2914 EL_SP_GRAVITY_ON_PORT_DOWN,
2915 EL_SP_GRAVITY_OFF_PORT_LEFT,
2916 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2917 EL_SP_GRAVITY_OFF_PORT_UP,
2918 EL_SP_GRAVITY_OFF_PORT_DOWN,
2924 static int ep_player[] =
2931 EL_SOKOBAN_FIELD_PLAYER,
2937 static int ep_can_pass_magic_wall[] =
2951 static int ep_can_pass_dc_magic_wall[] =
2967 static int ep_switchable[] =
2971 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2972 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2973 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2974 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2975 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2976 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2977 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2978 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2979 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2980 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2981 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2982 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2983 EL_SWITCHGATE_SWITCH_UP,
2984 EL_SWITCHGATE_SWITCH_DOWN,
2985 EL_DC_SWITCHGATE_SWITCH_UP,
2986 EL_DC_SWITCHGATE_SWITCH_DOWN,
2988 EL_LIGHT_SWITCH_ACTIVE,
2990 EL_DC_TIMEGATE_SWITCH,
2991 EL_BALLOON_SWITCH_LEFT,
2992 EL_BALLOON_SWITCH_RIGHT,
2993 EL_BALLOON_SWITCH_UP,
2994 EL_BALLOON_SWITCH_DOWN,
2995 EL_BALLOON_SWITCH_ANY,
2996 EL_BALLOON_SWITCH_NONE,
2999 EL_EMC_MAGIC_BALL_SWITCH,
3000 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3005 static int ep_bd_element[] =
3039 static int ep_sp_element[] =
3041 /* should always be valid */
3044 /* standard classic Supaplex elements */
3051 EL_SP_HARDWARE_GRAY,
3059 EL_SP_GRAVITY_PORT_RIGHT,
3060 EL_SP_GRAVITY_PORT_DOWN,
3061 EL_SP_GRAVITY_PORT_LEFT,
3062 EL_SP_GRAVITY_PORT_UP,
3067 EL_SP_PORT_VERTICAL,
3068 EL_SP_PORT_HORIZONTAL,
3074 EL_SP_HARDWARE_BASE_1,
3075 EL_SP_HARDWARE_GREEN,
3076 EL_SP_HARDWARE_BLUE,
3078 EL_SP_HARDWARE_YELLOW,
3079 EL_SP_HARDWARE_BASE_2,
3080 EL_SP_HARDWARE_BASE_3,
3081 EL_SP_HARDWARE_BASE_4,
3082 EL_SP_HARDWARE_BASE_5,
3083 EL_SP_HARDWARE_BASE_6,
3087 /* additional elements that appeared in newer Supaplex levels */
3090 /* additional gravity port elements (not switching, but setting gravity) */
3091 EL_SP_GRAVITY_ON_PORT_LEFT,
3092 EL_SP_GRAVITY_ON_PORT_RIGHT,
3093 EL_SP_GRAVITY_ON_PORT_UP,
3094 EL_SP_GRAVITY_ON_PORT_DOWN,
3095 EL_SP_GRAVITY_OFF_PORT_LEFT,
3096 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3097 EL_SP_GRAVITY_OFF_PORT_UP,
3098 EL_SP_GRAVITY_OFF_PORT_DOWN,
3100 /* more than one Murphy in a level results in an inactive clone */
3103 /* runtime Supaplex elements */
3104 EL_SP_DISK_RED_ACTIVE,
3105 EL_SP_TERMINAL_ACTIVE,
3106 EL_SP_BUGGY_BASE_ACTIVATING,
3107 EL_SP_BUGGY_BASE_ACTIVE,
3114 static int ep_sb_element[] =
3119 EL_SOKOBAN_FIELD_EMPTY,
3120 EL_SOKOBAN_FIELD_FULL,
3121 EL_SOKOBAN_FIELD_PLAYER,
3126 EL_INVISIBLE_STEELWALL,
3131 static int ep_gem[] =
3143 static int ep_food_dark_yamyam[] =
3171 static int ep_food_penguin[] =
3185 static int ep_food_pig[] =
3197 static int ep_historic_wall[] =
3208 EL_GATE_1_GRAY_ACTIVE,
3209 EL_GATE_2_GRAY_ACTIVE,
3210 EL_GATE_3_GRAY_ACTIVE,
3211 EL_GATE_4_GRAY_ACTIVE,
3220 EL_EM_GATE_1_GRAY_ACTIVE,
3221 EL_EM_GATE_2_GRAY_ACTIVE,
3222 EL_EM_GATE_3_GRAY_ACTIVE,
3223 EL_EM_GATE_4_GRAY_ACTIVE,
3230 EL_EXPANDABLE_WALL_HORIZONTAL,
3231 EL_EXPANDABLE_WALL_VERTICAL,
3232 EL_EXPANDABLE_WALL_ANY,
3233 EL_EXPANDABLE_WALL_GROWING,
3234 EL_BD_EXPANDABLE_WALL,
3241 EL_SP_HARDWARE_GRAY,
3242 EL_SP_HARDWARE_GREEN,
3243 EL_SP_HARDWARE_BLUE,
3245 EL_SP_HARDWARE_YELLOW,
3246 EL_SP_HARDWARE_BASE_1,
3247 EL_SP_HARDWARE_BASE_2,
3248 EL_SP_HARDWARE_BASE_3,
3249 EL_SP_HARDWARE_BASE_4,
3250 EL_SP_HARDWARE_BASE_5,
3251 EL_SP_HARDWARE_BASE_6,
3253 EL_SP_TERMINAL_ACTIVE,
3256 EL_INVISIBLE_STEELWALL,
3257 EL_INVISIBLE_STEELWALL_ACTIVE,
3259 EL_INVISIBLE_WALL_ACTIVE,
3260 EL_STEELWALL_SLIPPERY,
3277 static int ep_historic_solid[] =
3281 EL_EXPANDABLE_WALL_HORIZONTAL,
3282 EL_EXPANDABLE_WALL_VERTICAL,
3283 EL_EXPANDABLE_WALL_ANY,
3284 EL_BD_EXPANDABLE_WALL,
3297 EL_QUICKSAND_FILLING,
3298 EL_QUICKSAND_EMPTYING,
3300 EL_MAGIC_WALL_ACTIVE,
3301 EL_MAGIC_WALL_EMPTYING,
3302 EL_MAGIC_WALL_FILLING,
3306 EL_BD_MAGIC_WALL_ACTIVE,
3307 EL_BD_MAGIC_WALL_EMPTYING,
3308 EL_BD_MAGIC_WALL_FULL,
3309 EL_BD_MAGIC_WALL_FILLING,
3310 EL_BD_MAGIC_WALL_DEAD,
3319 EL_SP_TERMINAL_ACTIVE,
3323 EL_INVISIBLE_WALL_ACTIVE,
3324 EL_SWITCHGATE_SWITCH_UP,
3325 EL_SWITCHGATE_SWITCH_DOWN,
3326 EL_DC_SWITCHGATE_SWITCH_UP,
3327 EL_DC_SWITCHGATE_SWITCH_DOWN,
3329 EL_TIMEGATE_SWITCH_ACTIVE,
3330 EL_DC_TIMEGATE_SWITCH,
3331 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3343 /* the following elements are a direct copy of "indestructible" elements,
3344 except "EL_ACID", which is "indestructible", but not "solid"! */
3349 EL_ACID_POOL_TOPLEFT,
3350 EL_ACID_POOL_TOPRIGHT,
3351 EL_ACID_POOL_BOTTOMLEFT,
3352 EL_ACID_POOL_BOTTOM,
3353 EL_ACID_POOL_BOTTOMRIGHT,
3354 EL_SP_HARDWARE_GRAY,
3355 EL_SP_HARDWARE_GREEN,
3356 EL_SP_HARDWARE_BLUE,
3358 EL_SP_HARDWARE_YELLOW,
3359 EL_SP_HARDWARE_BASE_1,
3360 EL_SP_HARDWARE_BASE_2,
3361 EL_SP_HARDWARE_BASE_3,
3362 EL_SP_HARDWARE_BASE_4,
3363 EL_SP_HARDWARE_BASE_5,
3364 EL_SP_HARDWARE_BASE_6,
3365 EL_INVISIBLE_STEELWALL,
3366 EL_INVISIBLE_STEELWALL_ACTIVE,
3367 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3368 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3369 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3370 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3371 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3372 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3373 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3374 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3375 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3376 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3377 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3378 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3380 EL_LIGHT_SWITCH_ACTIVE,
3381 EL_SIGN_EXCLAMATION,
3382 EL_SIGN_RADIOACTIVITY,
3389 EL_SIGN_ENTRY_FORBIDDEN,
3390 EL_SIGN_EMERGENCY_EXIT,
3398 EL_STEEL_EXIT_CLOSED,
3400 EL_DC_STEELWALL_1_LEFT,
3401 EL_DC_STEELWALL_1_RIGHT,
3402 EL_DC_STEELWALL_1_TOP,
3403 EL_DC_STEELWALL_1_BOTTOM,
3404 EL_DC_STEELWALL_1_HORIZONTAL,
3405 EL_DC_STEELWALL_1_VERTICAL,
3406 EL_DC_STEELWALL_1_TOPLEFT,
3407 EL_DC_STEELWALL_1_TOPRIGHT,
3408 EL_DC_STEELWALL_1_BOTTOMLEFT,
3409 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3410 EL_DC_STEELWALL_1_TOPLEFT_2,
3411 EL_DC_STEELWALL_1_TOPRIGHT_2,
3412 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3413 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3414 EL_DC_STEELWALL_2_LEFT,
3415 EL_DC_STEELWALL_2_RIGHT,
3416 EL_DC_STEELWALL_2_TOP,
3417 EL_DC_STEELWALL_2_BOTTOM,
3418 EL_DC_STEELWALL_2_HORIZONTAL,
3419 EL_DC_STEELWALL_2_VERTICAL,
3420 EL_DC_STEELWALL_2_MIDDLE,
3421 EL_DC_STEELWALL_2_SINGLE,
3422 EL_STEELWALL_SLIPPERY,
3436 EL_GATE_1_GRAY_ACTIVE,
3437 EL_GATE_2_GRAY_ACTIVE,
3438 EL_GATE_3_GRAY_ACTIVE,
3439 EL_GATE_4_GRAY_ACTIVE,
3448 EL_EM_GATE_1_GRAY_ACTIVE,
3449 EL_EM_GATE_2_GRAY_ACTIVE,
3450 EL_EM_GATE_3_GRAY_ACTIVE,
3451 EL_EM_GATE_4_GRAY_ACTIVE,
3453 EL_SWITCHGATE_OPENING,
3454 EL_SWITCHGATE_CLOSED,
3455 EL_SWITCHGATE_CLOSING,
3457 EL_TIMEGATE_OPENING,
3459 EL_TIMEGATE_CLOSING,
3463 EL_TUBE_VERTICAL_LEFT,
3464 EL_TUBE_VERTICAL_RIGHT,
3465 EL_TUBE_HORIZONTAL_UP,
3466 EL_TUBE_HORIZONTAL_DOWN,
3475 static int ep_classic_enemy[] =
3492 static int ep_belt[] =
3494 EL_CONVEYOR_BELT_1_LEFT,
3495 EL_CONVEYOR_BELT_1_MIDDLE,
3496 EL_CONVEYOR_BELT_1_RIGHT,
3497 EL_CONVEYOR_BELT_2_LEFT,
3498 EL_CONVEYOR_BELT_2_MIDDLE,
3499 EL_CONVEYOR_BELT_2_RIGHT,
3500 EL_CONVEYOR_BELT_3_LEFT,
3501 EL_CONVEYOR_BELT_3_MIDDLE,
3502 EL_CONVEYOR_BELT_3_RIGHT,
3503 EL_CONVEYOR_BELT_4_LEFT,
3504 EL_CONVEYOR_BELT_4_MIDDLE,
3505 EL_CONVEYOR_BELT_4_RIGHT,
3510 static int ep_belt_active[] =
3512 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3513 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3514 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3515 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3516 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3517 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3518 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3519 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3520 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3521 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3522 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3523 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3528 static int ep_belt_switch[] =
3530 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3531 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3532 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3533 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3534 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3535 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3536 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3537 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3538 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3539 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3540 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3541 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3546 static int ep_tube[] =
3553 EL_TUBE_HORIZONTAL_UP,
3554 EL_TUBE_HORIZONTAL_DOWN,
3556 EL_TUBE_VERTICAL_LEFT,
3557 EL_TUBE_VERTICAL_RIGHT,
3563 static int ep_acid_pool[] =
3565 EL_ACID_POOL_TOPLEFT,
3566 EL_ACID_POOL_TOPRIGHT,
3567 EL_ACID_POOL_BOTTOMLEFT,
3568 EL_ACID_POOL_BOTTOM,
3569 EL_ACID_POOL_BOTTOMRIGHT,
3574 static int ep_keygate[] =
3584 EL_GATE_1_GRAY_ACTIVE,
3585 EL_GATE_2_GRAY_ACTIVE,
3586 EL_GATE_3_GRAY_ACTIVE,
3587 EL_GATE_4_GRAY_ACTIVE,
3596 EL_EM_GATE_1_GRAY_ACTIVE,
3597 EL_EM_GATE_2_GRAY_ACTIVE,
3598 EL_EM_GATE_3_GRAY_ACTIVE,
3599 EL_EM_GATE_4_GRAY_ACTIVE,
3608 EL_EMC_GATE_5_GRAY_ACTIVE,
3609 EL_EMC_GATE_6_GRAY_ACTIVE,
3610 EL_EMC_GATE_7_GRAY_ACTIVE,
3611 EL_EMC_GATE_8_GRAY_ACTIVE,
3613 EL_DC_GATE_WHITE_GRAY,
3614 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3619 static int ep_amoeboid[] =
3631 static int ep_amoebalive[] =
3642 static int ep_has_editor_content[] =
3648 EL_SOKOBAN_FIELD_PLAYER,
3665 static int ep_can_turn_each_move[] =
3667 /* !!! do something with this one !!! */
3671 static int ep_can_grow[] =
3685 static int ep_active_bomb[] =
3688 EL_EM_DYNAMITE_ACTIVE,
3689 EL_DYNABOMB_PLAYER_1_ACTIVE,
3690 EL_DYNABOMB_PLAYER_2_ACTIVE,
3691 EL_DYNABOMB_PLAYER_3_ACTIVE,
3692 EL_DYNABOMB_PLAYER_4_ACTIVE,
3693 EL_SP_DISK_RED_ACTIVE,
3698 static int ep_inactive[] =
3708 EL_QUICKSAND_FAST_EMPTY,
3731 EL_GATE_1_GRAY_ACTIVE,
3732 EL_GATE_2_GRAY_ACTIVE,
3733 EL_GATE_3_GRAY_ACTIVE,
3734 EL_GATE_4_GRAY_ACTIVE,
3743 EL_EM_GATE_1_GRAY_ACTIVE,
3744 EL_EM_GATE_2_GRAY_ACTIVE,
3745 EL_EM_GATE_3_GRAY_ACTIVE,
3746 EL_EM_GATE_4_GRAY_ACTIVE,
3755 EL_EMC_GATE_5_GRAY_ACTIVE,
3756 EL_EMC_GATE_6_GRAY_ACTIVE,
3757 EL_EMC_GATE_7_GRAY_ACTIVE,
3758 EL_EMC_GATE_8_GRAY_ACTIVE,
3760 EL_DC_GATE_WHITE_GRAY,
3761 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3762 EL_DC_GATE_FAKE_GRAY,
3765 EL_INVISIBLE_STEELWALL,
3773 EL_WALL_EMERALD_YELLOW,
3774 EL_DYNABOMB_INCREASE_NUMBER,
3775 EL_DYNABOMB_INCREASE_SIZE,
3776 EL_DYNABOMB_INCREASE_POWER,
3780 EL_SOKOBAN_FIELD_EMPTY,
3781 EL_SOKOBAN_FIELD_FULL,
3782 EL_WALL_EMERALD_RED,
3783 EL_WALL_EMERALD_PURPLE,
3784 EL_ACID_POOL_TOPLEFT,
3785 EL_ACID_POOL_TOPRIGHT,
3786 EL_ACID_POOL_BOTTOMLEFT,
3787 EL_ACID_POOL_BOTTOM,
3788 EL_ACID_POOL_BOTTOMRIGHT,
3792 EL_BD_MAGIC_WALL_DEAD,
3794 EL_DC_MAGIC_WALL_DEAD,
3795 EL_AMOEBA_TO_DIAMOND,
3803 EL_SP_GRAVITY_PORT_RIGHT,
3804 EL_SP_GRAVITY_PORT_DOWN,
3805 EL_SP_GRAVITY_PORT_LEFT,
3806 EL_SP_GRAVITY_PORT_UP,
3807 EL_SP_PORT_HORIZONTAL,
3808 EL_SP_PORT_VERTICAL,
3819 EL_SP_HARDWARE_GRAY,
3820 EL_SP_HARDWARE_GREEN,
3821 EL_SP_HARDWARE_BLUE,
3823 EL_SP_HARDWARE_YELLOW,
3824 EL_SP_HARDWARE_BASE_1,
3825 EL_SP_HARDWARE_BASE_2,
3826 EL_SP_HARDWARE_BASE_3,
3827 EL_SP_HARDWARE_BASE_4,
3828 EL_SP_HARDWARE_BASE_5,
3829 EL_SP_HARDWARE_BASE_6,
3830 EL_SP_GRAVITY_ON_PORT_LEFT,
3831 EL_SP_GRAVITY_ON_PORT_RIGHT,
3832 EL_SP_GRAVITY_ON_PORT_UP,
3833 EL_SP_GRAVITY_ON_PORT_DOWN,
3834 EL_SP_GRAVITY_OFF_PORT_LEFT,
3835 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3836 EL_SP_GRAVITY_OFF_PORT_UP,
3837 EL_SP_GRAVITY_OFF_PORT_DOWN,
3838 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3839 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3840 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3841 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3842 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3843 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3844 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3845 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3846 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3847 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3848 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3849 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3850 EL_SIGN_EXCLAMATION,
3851 EL_SIGN_RADIOACTIVITY,
3858 EL_SIGN_ENTRY_FORBIDDEN,
3859 EL_SIGN_EMERGENCY_EXIT,
3867 EL_DC_STEELWALL_1_LEFT,
3868 EL_DC_STEELWALL_1_RIGHT,
3869 EL_DC_STEELWALL_1_TOP,
3870 EL_DC_STEELWALL_1_BOTTOM,
3871 EL_DC_STEELWALL_1_HORIZONTAL,
3872 EL_DC_STEELWALL_1_VERTICAL,
3873 EL_DC_STEELWALL_1_TOPLEFT,
3874 EL_DC_STEELWALL_1_TOPRIGHT,
3875 EL_DC_STEELWALL_1_BOTTOMLEFT,
3876 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3877 EL_DC_STEELWALL_1_TOPLEFT_2,
3878 EL_DC_STEELWALL_1_TOPRIGHT_2,
3879 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3880 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3881 EL_DC_STEELWALL_2_LEFT,
3882 EL_DC_STEELWALL_2_RIGHT,
3883 EL_DC_STEELWALL_2_TOP,
3884 EL_DC_STEELWALL_2_BOTTOM,
3885 EL_DC_STEELWALL_2_HORIZONTAL,
3886 EL_DC_STEELWALL_2_VERTICAL,
3887 EL_DC_STEELWALL_2_MIDDLE,
3888 EL_DC_STEELWALL_2_SINGLE,
3889 EL_STEELWALL_SLIPPERY,
3894 EL_EMC_WALL_SLIPPERY_1,
3895 EL_EMC_WALL_SLIPPERY_2,
3896 EL_EMC_WALL_SLIPPERY_3,
3897 EL_EMC_WALL_SLIPPERY_4,
3918 static int ep_em_slippery_wall[] =
3923 static int ep_gfx_crumbled[] =
3934 static int ep_editor_cascade_active[] =
3936 EL_INTERNAL_CASCADE_BD_ACTIVE,
3937 EL_INTERNAL_CASCADE_EM_ACTIVE,
3938 EL_INTERNAL_CASCADE_EMC_ACTIVE,
3939 EL_INTERNAL_CASCADE_RND_ACTIVE,
3940 EL_INTERNAL_CASCADE_SB_ACTIVE,
3941 EL_INTERNAL_CASCADE_SP_ACTIVE,
3942 EL_INTERNAL_CASCADE_DC_ACTIVE,
3943 EL_INTERNAL_CASCADE_DX_ACTIVE,
3944 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
3945 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
3946 EL_INTERNAL_CASCADE_CE_ACTIVE,
3947 EL_INTERNAL_CASCADE_GE_ACTIVE,
3948 EL_INTERNAL_CASCADE_REF_ACTIVE,
3949 EL_INTERNAL_CASCADE_USER_ACTIVE,
3950 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
3955 static int ep_editor_cascade_inactive[] =
3957 EL_INTERNAL_CASCADE_BD,
3958 EL_INTERNAL_CASCADE_EM,
3959 EL_INTERNAL_CASCADE_EMC,
3960 EL_INTERNAL_CASCADE_RND,
3961 EL_INTERNAL_CASCADE_SB,
3962 EL_INTERNAL_CASCADE_SP,
3963 EL_INTERNAL_CASCADE_DC,
3964 EL_INTERNAL_CASCADE_DX,
3965 EL_INTERNAL_CASCADE_CHARS,
3966 EL_INTERNAL_CASCADE_STEEL_CHARS,
3967 EL_INTERNAL_CASCADE_CE,
3968 EL_INTERNAL_CASCADE_GE,
3969 EL_INTERNAL_CASCADE_REF,
3970 EL_INTERNAL_CASCADE_USER,
3971 EL_INTERNAL_CASCADE_DYNAMIC,
3976 static int ep_obsolete[] =
3980 EL_EM_KEY_1_FILE_OBSOLETE,
3981 EL_EM_KEY_2_FILE_OBSOLETE,
3982 EL_EM_KEY_3_FILE_OBSOLETE,
3983 EL_EM_KEY_4_FILE_OBSOLETE,
3984 EL_ENVELOPE_OBSOLETE,
3993 } element_properties[] =
3995 { ep_diggable, EP_DIGGABLE },
3996 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
3997 { ep_dont_run_into, EP_DONT_RUN_INTO },
3998 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
3999 { ep_dont_touch, EP_DONT_TOUCH },
4000 { ep_indestructible, EP_INDESTRUCTIBLE },
4001 { ep_slippery, EP_SLIPPERY },
4002 { ep_can_change, EP_CAN_CHANGE },
4003 { ep_can_move, EP_CAN_MOVE },
4004 { ep_can_fall, EP_CAN_FALL },
4005 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4006 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4007 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4008 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4009 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4010 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4011 { ep_walkable_over, EP_WALKABLE_OVER },
4012 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4013 { ep_walkable_under, EP_WALKABLE_UNDER },
4014 { ep_passable_over, EP_PASSABLE_OVER },
4015 { ep_passable_inside, EP_PASSABLE_INSIDE },
4016 { ep_passable_under, EP_PASSABLE_UNDER },
4017 { ep_droppable, EP_DROPPABLE },
4018 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4019 { ep_pushable, EP_PUSHABLE },
4020 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4021 { ep_protected, EP_PROTECTED },
4022 { ep_throwable, EP_THROWABLE },
4023 { ep_can_explode, EP_CAN_EXPLODE },
4024 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4026 { ep_player, EP_PLAYER },
4027 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4028 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4029 { ep_switchable, EP_SWITCHABLE },
4030 { ep_bd_element, EP_BD_ELEMENT },
4031 { ep_sp_element, EP_SP_ELEMENT },
4032 { ep_sb_element, EP_SB_ELEMENT },
4034 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4035 { ep_food_penguin, EP_FOOD_PENGUIN },
4036 { ep_food_pig, EP_FOOD_PIG },
4037 { ep_historic_wall, EP_HISTORIC_WALL },
4038 { ep_historic_solid, EP_HISTORIC_SOLID },
4039 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4040 { ep_belt, EP_BELT },
4041 { ep_belt_active, EP_BELT_ACTIVE },
4042 { ep_belt_switch, EP_BELT_SWITCH },
4043 { ep_tube, EP_TUBE },
4044 { ep_acid_pool, EP_ACID_POOL },
4045 { ep_keygate, EP_KEYGATE },
4046 { ep_amoeboid, EP_AMOEBOID },
4047 { ep_amoebalive, EP_AMOEBALIVE },
4048 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4049 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4050 { ep_can_grow, EP_CAN_GROW },
4051 { ep_active_bomb, EP_ACTIVE_BOMB },
4052 { ep_inactive, EP_INACTIVE },
4054 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4056 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4058 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4059 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4061 { ep_obsolete, EP_OBSOLETE },
4068 /* always start with reliable default values (element has no properties) */
4069 /* (but never initialize clipboard elements after the very first time) */
4070 /* (to be able to use clipboard elements between several levels) */
4071 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4072 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4073 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4074 SET_PROPERTY(i, j, FALSE);
4076 /* set all base element properties from above array definitions */
4077 for (i = 0; element_properties[i].elements != NULL; i++)
4078 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4079 SET_PROPERTY((element_properties[i].elements)[j],
4080 element_properties[i].property, TRUE);
4082 /* copy properties to some elements that are only stored in level file */
4083 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4084 for (j = 0; copy_properties[j][0] != -1; j++)
4085 if (HAS_PROPERTY(copy_properties[j][0], i))
4086 for (k = 1; k <= 4; k++)
4087 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4089 /* set static element properties that are not listed in array definitions */
4090 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4091 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4093 clipboard_elements_initialized = TRUE;
4096 void InitElementPropertiesEngine(int engine_version)
4098 static int no_wall_properties[] =
4101 EP_COLLECTIBLE_ONLY,
4103 EP_DONT_COLLIDE_WITH,
4106 EP_CAN_SMASH_PLAYER,
4107 EP_CAN_SMASH_ENEMIES,
4108 EP_CAN_SMASH_EVERYTHING,
4113 EP_FOOD_DARK_YAMYAM,
4129 /* important: after initialization in InitElementPropertiesStatic(), the
4130 elements are not again initialized to a default value; therefore all
4131 changes have to make sure that they leave the element with a defined
4132 property (which means that conditional property changes must be set to
4133 a reliable default value before) */
4135 /* resolve group elements */
4136 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4137 ResolveGroupElement(EL_GROUP_START + i);
4139 /* set all special, combined or engine dependent element properties */
4140 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4142 /* do not change (already initialized) clipboard elements here */
4143 if (IS_CLIPBOARD_ELEMENT(i))
4146 /* ---------- INACTIVE ------------------------------------------------- */
4147 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4148 i <= EL_CHAR_END) ||
4149 (i >= EL_STEEL_CHAR_START &&
4150 i <= EL_STEEL_CHAR_END)));
4152 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4153 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4154 IS_WALKABLE_INSIDE(i) ||
4155 IS_WALKABLE_UNDER(i)));
4157 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4158 IS_PASSABLE_INSIDE(i) ||
4159 IS_PASSABLE_UNDER(i)));
4161 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4162 IS_PASSABLE_OVER(i)));
4164 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4165 IS_PASSABLE_INSIDE(i)));
4167 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4168 IS_PASSABLE_UNDER(i)));
4170 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4173 /* ---------- COLLECTIBLE ---------------------------------------------- */
4174 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4178 /* ---------- SNAPPABLE ------------------------------------------------ */
4179 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4180 IS_COLLECTIBLE(i) ||
4184 /* ---------- WALL ----------------------------------------------------- */
4185 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4187 for (j = 0; no_wall_properties[j] != -1; j++)
4188 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4189 i >= EL_FIRST_RUNTIME_UNREAL)
4190 SET_PROPERTY(i, EP_WALL, FALSE);
4192 if (IS_HISTORIC_WALL(i))
4193 SET_PROPERTY(i, EP_WALL, TRUE);
4195 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4196 if (engine_version < VERSION_IDENT(2,2,0,0))
4197 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4199 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4201 !IS_COLLECTIBLE(i)));
4203 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4204 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4205 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4207 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4208 IS_INDESTRUCTIBLE(i)));
4210 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4212 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4213 else if (engine_version < VERSION_IDENT(2,2,0,0))
4214 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4216 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4220 if (IS_CUSTOM_ELEMENT(i))
4222 /* these are additional properties which are initially false when set */
4224 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4226 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4227 if (DONT_COLLIDE_WITH(i))
4228 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4230 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4231 if (CAN_SMASH_EVERYTHING(i))
4232 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4233 if (CAN_SMASH_ENEMIES(i))
4234 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4237 /* ---------- CAN_SMASH ------------------------------------------------ */
4238 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4239 CAN_SMASH_ENEMIES(i) ||
4240 CAN_SMASH_EVERYTHING(i)));
4242 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4243 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4244 EXPLODES_BY_FIRE(i)));
4246 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4247 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4248 EXPLODES_SMASHED(i)));
4250 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4251 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4252 EXPLODES_IMPACT(i)));
4254 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4255 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4257 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4258 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4259 i == EL_BLACK_ORB));
4261 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4262 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4264 IS_CUSTOM_ELEMENT(i)));
4266 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4267 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4268 i == EL_SP_ELECTRON));
4270 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4271 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4272 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4273 getMoveIntoAcidProperty(&level, i));
4275 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4276 if (MAYBE_DONT_COLLIDE_WITH(i))
4277 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4278 getDontCollideWithProperty(&level, i));
4280 /* ---------- SP_PORT -------------------------------------------------- */
4281 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4282 IS_PASSABLE_INSIDE(i)));
4284 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4285 for (j = 0; j < level.num_android_clone_elements; j++)
4286 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4288 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4290 /* ---------- CAN_CHANGE ----------------------------------------------- */
4291 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4292 for (j = 0; j < element_info[i].num_change_pages; j++)
4293 if (element_info[i].change_page[j].can_change)
4294 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4296 /* ---------- HAS_ACTION ----------------------------------------------- */
4297 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4298 for (j = 0; j < element_info[i].num_change_pages; j++)
4299 if (element_info[i].change_page[j].has_action)
4300 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4302 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4303 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4306 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4307 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4308 element_info[i].crumbled[ACTION_DEFAULT] !=
4309 element_info[i].graphic[ACTION_DEFAULT]);
4311 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4312 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4313 IS_EDITOR_CASCADE_INACTIVE(i)));
4316 /* dynamically adjust element properties according to game engine version */
4318 static int ep_em_slippery_wall[] =
4323 EL_EXPANDABLE_WALL_HORIZONTAL,
4324 EL_EXPANDABLE_WALL_VERTICAL,
4325 EL_EXPANDABLE_WALL_ANY,
4326 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4327 EL_EXPANDABLE_STEELWALL_VERTICAL,
4328 EL_EXPANDABLE_STEELWALL_ANY,
4329 EL_EXPANDABLE_STEELWALL_GROWING,
4333 static int ep_em_explodes_by_fire[] =
4336 EL_EM_DYNAMITE_ACTIVE,
4341 /* special EM style gems behaviour */
4342 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4343 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4344 level.em_slippery_gems);
4346 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4347 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4348 (level.em_slippery_gems &&
4349 engine_version > VERSION_IDENT(2,0,1,0)));
4351 /* special EM style explosion behaviour regarding chain reactions */
4352 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4353 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4354 level.em_explodes_by_fire);
4357 /* this is needed because some graphics depend on element properties */
4358 if (game_status == GAME_MODE_PLAYING)
4359 InitElementGraphicInfo();
4362 void InitElementPropertiesAfterLoading(int engine_version)
4366 /* set some other uninitialized values of custom elements in older levels */
4367 if (engine_version < VERSION_IDENT(3,1,0,0))
4369 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4371 int element = EL_CUSTOM_START + i;
4373 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4375 element_info[element].explosion_delay = 17;
4376 element_info[element].ignition_delay = 8;
4381 void InitElementPropertiesGfxElement()
4385 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4387 struct ElementInfo *ei = &element_info[i];
4389 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4393 static void InitGlobal()
4398 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4400 /* check if element_name_info entry defined for each element in "main.h" */
4401 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4402 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4404 element_info[i].token_name = element_name_info[i].token_name;
4405 element_info[i].class_name = element_name_info[i].class_name;
4406 element_info[i].editor_description= element_name_info[i].editor_description;
4409 /* create hash from image config list */
4410 image_config_hash = newSetupFileHash();
4411 for (i = 0; image_config[i].token != NULL; i++)
4412 setHashEntry(image_config_hash,
4413 image_config[i].token,
4414 image_config[i].value);
4416 /* create hash from element token list */
4417 element_token_hash = newSetupFileHash();
4418 for (i = 0; element_name_info[i].token_name != NULL; i++)
4419 setHashEntry(element_token_hash,
4420 element_name_info[i].token_name,
4423 /* create hash from graphic token list */
4424 graphic_token_hash = newSetupFileHash();
4425 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4426 if (strSuffix(image_config[i].value, ".png") ||
4427 strSuffix(image_config[i].value, ".pcx") ||
4428 strSuffix(image_config[i].value, ".wav") ||
4429 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4430 setHashEntry(graphic_token_hash,
4431 image_config[i].token,
4432 int2str(graphic++, 0));
4434 /* create hash from font token list */
4435 font_token_hash = newSetupFileHash();
4436 for (i = 0; font_info[i].token_name != NULL; i++)
4437 setHashEntry(font_token_hash,
4438 font_info[i].token_name,
4441 /* always start with reliable default values (all elements) */
4442 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4443 ActiveElement[i] = i;
4445 /* now add all entries that have an active state (active elements) */
4446 for (i = 0; element_with_active_state[i].element != -1; i++)
4448 int element = element_with_active_state[i].element;
4449 int element_active = element_with_active_state[i].element_active;
4451 ActiveElement[element] = element_active;
4454 /* always start with reliable default values (all buttons) */
4455 for (i = 0; i < NUM_IMAGE_FILES; i++)
4456 ActiveButton[i] = i;
4458 /* now add all entries that have an active state (active buttons) */
4459 for (i = 0; button_with_active_state[i].button != -1; i++)
4461 int button = button_with_active_state[i].button;
4462 int button_active = button_with_active_state[i].button_active;
4464 ActiveButton[button] = button_active;
4467 /* always start with reliable default values (all fonts) */
4468 for (i = 0; i < NUM_FONTS; i++)
4471 /* now add all entries that have an active state (active fonts) */
4472 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4474 int font = font_with_active_state[i].font_nr;
4475 int font_active = font_with_active_state[i].font_nr_active;
4477 ActiveFont[font] = font_active;
4480 global.autoplay_leveldir = NULL;
4481 global.convert_leveldir = NULL;
4482 global.create_images_dir = NULL;
4484 global.frames_per_second = 0;
4485 global.fps_slowdown = FALSE;
4486 global.fps_slowdown_factor = 1;
4488 global.border_status = GAME_MODE_MAIN;
4490 global.use_envelope_request = FALSE;
4493 void Execute_Command(char *command)
4497 if (strEqual(command, "print graphicsinfo.conf"))
4499 printf("# You can configure additional/alternative image files here.\n");
4500 printf("# (The entries below are default and therefore commented out.)\n");
4502 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4504 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4507 for (i = 0; image_config[i].token != NULL; i++)
4508 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
4509 image_config[i].value));
4513 else if (strEqual(command, "print soundsinfo.conf"))
4515 printf("# You can configure additional/alternative sound files here.\n");
4516 printf("# (The entries below are default and therefore commented out.)\n");
4518 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4520 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4523 for (i = 0; sound_config[i].token != NULL; i++)
4524 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4525 sound_config[i].value));
4529 else if (strEqual(command, "print musicinfo.conf"))
4531 printf("# You can configure additional/alternative music files here.\n");
4532 printf("# (The entries below are default and therefore commented out.)\n");
4534 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4536 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4539 for (i = 0; music_config[i].token != NULL; i++)
4540 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
4541 music_config[i].value));
4545 else if (strEqual(command, "print editorsetup.conf"))
4547 printf("# You can configure your personal editor element list here.\n");
4548 printf("# (The entries below are default and therefore commented out.)\n");
4551 /* this is needed to be able to check element list for cascade elements */
4552 InitElementPropertiesStatic();
4553 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4555 PrintEditorElementList();
4559 else if (strEqual(command, "print helpanim.conf"))
4561 printf("# You can configure different element help animations here.\n");
4562 printf("# (The entries below are default and therefore commented out.)\n");
4565 for (i = 0; helpanim_config[i].token != NULL; i++)
4567 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4568 helpanim_config[i].value));
4570 if (strEqual(helpanim_config[i].token, "end"))
4576 else if (strEqual(command, "print helptext.conf"))
4578 printf("# You can configure different element help text here.\n");
4579 printf("# (The entries below are default and therefore commented out.)\n");
4582 for (i = 0; helptext_config[i].token != NULL; i++)
4583 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4584 helptext_config[i].value));
4588 else if (strPrefix(command, "dump level "))
4590 char *filename = &command[11];
4592 if (!fileExists(filename))
4593 Error(ERR_EXIT, "cannot open file '%s'", filename);
4595 LoadLevelFromFilename(&level, filename);
4600 else if (strPrefix(command, "dump tape "))
4602 char *filename = &command[10];
4604 if (!fileExists(filename))
4605 Error(ERR_EXIT, "cannot open file '%s'", filename);
4607 LoadTapeFromFilename(filename);
4612 else if (strPrefix(command, "autoplay "))
4614 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
4616 while (*str_ptr != '\0') /* continue parsing string */
4618 /* cut leading whitespace from string, replace it by string terminator */
4619 while (*str_ptr == ' ' || *str_ptr == '\t')
4622 if (*str_ptr == '\0') /* end of string reached */
4625 if (global.autoplay_leveldir == NULL) /* read level set string */
4627 global.autoplay_leveldir = str_ptr;
4628 global.autoplay_all = TRUE; /* default: play all tapes */
4630 for (i = 0; i < MAX_TAPES_PER_SET; i++)
4631 global.autoplay_level[i] = FALSE;
4633 else /* read level number string */
4635 int level_nr = atoi(str_ptr); /* get level_nr value */
4637 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
4638 global.autoplay_level[level_nr] = TRUE;
4640 global.autoplay_all = FALSE;
4643 /* advance string pointer to the next whitespace (or end of string) */
4644 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
4648 else if (strPrefix(command, "convert "))
4650 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
4651 char *str_ptr = strchr(str_copy, ' ');
4653 global.convert_leveldir = str_copy;
4654 global.convert_level_nr = -1;
4656 if (str_ptr != NULL) /* level number follows */
4658 *str_ptr++ = '\0'; /* terminate leveldir string */
4659 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
4662 else if (strPrefix(command, "create images "))
4664 global.create_images_dir = getStringCopy(&command[14]);
4666 if (access(global.create_images_dir, W_OK) != 0)
4667 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
4668 global.create_images_dir);
4672 #if defined(TARGET_SDL2)
4673 else if (strEqual(command, "SDL_ListModes"))
4675 SDL_Init(SDL_INIT_VIDEO);
4677 int num_displays = SDL_GetNumVideoDisplays();
4679 // check if there are any displays available
4680 if (num_displays < 0)
4682 printf("No displays available: %s\n", SDL_GetError());
4687 for (i = 0; i < num_displays; i++)
4689 int num_modes = SDL_GetNumDisplayModes(i);
4692 printf("Available display modes for display %d:\n", i);
4694 // check if there are any display modes available for this display
4697 printf("No display modes available for display %d: %s\n",
4703 for (j = 0; j < num_modes; j++)
4705 SDL_DisplayMode mode;
4707 if (SDL_GetDisplayMode(i, j, &mode) < 0)
4709 printf("Cannot get display mode %d for display %d: %s\n",
4710 j, i, SDL_GetError());
4715 printf("- %d x %d\n", mode.w, mode.h);
4721 #elif defined(TARGET_SDL)
4722 else if (strEqual(command, "SDL_ListModes"))
4727 SDL_Init(SDL_INIT_VIDEO);
4729 /* get available fullscreen/hardware modes */
4730 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
4732 /* check if there are any modes available */
4735 printf("No modes available!\n");
4740 /* check if our resolution is restricted */
4741 if (modes == (SDL_Rect **)-1)
4743 printf("All resolutions available.\n");
4747 printf("Available display modes:\n");
4749 for (i = 0; modes[i]; i++)
4750 printf("- %d x %d\n", modes[i]->w, modes[i]->h);
4760 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4764 static void InitSetup()
4766 LoadSetup(); /* global setup info */
4768 /* set some options from setup file */
4770 if (setup.options.verbose)
4771 options.verbose = TRUE;
4774 static void InitGameInfo()
4776 game.restart_level = FALSE;
4779 static void InitPlayerInfo()
4783 /* choose default local player */
4784 local_player = &stored_player[0];
4786 for (i = 0; i < MAX_PLAYERS; i++)
4787 stored_player[i].connected = FALSE;
4789 local_player->connected = TRUE;
4792 static void InitArtworkInfo()
4797 static char *get_string_in_brackets(char *string)
4799 char *string_in_brackets = checked_malloc(strlen(string) + 3);
4801 sprintf(string_in_brackets, "[%s]", string);
4803 return string_in_brackets;
4806 static char *get_level_id_suffix(int id_nr)
4808 char *id_suffix = checked_malloc(1 + 3 + 1);
4810 if (id_nr < 0 || id_nr > 999)
4813 sprintf(id_suffix, ".%03d", id_nr);
4818 static void InitArtworkConfig()
4820 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
4821 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
4822 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
4823 static char *action_id_suffix[NUM_ACTIONS + 1];
4824 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
4825 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
4826 static char *level_id_suffix[MAX_LEVELS + 1];
4827 static char *dummy[1] = { NULL };
4828 static char *ignore_generic_tokens[] =
4834 static char **ignore_image_tokens;
4835 static char **ignore_sound_tokens;
4836 static char **ignore_music_tokens;
4837 int num_ignore_generic_tokens;
4838 int num_ignore_image_tokens;
4839 int num_ignore_sound_tokens;
4840 int num_ignore_music_tokens;
4843 /* dynamically determine list of generic tokens to be ignored */
4844 num_ignore_generic_tokens = 0;
4845 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
4846 num_ignore_generic_tokens++;
4848 /* dynamically determine list of image tokens to be ignored */
4849 num_ignore_image_tokens = num_ignore_generic_tokens;
4850 for (i = 0; image_config_vars[i].token != NULL; i++)
4851 num_ignore_image_tokens++;
4852 ignore_image_tokens =
4853 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
4854 for (i = 0; i < num_ignore_generic_tokens; i++)
4855 ignore_image_tokens[i] = ignore_generic_tokens[i];
4856 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
4857 ignore_image_tokens[num_ignore_generic_tokens + i] =
4858 image_config_vars[i].token;
4859 ignore_image_tokens[num_ignore_image_tokens] = NULL;
4861 /* dynamically determine list of sound tokens to be ignored */
4862 num_ignore_sound_tokens = num_ignore_generic_tokens;
4863 ignore_sound_tokens =
4864 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
4865 for (i = 0; i < num_ignore_generic_tokens; i++)
4866 ignore_sound_tokens[i] = ignore_generic_tokens[i];
4867 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
4869 /* dynamically determine list of music tokens to be ignored */
4870 num_ignore_music_tokens = num_ignore_generic_tokens;
4871 ignore_music_tokens =
4872 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
4873 for (i = 0; i < num_ignore_generic_tokens; i++)
4874 ignore_music_tokens[i] = ignore_generic_tokens[i];
4875 ignore_music_tokens[num_ignore_music_tokens] = NULL;
4877 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4878 image_id_prefix[i] = element_info[i].token_name;
4879 for (i = 0; i < NUM_FONTS; i++)
4880 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
4881 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
4883 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4884 sound_id_prefix[i] = element_info[i].token_name;
4885 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4886 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
4887 get_string_in_brackets(element_info[i].class_name);
4888 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
4890 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
4891 music_id_prefix[i] = music_prefix_info[i].prefix;
4892 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
4894 for (i = 0; i < NUM_ACTIONS; i++)
4895 action_id_suffix[i] = element_action_info[i].suffix;
4896 action_id_suffix[NUM_ACTIONS] = NULL;
4898 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
4899 direction_id_suffix[i] = element_direction_info[i].suffix;
4900 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
4902 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
4903 special_id_suffix[i] = special_suffix_info[i].suffix;
4904 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
4906 for (i = 0; i < MAX_LEVELS; i++)
4907 level_id_suffix[i] = get_level_id_suffix(i);
4908 level_id_suffix[MAX_LEVELS] = NULL;
4910 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
4911 image_id_prefix, action_id_suffix, direction_id_suffix,
4912 special_id_suffix, ignore_image_tokens);
4913 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
4914 sound_id_prefix, action_id_suffix, dummy,
4915 special_id_suffix, ignore_sound_tokens);
4916 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
4917 music_id_prefix, special_id_suffix, level_id_suffix,
4918 dummy, ignore_music_tokens);
4921 static void InitMixer()
4928 void InitGfxBuffers()
4930 /* create additional image buffers for double-buffering and cross-fading */
4931 ReCreateBitmap(&bitmap_db_store, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
4932 ReCreateBitmap(&bitmap_db_cross, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
4933 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE, DEFAULT_DEPTH);
4934 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE, DEFAULT_DEPTH);
4935 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE, DEFAULT_DEPTH);
4936 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE, DEFAULT_DEPTH);
4937 ReCreateBitmap(&bitmap_db_toons, FULL_SXSIZE, FULL_SYSIZE, DEFAULT_DEPTH);
4939 /* initialize screen properties */
4940 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
4941 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
4943 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
4944 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
4945 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
4946 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
4947 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
4948 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
4950 InitGfxBuffers_EM();
4951 InitGfxBuffers_SP();
4956 struct GraphicInfo *graphic_info_last = graphic_info;
4957 char *filename_font_initial = NULL;
4958 char *filename_anim_initial = NULL;
4959 Bitmap *bitmap_font_initial = NULL;
4963 /* determine settings for initial font (for displaying startup messages) */
4964 for (i = 0; image_config[i].token != NULL; i++)
4966 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4968 char font_token[128];
4971 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
4972 len_font_token = strlen(font_token);
4974 if (strEqual(image_config[i].token, font_token))
4975 filename_font_initial = image_config[i].value;
4976 else if (strlen(image_config[i].token) > len_font_token &&
4977 strncmp(image_config[i].token, font_token, len_font_token) == 0)
4979 if (strEqual(&image_config[i].token[len_font_token], ".x"))
4980 font_initial[j].src_x = atoi(image_config[i].value);
4981 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
4982 font_initial[j].src_y = atoi(image_config[i].value);
4983 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
4984 font_initial[j].width = atoi(image_config[i].value);
4985 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
4986 font_initial[j].height = atoi(image_config[i].value);
4991 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4993 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
4994 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
4997 if (filename_font_initial == NULL) /* should not happen */
4998 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5001 InitGfxCustomArtworkInfo();
5003 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5005 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5006 font_initial[j].bitmap = bitmap_font_initial;
5008 InitFontGraphicInfo();
5010 font_height = getFontHeight(FC_RED);
5012 DrawInitTextAlways(getProgramInitString(), 20, FC_YELLOW);
5013 DrawInitTextAlways(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
5014 DrawInitTextAlways(PROGRAM_WEBSITE_STRING, WIN_YSIZE - 20 - font_height,
5017 DrawInitTextAlways("Loading graphics", 120, FC_GREEN);
5019 /* initialize busy animation with default values */
5020 int parameter[NUM_GFX_ARGS];
5021 for (i = 0; i < NUM_GFX_ARGS; i++)
5022 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5023 image_config_suffix[i].token,
5024 image_config_suffix[i].type);
5026 /* determine settings for busy animation (when displaying startup messages) */
5027 for (i = 0; image_config[i].token != NULL; i++)
5029 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5030 int len_anim_token = strlen(anim_token);
5032 if (strEqual(image_config[i].token, anim_token))
5033 filename_anim_initial = image_config[i].value;
5034 else if (strlen(image_config[i].token) > len_anim_token &&
5035 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5037 for (j = 0; image_config_suffix[j].token != NULL; j++)
5039 if (strEqual(&image_config[i].token[len_anim_token],
5040 image_config_suffix[j].token))
5042 get_graphic_parameter_value(image_config[i].value,
5043 image_config_suffix[j].token,
5044 image_config_suffix[j].type);
5049 #if defined(CREATE_SPECIAL_EDITION_RND_JUE)
5050 filename_anim_initial = "loading.pcx";
5052 parameter[GFX_ARG_X] = 0;
5053 parameter[GFX_ARG_Y] = 0;
5054 parameter[GFX_ARG_WIDTH] = 128;
5055 parameter[GFX_ARG_HEIGHT] = 40;
5056 parameter[GFX_ARG_FRAMES] = 32;
5057 parameter[GFX_ARG_DELAY] = 4;
5058 parameter[GFX_ARG_FRAMES_PER_LINE] = ARG_UNDEFINED_VALUE;
5061 if (filename_anim_initial == NULL) /* should not happen */
5062 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5064 anim_initial.bitmap = LoadCustomImage(filename_anim_initial);
5066 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
5068 set_graphic_parameters_ext(0, parameter, anim_initial.bitmap);
5070 graphic_info = graphic_info_last;
5072 init.busy.width = anim_initial.width;
5073 init.busy.height = anim_initial.height;
5075 InitMenuDesignSettings_Static();
5076 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5078 /* use copy of busy animation to prevent change while reloading artwork */
5082 void RedrawBackground()
5084 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
5085 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
5087 redraw_mask = REDRAW_ALL;
5090 void InitGfxBackground()
5094 fieldbuffer = bitmap_db_field;
5095 SetDrawtoField(DRAW_BACKBUFFER);
5097 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5099 for (x = 0; x < MAX_BUF_XSIZE; x++)
5100 for (y = 0; y < MAX_BUF_YSIZE; y++)
5103 redraw_mask = REDRAW_ALL;
5106 static void InitLevelInfo()
5108 LoadLevelInfo(); /* global level info */
5109 LoadLevelSetup_LastSeries(); /* last played series info */
5110 LoadLevelSetup_SeriesInfo(); /* last played level info */
5113 static void InitLevelArtworkInfo()
5115 LoadLevelArtworkInfo();
5118 static void InitImages()
5120 print_timestamp_init("InitImages");
5123 printf("::: leveldir_current->identifier == '%s'\n",
5124 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5125 printf("::: leveldir_current->graphics_path == '%s'\n",
5126 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5127 printf("::: leveldir_current->graphics_set == '%s'\n",
5128 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5129 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5130 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5133 setLevelArtworkDir(artwork.gfx_first);
5136 printf("::: leveldir_current->identifier == '%s'\n",
5137 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5138 printf("::: leveldir_current->graphics_path == '%s'\n",
5139 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5140 printf("::: leveldir_current->graphics_set == '%s'\n",
5141 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5142 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5143 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5147 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5148 leveldir_current->identifier,
5149 artwork.gfx_current_identifier,
5150 artwork.gfx_current->identifier,
5151 leveldir_current->graphics_set,
5152 leveldir_current->graphics_path);
5155 UPDATE_BUSY_STATE();
5157 ReloadCustomImages();
5158 print_timestamp_time("ReloadCustomImages");
5160 UPDATE_BUSY_STATE();
5162 LoadCustomElementDescriptions();
5163 print_timestamp_time("LoadCustomElementDescriptions");
5165 UPDATE_BUSY_STATE();
5167 LoadMenuDesignSettings();
5168 print_timestamp_time("LoadMenuDesignSettings");
5170 UPDATE_BUSY_STATE();
5172 ReinitializeGraphics();
5173 print_timestamp_time("ReinitializeGraphics");
5175 UPDATE_BUSY_STATE();
5177 print_timestamp_done("InitImages");
5180 static void InitSound(char *identifier)
5182 print_timestamp_init("InitSound");
5184 if (identifier == NULL)
5185 identifier = artwork.snd_current->identifier;
5187 /* set artwork path to send it to the sound server process */
5188 setLevelArtworkDir(artwork.snd_first);
5190 InitReloadCustomSounds(identifier);
5191 print_timestamp_time("InitReloadCustomSounds");
5193 ReinitializeSounds();
5194 print_timestamp_time("ReinitializeSounds");
5196 print_timestamp_done("InitSound");
5199 static void InitMusic(char *identifier)
5201 print_timestamp_init("InitMusic");
5203 if (identifier == NULL)
5204 identifier = artwork.mus_current->identifier;
5206 /* set artwork path to send it to the sound server process */
5207 setLevelArtworkDir(artwork.mus_first);
5209 InitReloadCustomMusic(identifier);
5210 print_timestamp_time("InitReloadCustomMusic");
5212 ReinitializeMusic();
5213 print_timestamp_time("ReinitializeMusic");
5215 print_timestamp_done("InitMusic");
5218 void InitNetworkServer()
5220 #if defined(NETWORK_AVALIABLE)
5224 if (!options.network)
5227 #if defined(NETWORK_AVALIABLE)
5228 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5230 if (!ConnectToServer(options.server_host, options.server_port))
5231 Error(ERR_EXIT, "cannot connect to network game server");
5233 SendToServer_PlayerName(setup.player_name);
5234 SendToServer_ProtocolVersion();
5237 SendToServer_NrWanted(nr_wanted);
5241 static boolean CheckArtworkConfigForCustomElements(char *filename)
5243 SetupFileHash *setup_file_hash;
5244 boolean redefined_ce_found = FALSE;
5246 /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */
5248 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5250 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5252 char *token = HASH_ITERATION_TOKEN(itr);
5254 if (strPrefix(token, "custom_"))
5256 redefined_ce_found = TRUE;
5261 END_HASH_ITERATION(setup_file_hash, itr)
5263 freeSetupFileHash(setup_file_hash);
5266 return redefined_ce_found;
5269 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5271 char *filename_base, *filename_local;
5272 boolean redefined_ce_found = FALSE;
5274 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5277 printf("::: leveldir_current->identifier == '%s'\n",
5278 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5279 printf("::: leveldir_current->graphics_path == '%s'\n",
5280 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5281 printf("::: leveldir_current->graphics_set == '%s'\n",
5282 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5283 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5284 leveldir_current == NULL ? "[NULL]" :
5285 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5288 /* first look for special artwork configured in level series config */
5289 filename_base = getCustomArtworkLevelConfigFilename(type);
5292 printf("::: filename_base == '%s'\n", filename_base);
5295 if (fileExists(filename_base))
5296 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5298 filename_local = getCustomArtworkConfigFilename(type);
5301 printf("::: filename_local == '%s'\n", filename_local);
5304 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5305 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5308 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5311 return redefined_ce_found;
5314 static void InitOverrideArtwork()
5316 boolean redefined_ce_found = FALSE;
5318 /* to check if this level set redefines any CEs, do not use overriding */
5319 gfx.override_level_graphics = FALSE;
5320 gfx.override_level_sounds = FALSE;
5321 gfx.override_level_music = FALSE;
5323 /* now check if this level set has definitions for custom elements */
5324 if (setup.override_level_graphics == AUTO ||
5325 setup.override_level_sounds == AUTO ||
5326 setup.override_level_music == AUTO)
5327 redefined_ce_found =
5328 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5329 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5330 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5333 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5336 if (redefined_ce_found)
5338 /* this level set has CE definitions: change "AUTO" to "FALSE" */
5339 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5340 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
5341 gfx.override_level_music = (setup.override_level_music == TRUE);
5345 /* this level set has no CE definitions: change "AUTO" to "TRUE" */
5346 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5347 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
5348 gfx.override_level_music = (setup.override_level_music != FALSE);
5352 printf("::: => %d, %d, %d\n",
5353 gfx.override_level_graphics,
5354 gfx.override_level_sounds,
5355 gfx.override_level_music);
5359 static char *getNewArtworkIdentifier(int type)
5361 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5362 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5363 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5364 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5365 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5366 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5367 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5368 char *leveldir_identifier = leveldir_current->identifier;
5369 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
5370 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5371 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5372 char *artwork_current_identifier;
5373 char *artwork_new_identifier = NULL; /* default: nothing has changed */
5375 /* leveldir_current may be invalid (level group, parent link) */
5376 if (!validLevelSeries(leveldir_current))
5379 /* 1st step: determine artwork set to be activated in descending order:
5380 --------------------------------------------------------------------
5381 1. setup artwork (when configured to override everything else)
5382 2. artwork set configured in "levelinfo.conf" of current level set
5383 (artwork in level directory will have priority when loading later)
5384 3. artwork in level directory (stored in artwork sub-directory)
5385 4. setup artwork (currently configured in setup menu) */
5387 if (setup_override_artwork)
5388 artwork_current_identifier = setup_artwork_set;
5389 else if (leveldir_artwork_set != NULL)
5390 artwork_current_identifier = leveldir_artwork_set;
5391 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5392 artwork_current_identifier = leveldir_identifier;
5394 artwork_current_identifier = setup_artwork_set;
5397 /* 2nd step: check if it is really needed to reload artwork set
5398 ------------------------------------------------------------ */
5400 /* ---------- reload if level set and also artwork set has changed ------- */
5401 if (leveldir_current_identifier[type] != leveldir_identifier &&
5402 (last_has_level_artwork_set[type] || has_level_artwork_set))
5403 artwork_new_identifier = artwork_current_identifier;
5405 leveldir_current_identifier[type] = leveldir_identifier;
5406 last_has_level_artwork_set[type] = has_level_artwork_set;
5408 /* ---------- reload if "override artwork" setting has changed ----------- */
5409 if (last_override_level_artwork[type] != setup_override_artwork)
5410 artwork_new_identifier = artwork_current_identifier;
5412 last_override_level_artwork[type] = setup_override_artwork;
5414 /* ---------- reload if current artwork identifier has changed ----------- */
5415 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5416 artwork_current_identifier))
5417 artwork_new_identifier = artwork_current_identifier;
5419 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5421 /* ---------- do not reload directly after starting ---------------------- */
5422 if (!initialized[type])
5423 artwork_new_identifier = NULL;
5425 initialized[type] = TRUE;
5427 return artwork_new_identifier;
5430 void ReloadCustomArtwork(int force_reload)
5432 int last_game_status = game_status; /* save current game status */
5433 char *gfx_new_identifier;
5434 char *snd_new_identifier;
5435 char *mus_new_identifier;
5436 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5437 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5438 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5439 boolean reload_needed;
5441 InitOverrideArtwork();
5443 force_reload_gfx |= AdjustGraphicsForEMC();
5445 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5446 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5447 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5449 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
5450 snd_new_identifier != NULL || force_reload_snd ||
5451 mus_new_identifier != NULL || force_reload_mus);
5456 print_timestamp_init("ReloadCustomArtwork");
5458 game_status = GAME_MODE_LOADING;
5460 FadeOut(REDRAW_ALL);
5462 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5463 print_timestamp_time("ClearRectangle");
5467 if (gfx_new_identifier != NULL || force_reload_gfx)
5470 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5471 artwork.gfx_current_identifier,
5473 artwork.gfx_current->identifier,
5474 leveldir_current->graphics_set);
5478 print_timestamp_time("InitImages");
5481 if (snd_new_identifier != NULL || force_reload_snd)
5483 InitSound(snd_new_identifier);
5484 print_timestamp_time("InitSound");
5487 if (mus_new_identifier != NULL || force_reload_mus)
5489 InitMusic(mus_new_identifier);
5490 print_timestamp_time("InitMusic");
5493 game_status = last_game_status; /* restore current game status */
5495 init_last = init; /* switch to new busy animation */
5497 FadeOut(REDRAW_ALL);
5501 /* force redraw of (open or closed) door graphics */
5502 SetDoorState(DOOR_OPEN_ALL);
5503 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5505 FadeSetEnterScreen();
5506 FadeSkipNextFadeOut();
5508 print_timestamp_done("ReloadCustomArtwork");
5510 LimitScreenUpdates(FALSE);
5513 void KeyboardAutoRepeatOffUnlessAutoplay()
5515 if (global.autoplay_leveldir == NULL)
5516 KeyboardAutoRepeatOff();
5519 void DisplayExitMessage(char *format, va_list ap)
5521 // check if draw buffer and fonts for exit message are already available
5522 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
5525 int font_1 = FC_RED;
5526 int font_2 = FC_YELLOW;
5527 int font_3 = FC_BLUE;
5528 int font_width = getFontWidth(font_2);
5529 int font_height = getFontHeight(font_2);
5532 int sxsize = WIN_XSIZE - 2 * sx;
5533 int sysize = WIN_YSIZE - 2 * sy;
5534 int line_length = sxsize / font_width;
5535 int max_lines = sysize / font_height;
5536 int num_lines_printed;
5540 gfx.sxsize = sxsize;
5541 gfx.sysize = sysize;
5545 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5547 DrawTextSCentered(sy, font_1, "Fatal error:");
5548 sy += 3 * font_height;;
5551 DrawTextBufferVA(sx, sy, format, ap, font_2,
5552 line_length, line_length, max_lines,
5553 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5554 sy += (num_lines_printed + 3) * font_height;
5556 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
5557 sy += 3 * font_height;
5560 DrawTextBuffer(sx, sy, program.error_filename, font_2,
5561 line_length, line_length, max_lines,
5562 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5564 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
5566 redraw_mask = REDRAW_ALL;
5570 /* deactivate toons on error message screen */
5571 setup.toons = FALSE;
5573 WaitForEventToContinue();
5577 /* ========================================================================= */
5579 /* ========================================================================= */
5583 print_timestamp_init("OpenAll");
5585 game_status = GAME_MODE_LOADING;
5589 InitGlobal(); /* initialize some global variables */
5591 print_timestamp_time("[init global stuff]");
5593 if (options.execute_command)
5594 Execute_Command(options.execute_command);
5596 if (options.serveronly)
5598 #if defined(PLATFORM_UNIX)
5599 NetworkServer(options.server_port, options.serveronly);
5601 Error(ERR_WARN, "networking only supported in Unix version");
5604 exit(0); /* never reached, server loops forever */
5609 print_timestamp_time("[init setup/config stuff (1)]");
5612 print_timestamp_time("[init setup/config stuff (2)]");
5614 print_timestamp_time("[init setup/config stuff (3)]");
5615 InitArtworkInfo(); /* needed before loading gfx, sound & music */
5616 print_timestamp_time("[init setup/config stuff (4)]");
5617 InitArtworkConfig(); /* needed before forking sound child process */
5618 print_timestamp_time("[init setup/config stuff (5)]");
5620 print_timestamp_time("[init setup/config stuff (6)]");
5622 InitRND(NEW_RANDOMIZE);
5623 InitSimpleRandom(NEW_RANDOMIZE);
5627 print_timestamp_time("[init setup/config stuff]");
5630 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
5632 InitEventFilter(FilterEvents);
5634 print_timestamp_time("[init video stuff]");
5636 InitElementPropertiesStatic();
5637 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5638 InitElementPropertiesGfxElement();
5640 print_timestamp_time("[init element properties stuff]");
5644 print_timestamp_time("InitGfx");
5647 print_timestamp_time("InitLevelInfo");
5649 InitLevelArtworkInfo();
5650 print_timestamp_time("InitLevelArtworkInfo");
5652 InitOverrideArtwork(); /* needs to know current level directory */
5653 print_timestamp_time("InitOverrideArtwork");
5655 InitImages(); /* needs to know current level directory */
5656 print_timestamp_time("InitImages");
5658 InitSound(NULL); /* needs to know current level directory */
5659 print_timestamp_time("InitSound");
5661 InitMusic(NULL); /* needs to know current level directory */
5662 print_timestamp_time("InitMusic");
5664 InitGfxBackground();
5669 if (global.autoplay_leveldir)
5674 else if (global.convert_leveldir)
5679 else if (global.create_images_dir)
5681 CreateLevelSketchImages();
5685 game_status = GAME_MODE_MAIN;
5687 FadeSetEnterScreen();
5688 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
5689 FadeSkipNextFadeOut();
5691 print_timestamp_time("[post-artwork]");
5693 print_timestamp_done("OpenAll");
5697 InitNetworkServer();
5700 Error(ERR_DEBUG, "::: SDL_GetBasePath() == '%s'",
5702 Error(ERR_DEBUG, "::: SDL_GetPrefPath() == '%s'",
5703 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
5704 #if defined(PLATFORM_ANDROID)
5705 Error(ERR_DEBUG, "::: SDL_AndroidGetInternalStoragePath() == '%s'",
5706 SDL_AndroidGetInternalStoragePath());
5707 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStoragePath() == '%s'",
5708 SDL_AndroidGetExternalStoragePath());
5709 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStorageState() == '%s'",
5710 (SDL_AndroidGetExternalStorageState() ==
5711 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "read" :
5712 SDL_AndroidGetExternalStorageState() ==
5713 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "write" : "not available"));
5718 void CloseAllAndExit(int exit_value)
5723 CloseAudio(); /* called after freeing sounds (needed for SDL) */
5730 #if defined(TARGET_SDL)
5731 #if defined(TARGET_SDL2)
5733 // set a flag to tell the network server thread to quit and wait for it
5734 // using SDL_WaitThread()
5736 if (network_server) /* terminate network server */
5737 SDL_KillThread(server_thread);
5741 CloseVideoDisplay();
5742 ClosePlatformDependentStuff();
5744 if (exit_value != 0)
5746 /* fall back to default level set (current set may have caused an error) */
5747 SaveLevelSetup_LastSeries_Deactivate();
5749 /* tell user where to find error log file which may contain more details */
5750 // (error notification now directly displayed on screen inside R'n'D
5751 // NotifyUserAboutErrorFile(); /* currently only works for Windows */