1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2006 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
14 #include "libgame/libgame.h"
29 #include "conf_e2g.c" /* include auto-generated data structure definitions */
30 #include "conf_esg.c" /* include auto-generated data structure definitions */
31 #include "conf_e2s.c" /* include auto-generated data structure definitions */
32 #include "conf_fnt.c" /* include auto-generated data structure definitions */
33 #include "conf_g2s.c" /* include auto-generated data structure definitions */
34 #include "conf_g2m.c" /* include auto-generated data structure definitions */
35 #include "conf_act.c" /* include auto-generated data structure definitions */
38 #define CONFIG_TOKEN_FONT_INITIAL "font.initial"
39 #define CONFIG_TOKEN_GLOBAL_BUSY "global.busy"
41 #define DEBUG_PRINT_INIT_TIMESTAMPS TRUE
42 #define DEBUG_PRINT_INIT_TIMESTAMPS_DEPTH 5
45 static struct FontBitmapInfo font_initial[NUM_INITIAL_FONTS];
46 static struct GraphicInfo anim_initial;
48 static int copy_properties[][5] =
52 EL_BUG_LEFT, EL_BUG_RIGHT,
53 EL_BUG_UP, EL_BUG_DOWN
57 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
58 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
62 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
63 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
67 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
68 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
72 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
73 EL_PACMAN_UP, EL_PACMAN_DOWN
77 EL_YAMYAM_LEFT, EL_YAMYAM_RIGHT,
78 EL_YAMYAM_UP, EL_YAMYAM_DOWN
82 EL_MOLE_LEFT, EL_MOLE_RIGHT,
83 EL_MOLE_UP, EL_MOLE_DOWN
92 static void print_init_timestamp(char *message)
95 #if DEBUG_PRINT_INIT_TIMESTAMPS
96 static char *last_message = NULL;
97 static int counter_nr = 0;
98 int max_depth = DEBUG_PRINT_INIT_TIMESTAMPS_DEPTH;
100 if (strEqualPrefix(message, "INIT"))
102 if (counter_nr + 1 < max_depth)
104 debug_print_timestamp(counter_nr, NULL);
105 debug_print_timestamp(counter_nr, message);
110 debug_print_timestamp(counter_nr, NULL);
112 else if (strEqualPrefix(message, "DONE"))
116 if (counter_nr + 1 < max_depth)
118 last_message = &message[4];
120 debug_print_timestamp(counter_nr, message);
123 else if (!strEqualPrefix(message, "TIME") ||
124 !strEqualSuffix(message, last_message))
126 if (counter_nr < max_depth)
127 debug_print_timestamp(counter_nr, message);
135 struct GraphicInfo *graphic_info_last = graphic_info;
137 static unsigned long action_delay = 0;
138 unsigned long action_delay_value = GameFrameDelay;
139 int sync_frame = FrameCounter;
142 if (anim_initial.bitmap == NULL || window == NULL)
145 if (!DelayReached(&action_delay, action_delay_value))
150 static unsigned long last_counter = -1;
151 unsigned long current_counter = Counter();
152 unsigned long delay = current_counter - last_counter;
154 if (last_counter != -1 && delay > action_delay_value + 5)
155 printf("::: DrawInitAnim: DELAY TOO LONG: %ld\n", delay);
157 last_counter = current_counter;
162 anim_initial.anim_mode = ANIM_LOOP;
163 anim_initial.anim_start_frame = 0;
164 anim_initial.offset_x = anim_initial.width;
165 anim_initial.offset_y = 0;
169 x = ALIGNED_TEXT_XPOS(&init.busy);
170 y = ALIGNED_TEXT_YPOS(&init.busy);
172 x = WIN_XSIZE / 2 - TILESIZE / 2;
173 y = WIN_YSIZE / 2 - TILESIZE / 2;
178 static boolean done = FALSE;
181 printf("::: %d, %d, %d, %d => %d, %d\n",
182 init.busy.x, init.busy.y,
183 init.busy.align, init.busy.valign,
190 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
192 if (sync_frame % anim_initial.anim_delay == 0)
193 DrawGraphicAnimationExt(window, x, y, graphic, sync_frame, NO_MASKING);
195 graphic_info = graphic_info_last;
202 FreeLevelEditorGadgets();
211 static boolean gadgets_initialized = FALSE;
213 if (gadgets_initialized)
216 CreateLevelEditorGadgets();
220 CreateScreenGadgets();
222 InitGadgetsSoundCallback(PlaySoundActivating, PlaySoundSelecting);
224 gadgets_initialized = TRUE;
227 inline void InitElementSmallImagesScaledUp(int graphic)
230 struct FileInfo *fi = getImageListEntryFromImageID(graphic);
232 printf("::: '%s' -> '%s'\n", fi->token, fi->filename);
235 CreateImageWithSmallImages(graphic, graphic_info[graphic].scale_up_factor);
238 void InitElementSmallImages()
240 static int special_graphics[] =
242 IMG_EDITOR_ELEMENT_BORDER,
243 IMG_EDITOR_ELEMENT_BORDER_INPUT,
244 IMG_EDITOR_CASCADE_LIST,
245 IMG_EDITOR_CASCADE_LIST_ACTIVE,
248 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
249 int num_property_mappings = getImageListPropertyMappingSize();
252 /* initialize normal images from static configuration */
253 for (i = 0; element_to_graphic[i].element > -1; i++)
254 InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
256 /* initialize special images from static configuration */
257 for (i = 0; element_to_special_graphic[i].element > -1; i++)
258 InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
260 /* initialize images from dynamic configuration (may be elements or other) */
261 for (i = 0; i < num_property_mappings; i++)
262 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
264 /* initialize special images from above list (non-element images) */
265 for (i = 0; special_graphics[i] > -1; i++)
266 InitElementSmallImagesScaledUp(special_graphics[i]);
269 void InitScaledImages()
273 /* scale normal images from static configuration, if not already scaled */
274 for (i = 0; i < NUM_IMAGE_FILES; i++)
275 ScaleImage(i, graphic_info[i].scale_up_factor);
279 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
280 void SetBitmaps_EM(Bitmap **em_bitmap)
282 em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
283 em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].bitmap;
287 static int getFontBitmapID(int font_nr)
291 if (game_status >= GAME_MODE_TITLE_INITIAL &&
292 game_status <= GAME_MODE_PSEUDO_PREVIEW)
293 special = game_status;
294 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
295 special = GFX_SPECIAL_ARG_MAIN;
297 else if (game_status == GAME_MODE_PLAYING)
298 special = GFX_SPECIAL_ARG_DOOR;
302 return font_info[font_nr].special_bitmap_id[special];
307 static int getFontFromToken(char *token)
311 /* !!! OPTIMIZE THIS BY USING HASH !!! */
312 for (i = 0; i < NUM_FONTS; i++)
313 if (strEqual(token, font_info[i].token_name))
316 /* if font not found, use reliable default value */
317 return FONT_INITIAL_1;
320 void InitFontGraphicInfo()
322 static struct FontBitmapInfo *font_bitmap_info = NULL;
323 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
324 int num_property_mappings = getImageListPropertyMappingSize();
325 int num_font_bitmaps = NUM_FONTS;
328 if (graphic_info == NULL) /* still at startup phase */
330 InitFontInfo(font_initial, NUM_INITIAL_FONTS,
331 getFontBitmapID, getFontFromToken);
336 /* ---------- initialize font graphic definitions ---------- */
338 /* always start with reliable default values (normal font graphics) */
339 for (i = 0; i < NUM_FONTS; i++)
340 font_info[i].graphic = IMG_FONT_INITIAL_1;
342 /* initialize normal font/graphic mapping from static configuration */
343 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
345 int font_nr = font_to_graphic[i].font_nr;
346 int special = font_to_graphic[i].special;
347 int graphic = font_to_graphic[i].graphic;
352 font_info[font_nr].graphic = graphic;
355 /* always start with reliable default values (special font graphics) */
356 for (i = 0; i < NUM_FONTS; i++)
358 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
360 font_info[i].special_graphic[j] = font_info[i].graphic;
361 font_info[i].special_bitmap_id[j] = i;
365 /* initialize special font/graphic mapping from static configuration */
366 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
368 int font_nr = font_to_graphic[i].font_nr;
369 int special = font_to_graphic[i].special;
370 int graphic = font_to_graphic[i].graphic;
371 int base_graphic = font2baseimg(font_nr);
373 if (IS_SPECIAL_GFX_ARG(special))
375 boolean base_redefined =
376 getImageListEntryFromImageID(base_graphic)->redefined;
377 boolean special_redefined =
378 getImageListEntryFromImageID(graphic)->redefined;
379 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
381 /* if the base font ("font.title_1", for example) has been redefined,
382 but not the special font ("font.title_1.LEVELS", for example), do not
383 use an existing (in this case considered obsolete) special font
384 anymore, but use the automatically determined default font */
385 /* special case: cloned special fonts must be explicitly redefined,
386 but are not automatically redefined by redefining base font */
387 if (base_redefined && !special_redefined && !special_cloned)
390 font_info[font_nr].special_graphic[special] = graphic;
391 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
396 /* initialize special font/graphic mapping from dynamic configuration */
397 for (i = 0; i < num_property_mappings; i++)
399 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
400 int special = property_mapping[i].ext3_index;
401 int graphic = property_mapping[i].artwork_index;
406 if (IS_SPECIAL_GFX_ARG(special))
408 font_info[font_nr].special_graphic[special] = graphic;
409 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
414 /* correct special font/graphic mapping for cloned fonts for downwards
415 compatibility of PREVIEW fonts -- this is only needed for implicit
416 redefinition of special font by redefined base font, and only if other
417 fonts are cloned from this special font (like in the "Zelda" level set) */
418 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
420 int font_nr = font_to_graphic[i].font_nr;
421 int special = font_to_graphic[i].special;
422 int graphic = font_to_graphic[i].graphic;
424 if (IS_SPECIAL_GFX_ARG(special))
426 boolean special_redefined =
427 getImageListEntryFromImageID(graphic)->redefined;
428 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
430 if (special_cloned && !special_redefined)
434 for (j = 0; font_to_graphic[j].font_nr > -1; j++)
436 int font_nr2 = font_to_graphic[j].font_nr;
437 int special2 = font_to_graphic[j].special;
438 int graphic2 = font_to_graphic[j].graphic;
440 if (IS_SPECIAL_GFX_ARG(special2) &&
441 graphic2 == graphic_info[graphic].clone_from)
443 font_info[font_nr].special_graphic[special] =
444 font_info[font_nr2].special_graphic[special2];
445 font_info[font_nr].special_bitmap_id[special] =
446 font_info[font_nr2].special_bitmap_id[special2];
453 /* reset non-redefined ".active" font graphics if normal font is redefined */
454 /* (this different treatment is needed because normal and active fonts are
455 independently defined ("active" is not a property of font definitions!) */
456 for (i = 0; i < NUM_FONTS; i++)
458 int font_nr_base = i;
459 int font_nr_active = FONT_ACTIVE(font_nr_base);
461 /* check only those fonts with exist as normal and ".active" variant */
462 if (font_nr_base != font_nr_active)
464 int base_graphic = font_info[font_nr_base].graphic;
465 int active_graphic = font_info[font_nr_active].graphic;
466 boolean base_redefined =
467 getImageListEntryFromImageID(base_graphic)->redefined;
468 boolean active_redefined =
469 getImageListEntryFromImageID(active_graphic)->redefined;
471 /* if the base font ("font.menu_1", for example) has been redefined,
472 but not the active font ("font.menu_1.active", for example), do not
473 use an existing (in this case considered obsolete) active font
474 anymore, but use the automatically determined default font */
475 if (base_redefined && !active_redefined)
476 font_info[font_nr_active].graphic = base_graphic;
478 /* now also check each "special" font (which may be the same as above) */
479 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
481 int base_graphic = font_info[font_nr_base].special_graphic[j];
482 int active_graphic = font_info[font_nr_active].special_graphic[j];
483 boolean base_redefined =
484 getImageListEntryFromImageID(base_graphic)->redefined;
485 boolean active_redefined =
486 getImageListEntryFromImageID(active_graphic)->redefined;
488 /* same as above, but check special graphic definitions, for example:
489 redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN" */
490 if (base_redefined && !active_redefined)
492 font_info[font_nr_active].special_graphic[j] =
493 font_info[font_nr_base].special_graphic[j];
494 font_info[font_nr_active].special_bitmap_id[j] =
495 font_info[font_nr_base].special_bitmap_id[j];
501 /* ---------- initialize font bitmap array ---------- */
503 if (font_bitmap_info != NULL)
504 FreeFontInfo(font_bitmap_info);
507 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
509 /* ---------- initialize font bitmap definitions ---------- */
511 for (i = 0; i < NUM_FONTS; i++)
513 if (i < NUM_INITIAL_FONTS)
515 font_bitmap_info[i] = font_initial[i];
519 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
521 int font_bitmap_id = font_info[i].special_bitmap_id[j];
522 int graphic = font_info[i].special_graphic[j];
524 /* set 'graphic_info' for font entries, if uninitialized (guessed) */
525 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
527 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
528 graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
531 /* copy font relevant information from graphics information */
532 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
533 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
534 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
535 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
536 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
538 font_bitmap_info[font_bitmap_id].draw_xoffset =
539 graphic_info[graphic].draw_xoffset;
540 font_bitmap_info[font_bitmap_id].draw_yoffset =
541 graphic_info[graphic].draw_yoffset;
543 font_bitmap_info[font_bitmap_id].num_chars =
544 graphic_info[graphic].anim_frames;
545 font_bitmap_info[font_bitmap_id].num_chars_per_line =
546 graphic_info[graphic].anim_frames_per_line;
550 InitFontInfo(font_bitmap_info, num_font_bitmaps,
551 getFontBitmapID, getFontFromToken);
554 void InitElementGraphicInfo()
556 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
557 int num_property_mappings = getImageListPropertyMappingSize();
560 if (graphic_info == NULL) /* still at startup phase */
563 /* set values to -1 to identify later as "uninitialized" values */
564 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
566 for (act = 0; act < NUM_ACTIONS; act++)
568 element_info[i].graphic[act] = -1;
569 element_info[i].crumbled[act] = -1;
571 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
573 element_info[i].direction_graphic[act][dir] = -1;
574 element_info[i].direction_crumbled[act][dir] = -1;
581 /* initialize normal element/graphic mapping from static configuration */
582 for (i = 0; element_to_graphic[i].element > -1; i++)
584 int element = element_to_graphic[i].element;
585 int action = element_to_graphic[i].action;
586 int direction = element_to_graphic[i].direction;
587 boolean crumbled = element_to_graphic[i].crumbled;
588 int graphic = element_to_graphic[i].graphic;
589 int base_graphic = el2baseimg(element);
591 if (graphic_info[graphic].bitmap == NULL)
594 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
597 boolean base_redefined =
598 getImageListEntryFromImageID(base_graphic)->redefined;
599 boolean act_dir_redefined =
600 getImageListEntryFromImageID(graphic)->redefined;
602 /* if the base graphic ("emerald", for example) has been redefined,
603 but not the action graphic ("emerald.falling", for example), do not
604 use an existing (in this case considered obsolete) action graphic
605 anymore, but use the automatically determined default graphic */
606 if (base_redefined && !act_dir_redefined)
611 action = ACTION_DEFAULT;
616 element_info[element].direction_crumbled[action][direction] = graphic;
618 element_info[element].crumbled[action] = graphic;
623 element_info[element].direction_graphic[action][direction] = graphic;
625 element_info[element].graphic[action] = graphic;
629 /* initialize normal element/graphic mapping from dynamic configuration */
630 for (i = 0; i < num_property_mappings; i++)
632 int element = property_mapping[i].base_index;
633 int action = property_mapping[i].ext1_index;
634 int direction = property_mapping[i].ext2_index;
635 int special = property_mapping[i].ext3_index;
636 int graphic = property_mapping[i].artwork_index;
637 boolean crumbled = FALSE;
640 if ((element == EL_EM_DYNAMITE ||
641 element == EL_EM_DYNAMITE_ACTIVE) &&
642 action == ACTION_ACTIVE &&
643 (special == GFX_SPECIAL_ARG_EDITOR ||
644 special == GFX_SPECIAL_ARG_PANEL))
645 printf("::: DYNAMIC: %d, %d, %d -> %d\n",
646 element, action, special, graphic);
649 if (special == GFX_SPECIAL_ARG_CRUMBLED)
655 if (graphic_info[graphic].bitmap == NULL)
658 if (element >= MAX_NUM_ELEMENTS || special != -1)
662 action = ACTION_DEFAULT;
667 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
668 element_info[element].direction_crumbled[action][dir] = -1;
671 element_info[element].direction_crumbled[action][direction] = graphic;
673 element_info[element].crumbled[action] = graphic;
678 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
679 element_info[element].direction_graphic[action][dir] = -1;
682 element_info[element].direction_graphic[action][direction] = graphic;
684 element_info[element].graphic[action] = graphic;
688 /* now copy all graphics that are defined to be cloned from other graphics */
689 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
691 int graphic = element_info[i].graphic[ACTION_DEFAULT];
692 int crumbled_like, diggable_like;
697 crumbled_like = graphic_info[graphic].crumbled_like;
698 diggable_like = graphic_info[graphic].diggable_like;
700 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
702 for (act = 0; act < NUM_ACTIONS; act++)
703 element_info[i].crumbled[act] =
704 element_info[crumbled_like].crumbled[act];
705 for (act = 0; act < NUM_ACTIONS; act++)
706 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
707 element_info[i].direction_crumbled[act][dir] =
708 element_info[crumbled_like].direction_crumbled[act][dir];
711 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
713 element_info[i].graphic[ACTION_DIGGING] =
714 element_info[diggable_like].graphic[ACTION_DIGGING];
715 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
716 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
717 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
722 /* set hardcoded definitions for some runtime elements without graphic */
723 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
727 /* set hardcoded definitions for some internal elements without graphic */
728 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
730 if (IS_EDITOR_CASCADE_INACTIVE(i))
731 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
732 else if (IS_EDITOR_CASCADE_ACTIVE(i))
733 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
737 /* now set all undefined/invalid graphics to -1 to set to default after it */
738 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
740 for (act = 0; act < NUM_ACTIONS; act++)
744 graphic = element_info[i].graphic[act];
745 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
746 element_info[i].graphic[act] = -1;
748 graphic = element_info[i].crumbled[act];
749 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
750 element_info[i].crumbled[act] = -1;
752 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
754 graphic = element_info[i].direction_graphic[act][dir];
755 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
756 element_info[i].direction_graphic[act][dir] = -1;
758 graphic = element_info[i].direction_crumbled[act][dir];
759 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
760 element_info[i].direction_crumbled[act][dir] = -1;
767 /* adjust graphics with 2nd tile for movement according to direction
768 (do this before correcting '-1' values to minimize calculations) */
769 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
771 for (act = 0; act < NUM_ACTIONS; act++)
773 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
775 int graphic = element_info[i].direction_graphic[act][dir];
776 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
778 if (act == ACTION_FALLING) /* special case */
779 graphic = element_info[i].graphic[act];
782 graphic_info[graphic].double_movement &&
783 graphic_info[graphic].swap_double_tiles != 0)
785 struct GraphicInfo *g = &graphic_info[graphic];
786 int src_x_front = g->src_x;
787 int src_y_front = g->src_y;
788 int src_x_back = g->src_x + g->offset2_x;
789 int src_y_back = g->src_y + g->offset2_y;
790 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
792 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
793 src_y_front < src_y_back);
794 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
795 boolean swap_movement_tiles_autodetected =
796 (!frames_are_ordered_diagonally &&
797 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
798 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
799 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
800 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
803 /* swap frontside and backside graphic tile coordinates, if needed */
804 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
806 /* get current (wrong) backside tile coordinates */
807 getGraphicSourceExt(graphic, 0, &dummy, &src_x_back, &src_y_back,
810 /* set frontside tile coordinates to backside tile coordinates */
811 g->src_x = src_x_back;
812 g->src_y = src_y_back;
814 /* invert tile offset to point to new backside tile coordinates */
818 /* do not swap front and backside tiles again after correction */
819 g->swap_double_tiles = 0;
828 /* now set all '-1' values to element specific default values */
829 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
831 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
832 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
833 int default_direction_graphic[NUM_DIRECTIONS_FULL];
834 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
836 if (default_graphic == -1)
837 default_graphic = IMG_UNKNOWN;
839 if (default_crumbled == -1)
840 default_crumbled = default_graphic;
842 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
843 if (default_crumbled == -1)
844 default_crumbled = IMG_EMPTY;
847 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
849 default_direction_graphic[dir] =
850 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
851 default_direction_crumbled[dir] =
852 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
854 if (default_direction_graphic[dir] == -1)
855 default_direction_graphic[dir] = default_graphic;
857 if (default_direction_crumbled[dir] == -1)
858 default_direction_crumbled[dir] = default_direction_graphic[dir];
860 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
861 if (default_direction_crumbled[dir] == -1)
862 default_direction_crumbled[dir] = default_crumbled;
866 for (act = 0; act < NUM_ACTIONS; act++)
868 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
869 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
870 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
871 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
872 act == ACTION_TURNING_FROM_RIGHT ||
873 act == ACTION_TURNING_FROM_UP ||
874 act == ACTION_TURNING_FROM_DOWN);
876 /* generic default action graphic (defined by "[default]" directive) */
877 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
878 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
879 int default_remove_graphic = IMG_EMPTY;
881 if (act_remove && default_action_graphic != -1)
882 default_remove_graphic = default_action_graphic;
884 /* look for special default action graphic (classic game specific) */
885 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
886 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
887 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
888 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
889 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
890 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
892 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
893 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
894 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
895 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
896 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
897 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
900 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
901 /* !!! make this better !!! */
902 if (i == EL_EMPTY_SPACE)
904 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
905 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
909 if (default_action_graphic == -1)
910 default_action_graphic = default_graphic;
912 if (default_action_crumbled == -1)
913 default_action_crumbled = default_action_graphic;
915 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
916 if (default_action_crumbled == -1)
917 default_action_crumbled = default_crumbled;
920 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
922 /* use action graphic as the default direction graphic, if undefined */
923 int default_action_direction_graphic = element_info[i].graphic[act];
924 int default_action_direction_crumbled = element_info[i].crumbled[act];
926 /* no graphic for current action -- use default direction graphic */
927 if (default_action_direction_graphic == -1)
928 default_action_direction_graphic =
929 (act_remove ? default_remove_graphic :
931 element_info[i].direction_graphic[ACTION_TURNING][dir] :
932 default_action_graphic != default_graphic ?
933 default_action_graphic :
934 default_direction_graphic[dir]);
936 if (element_info[i].direction_graphic[act][dir] == -1)
937 element_info[i].direction_graphic[act][dir] =
938 default_action_direction_graphic;
941 if (default_action_direction_crumbled == -1)
942 default_action_direction_crumbled =
943 element_info[i].direction_graphic[act][dir];
945 if (default_action_direction_crumbled == -1)
946 default_action_direction_crumbled =
947 (act_remove ? default_remove_graphic :
949 element_info[i].direction_crumbled[ACTION_TURNING][dir] :
950 default_action_crumbled != default_crumbled ?
951 default_action_crumbled :
952 default_direction_crumbled[dir]);
955 if (element_info[i].direction_crumbled[act][dir] == -1)
956 element_info[i].direction_crumbled[act][dir] =
957 default_action_direction_crumbled;
960 /* no graphic for this specific action -- use default action graphic */
961 if (element_info[i].graphic[act] == -1)
962 element_info[i].graphic[act] =
963 (act_remove ? default_remove_graphic :
964 act_turning ? element_info[i].graphic[ACTION_TURNING] :
965 default_action_graphic);
967 if (element_info[i].crumbled[act] == -1)
968 element_info[i].crumbled[act] = element_info[i].graphic[act];
970 if (element_info[i].crumbled[act] == -1)
971 element_info[i].crumbled[act] =
972 (act_remove ? default_remove_graphic :
973 act_turning ? element_info[i].crumbled[ACTION_TURNING] :
974 default_action_crumbled);
982 /* !!! THIS ALSO CLEARS SPECIAL FLAGS (AND IS NOT NEEDED ANYWAY) !!! */
983 /* set animation mode to "none" for each graphic with only 1 frame */
984 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
986 for (act = 0; act < NUM_ACTIONS; act++)
988 int graphic = element_info[i].graphic[act];
989 int crumbled = element_info[i].crumbled[act];
991 if (graphic_info[graphic].anim_frames == 1)
992 graphic_info[graphic].anim_mode = ANIM_NONE;
993 if (graphic_info[crumbled].anim_frames == 1)
994 graphic_info[crumbled].anim_mode = ANIM_NONE;
996 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
998 graphic = element_info[i].direction_graphic[act][dir];
999 crumbled = element_info[i].direction_crumbled[act][dir];
1001 if (graphic_info[graphic].anim_frames == 1)
1002 graphic_info[graphic].anim_mode = ANIM_NONE;
1003 if (graphic_info[crumbled].anim_frames == 1)
1004 graphic_info[crumbled].anim_mode = ANIM_NONE;
1012 if (options.verbose)
1014 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1015 if (element_info[i].graphic[ACTION_DEFAULT] == IMG_UNKNOWN &&
1017 Error(ERR_INFO, "warning: no graphic for element '%s' (%d)",
1018 element_info[i].token_name, i);
1024 void InitElementSpecialGraphicInfo()
1026 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
1027 int num_property_mappings = getImageListPropertyMappingSize();
1030 /* always start with reliable default values */
1031 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1032 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1033 element_info[i].special_graphic[j] =
1034 element_info[i].graphic[ACTION_DEFAULT];
1036 /* initialize special element/graphic mapping from static configuration */
1037 for (i = 0; element_to_special_graphic[i].element > -1; i++)
1039 int element = element_to_special_graphic[i].element;
1040 int special = element_to_special_graphic[i].special;
1041 int graphic = element_to_special_graphic[i].graphic;
1042 int base_graphic = el2baseimg(element);
1043 boolean base_redefined =
1044 getImageListEntryFromImageID(base_graphic)->redefined;
1045 boolean special_redefined =
1046 getImageListEntryFromImageID(graphic)->redefined;
1049 if ((element == EL_EM_DYNAMITE ||
1050 element == EL_EM_DYNAMITE_ACTIVE) &&
1051 (special == GFX_SPECIAL_ARG_EDITOR ||
1052 special == GFX_SPECIAL_ARG_PANEL))
1053 printf("::: SPECIAL STATIC: %d, %d -> %d\n",
1054 element, special, graphic);
1057 /* if the base graphic ("emerald", for example) has been redefined,
1058 but not the special graphic ("emerald.EDITOR", for example), do not
1059 use an existing (in this case considered obsolete) special graphic
1060 anymore, but use the automatically created (down-scaled) graphic */
1061 if (base_redefined && !special_redefined)
1064 element_info[element].special_graphic[special] = graphic;
1067 /* initialize special element/graphic mapping from dynamic configuration */
1068 for (i = 0; i < num_property_mappings; i++)
1070 int element = property_mapping[i].base_index;
1071 int action = property_mapping[i].ext1_index;
1072 int direction = property_mapping[i].ext2_index;
1073 int special = property_mapping[i].ext3_index;
1074 int graphic = property_mapping[i].artwork_index;
1077 if ((element == EL_EM_DYNAMITE ||
1078 element == EL_EM_DYNAMITE_ACTIVE ||
1079 element == EL_CONVEYOR_BELT_1_MIDDLE ||
1080 element == EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE) &&
1081 (special == GFX_SPECIAL_ARG_EDITOR ||
1082 special == GFX_SPECIAL_ARG_PANEL))
1083 printf("::: SPECIAL DYNAMIC: %d, %d -> %d [%d]\n",
1084 element, special, graphic, property_mapping[i].ext1_index);
1088 if (element == EL_CONVEYOR_BELT_1_MIDDLE &&
1089 action == ACTION_ACTIVE)
1091 element = EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE;
1097 if (element == EL_MAGIC_WALL &&
1098 action == ACTION_ACTIVE)
1100 element = EL_MAGIC_WALL_ACTIVE;
1106 /* for action ".active", replace element with active element, if exists */
1107 if (action == ACTION_ACTIVE && element != ELEMENT_ACTIVE(element))
1109 element = ELEMENT_ACTIVE(element);
1114 if (element >= MAX_NUM_ELEMENTS)
1117 /* do not change special graphic if action or direction was specified */
1118 if (action != -1 || direction != -1)
1121 if (IS_SPECIAL_GFX_ARG(special))
1122 element_info[element].special_graphic[special] = graphic;
1125 /* now set all undefined/invalid graphics to default */
1126 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1127 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1128 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
1129 element_info[i].special_graphic[j] =
1130 element_info[i].graphic[ACTION_DEFAULT];
1133 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
1138 if (type != TYPE_TOKEN)
1139 return get_parameter_value(value_raw, suffix, type);
1141 if (strEqual(value_raw, ARG_UNDEFINED))
1142 return ARG_UNDEFINED_VALUE;
1144 /* !!! THIS IS BUGGY !!! NOT SURE IF YOU GET ELEMENT ID OR GRAPHIC ID !!! */
1145 /* !!! (possible reason why ".clone_from" with elements doesn't work) !!! */
1147 /* !!! OPTIMIZE THIS BY USING HASH !!! */
1148 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1149 if (strEqual(element_info[i].token_name, value_raw))
1152 /* !!! OPTIMIZE THIS BY USING HASH !!! */
1153 for (i = 0; image_config[i].token != NULL; i++)
1155 int len_config_value = strlen(image_config[i].value);
1157 if (!strEqual(&image_config[i].value[len_config_value - 4], ".pcx") &&
1158 !strEqual(&image_config[i].value[len_config_value - 4], ".wav") &&
1159 !strEqual(image_config[i].value, UNDEFINED_FILENAME))
1162 if (strEqual(image_config[i].token, value_raw))
1171 static int get_scaled_graphic_width(int graphic)
1173 int original_width = getOriginalImageWidthFromImageID(graphic);
1174 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1176 return original_width * scale_up_factor;
1179 static int get_scaled_graphic_height(int graphic)
1181 int original_height = getOriginalImageHeightFromImageID(graphic);
1182 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1184 return original_height * scale_up_factor;
1187 static void set_graphic_parameters_ext(int graphic, struct GraphicInfo *g,
1188 int *parameter, Bitmap *src_bitmap)
1190 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1191 int anim_frames_per_line = 1;
1193 /* always start with reliable default values */
1194 g->src_image_width = 0;
1195 g->src_image_height = 0;
1198 g->width = TILEX; /* default for element graphics */
1199 g->height = TILEY; /* default for element graphics */
1200 g->offset_x = 0; /* one or both of these values ... */
1201 g->offset_y = 0; /* ... will be corrected later */
1202 g->offset2_x = 0; /* one or both of these values ... */
1203 g->offset2_y = 0; /* ... will be corrected later */
1204 g->swap_double_tiles = -1; /* auto-detect tile swapping */
1205 g->crumbled_like = -1; /* do not use clone element */
1206 g->diggable_like = -1; /* do not use clone element */
1207 g->border_size = TILEX / 8; /* "CRUMBLED" border size */
1208 g->scale_up_factor = 1; /* default: no scaling up */
1209 g->clone_from = -1; /* do not use clone graphic */
1210 g->anim_delay_fixed = 0;
1211 g->anim_delay_random = 0;
1212 g->post_delay_fixed = 0;
1213 g->post_delay_random = 0;
1214 g->fade_mode = FADE_MODE_DEFAULT;
1218 g->align = ALIGN_CENTER; /* default for title screens */
1219 g->valign = VALIGN_MIDDLE; /* default for title screens */
1220 g->sort_priority = 0; /* default for title screens */
1222 g->bitmap = src_bitmap;
1225 /* optional zoom factor for scaling up the image to a larger size */
1226 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1227 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1228 if (g->scale_up_factor < 1)
1229 g->scale_up_factor = 1; /* no scaling */
1233 if (g->use_image_size)
1235 /* set new default bitmap size (with scaling, but without small images) */
1236 g->width = get_scaled_graphic_width(graphic);
1237 g->height = get_scaled_graphic_height(graphic);
1241 /* optional x and y tile position of animation frame sequence */
1242 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1243 g->src_x = parameter[GFX_ARG_XPOS] * TILEX;
1244 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1245 g->src_y = parameter[GFX_ARG_YPOS] * TILEY;
1247 /* optional x and y pixel position of animation frame sequence */
1248 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1249 g->src_x = parameter[GFX_ARG_X];
1250 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1251 g->src_y = parameter[GFX_ARG_Y];
1253 /* optional width and height of each animation frame */
1254 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1255 g->width = parameter[GFX_ARG_WIDTH];
1256 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1257 g->height = parameter[GFX_ARG_HEIGHT];
1260 /* optional zoom factor for scaling up the image to a larger size */
1261 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1262 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1263 if (g->scale_up_factor < 1)
1264 g->scale_up_factor = 1; /* no scaling */
1269 /* get final bitmap size (with scaling, but without small images) */
1270 int src_image_width = get_scaled_graphic_width(graphic);
1271 int src_image_height = get_scaled_graphic_height(graphic);
1273 anim_frames_per_row = src_image_width / g->width;
1274 anim_frames_per_col = src_image_height / g->height;
1276 g->src_image_width = src_image_width;
1277 g->src_image_height = src_image_height;
1280 /* correct x or y offset dependent of vertical or horizontal frame order */
1281 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1283 g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1284 parameter[GFX_ARG_OFFSET] : g->height);
1285 anim_frames_per_line = anim_frames_per_col;
1287 else /* frames are ordered horizontally */
1289 g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1290 parameter[GFX_ARG_OFFSET] : g->width);
1291 anim_frames_per_line = anim_frames_per_row;
1294 /* optionally, the x and y offset of frames can be specified directly */
1295 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1296 g->offset_x = parameter[GFX_ARG_XOFFSET];
1297 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1298 g->offset_y = parameter[GFX_ARG_YOFFSET];
1300 /* optionally, moving animations may have separate start and end graphics */
1301 g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1303 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1304 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1306 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1307 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1308 g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1309 parameter[GFX_ARG_2ND_OFFSET] : g->height);
1310 else /* frames are ordered horizontally */
1311 g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1312 parameter[GFX_ARG_2ND_OFFSET] : g->width);
1314 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1315 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1316 g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1317 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1318 g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1320 /* optionally, the second movement tile can be specified as start tile */
1321 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1322 g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1324 /* automatically determine correct number of frames, if not defined */
1325 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1326 g->anim_frames = parameter[GFX_ARG_FRAMES];
1327 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1328 g->anim_frames = anim_frames_per_row;
1329 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1330 g->anim_frames = anim_frames_per_col;
1334 if (g->anim_frames == 0) /* frames must be at least 1 */
1337 g->anim_frames_per_line =
1338 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1339 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1341 g->anim_delay = parameter[GFX_ARG_DELAY];
1342 if (g->anim_delay == 0) /* delay must be at least 1 */
1345 g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1347 if (g->anim_frames == 1)
1348 g->anim_mode = ANIM_NONE;
1351 /* automatically determine correct start frame, if not defined */
1352 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1353 g->anim_start_frame = 0;
1354 else if (g->anim_mode & ANIM_REVERSE)
1355 g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1357 g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1359 /* animation synchronized with global frame counter, not move position */
1360 g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1362 /* optional element for cloning crumble graphics */
1363 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1364 g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1366 /* optional element for cloning digging graphics */
1367 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1368 g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1370 /* optional border size for "crumbling" diggable graphics */
1371 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1372 g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1374 /* this is only used for player "boring" and "sleeping" actions */
1375 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1376 g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1377 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1378 g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1379 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1380 g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1381 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1382 g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1384 /* this is only used for toon animations */
1385 g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1386 g->step_delay = parameter[GFX_ARG_STEP_DELAY];
1388 /* this is only used for drawing font characters */
1389 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1390 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1392 /* this is only used for drawing envelope graphics */
1393 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1395 /* optional graphic for cloning all graphics settings */
1396 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1397 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1399 /* optional settings for drawing title screens and title messages */
1400 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1401 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1402 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1403 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1404 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1405 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1406 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1407 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1408 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1409 g->align = parameter[GFX_ARG_ALIGN];
1410 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1411 g->valign = parameter[GFX_ARG_VALIGN];
1412 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1413 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1416 static void set_graphic_parameters(int graphic)
1419 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1420 char **parameter_raw = image->parameter;
1421 Bitmap *src_bitmap = getBitmapFromImageID(graphic);
1422 int parameter[NUM_GFX_ARGS];
1425 /* if fallback to default artwork is done, also use the default parameters */
1426 if (image->fallback_to_default)
1427 parameter_raw = image->default_parameter;
1429 /* get integer values from string parameters */
1430 for (i = 0; i < NUM_GFX_ARGS; i++)
1431 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1432 image_config_suffix[i].token,
1433 image_config_suffix[i].type);
1435 set_graphic_parameters_ext(graphic, &graphic_info[graphic],
1436 parameter, src_bitmap);
1440 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1441 char **parameter_raw = image->parameter;
1442 Bitmap *src_bitmap = getBitmapFromImageID(graphic);
1443 int parameter[NUM_GFX_ARGS];
1444 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1445 int anim_frames_per_line = 1;
1448 /* if fallback to default artwork is done, also use the default parameters */
1449 if (image->fallback_to_default)
1450 parameter_raw = image->default_parameter;
1452 /* get integer values from string parameters */
1453 for (i = 0; i < NUM_GFX_ARGS; i++)
1454 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1455 image_config_suffix[i].token,
1456 image_config_suffix[i].type);
1458 graphic_info[graphic].bitmap = src_bitmap;
1460 /* always start with reliable default values */
1461 graphic_info[graphic].src_image_width = 0;
1462 graphic_info[graphic].src_image_height = 0;
1463 graphic_info[graphic].src_x = 0;
1464 graphic_info[graphic].src_y = 0;
1465 graphic_info[graphic].width = TILEX; /* default for element graphics */
1466 graphic_info[graphic].height = TILEY; /* default for element graphics */
1467 graphic_info[graphic].offset_x = 0; /* one or both of these values ... */
1468 graphic_info[graphic].offset_y = 0; /* ... will be corrected later */
1469 graphic_info[graphic].offset2_x = 0; /* one or both of these values ... */
1470 graphic_info[graphic].offset2_y = 0; /* ... will be corrected later */
1471 graphic_info[graphic].swap_double_tiles = -1; /* auto-detect tile swapping */
1472 graphic_info[graphic].crumbled_like = -1; /* do not use clone element */
1473 graphic_info[graphic].diggable_like = -1; /* do not use clone element */
1474 graphic_info[graphic].border_size = TILEX / 8; /* "CRUMBLED" border size */
1475 graphic_info[graphic].scale_up_factor = 1; /* default: no scaling up */
1476 graphic_info[graphic].clone_from = -1; /* do not use clone graphic */
1477 graphic_info[graphic].anim_delay_fixed = 0;
1478 graphic_info[graphic].anim_delay_random = 0;
1479 graphic_info[graphic].post_delay_fixed = 0;
1480 graphic_info[graphic].post_delay_random = 0;
1481 graphic_info[graphic].fade_mode = FADE_MODE_DEFAULT;
1482 graphic_info[graphic].fade_delay = -1;
1483 graphic_info[graphic].post_delay = -1;
1484 graphic_info[graphic].auto_delay = -1;
1485 graphic_info[graphic].align = ALIGN_CENTER; /* default for title screens */
1486 graphic_info[graphic].valign = VALIGN_MIDDLE; /* default for title screens */
1487 graphic_info[graphic].sort_priority = 0; /* default for title screens */
1490 /* optional zoom factor for scaling up the image to a larger size */
1491 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1492 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1493 if (graphic_info[graphic].scale_up_factor < 1)
1494 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
1498 if (graphic_info[graphic].use_image_size)
1500 /* set new default bitmap size (with scaling, but without small images) */
1501 graphic_info[graphic].width = get_scaled_graphic_width(graphic);
1502 graphic_info[graphic].height = get_scaled_graphic_height(graphic);
1506 /* optional x and y tile position of animation frame sequence */
1507 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1508 graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
1509 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1510 graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
1512 /* optional x and y pixel position of animation frame sequence */
1513 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1514 graphic_info[graphic].src_x = parameter[GFX_ARG_X];
1515 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1516 graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
1518 /* optional width and height of each animation frame */
1519 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1520 graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
1521 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1522 graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
1525 /* optional zoom factor for scaling up the image to a larger size */
1526 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1527 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1528 if (graphic_info[graphic].scale_up_factor < 1)
1529 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
1534 /* get final bitmap size (with scaling, but without small images) */
1535 int src_image_width = get_scaled_graphic_width(graphic);
1536 int src_image_height = get_scaled_graphic_height(graphic);
1538 anim_frames_per_row = src_image_width / graphic_info[graphic].width;
1539 anim_frames_per_col = src_image_height / graphic_info[graphic].height;
1541 graphic_info[graphic].src_image_width = src_image_width;
1542 graphic_info[graphic].src_image_height = src_image_height;
1545 /* correct x or y offset dependent of vertical or horizontal frame order */
1546 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1548 graphic_info[graphic].offset_y =
1549 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1550 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
1551 anim_frames_per_line = anim_frames_per_col;
1553 else /* frames are ordered horizontally */
1555 graphic_info[graphic].offset_x =
1556 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1557 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
1558 anim_frames_per_line = anim_frames_per_row;
1561 /* optionally, the x and y offset of frames can be specified directly */
1562 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1563 graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
1564 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1565 graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
1567 /* optionally, moving animations may have separate start and end graphics */
1568 graphic_info[graphic].double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1570 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1571 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1573 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1574 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1575 graphic_info[graphic].offset2_y =
1576 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1577 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].height);
1578 else /* frames are ordered horizontally */
1579 graphic_info[graphic].offset2_x =
1580 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1581 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].width);
1583 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1584 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1585 graphic_info[graphic].offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1586 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1587 graphic_info[graphic].offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1589 /* optionally, the second movement tile can be specified as start tile */
1590 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1591 graphic_info[graphic].swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1593 /* automatically determine correct number of frames, if not defined */
1594 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1595 graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
1596 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1597 graphic_info[graphic].anim_frames = anim_frames_per_row;
1598 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1599 graphic_info[graphic].anim_frames = anim_frames_per_col;
1601 graphic_info[graphic].anim_frames = 1;
1603 if (graphic_info[graphic].anim_frames == 0) /* frames must be at least 1 */
1604 graphic_info[graphic].anim_frames = 1;
1606 graphic_info[graphic].anim_frames_per_line =
1607 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1608 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1610 graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
1611 if (graphic_info[graphic].anim_delay == 0) /* delay must be at least 1 */
1612 graphic_info[graphic].anim_delay = 1;
1614 graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
1616 if (graphic_info[graphic].anim_frames == 1)
1617 graphic_info[graphic].anim_mode = ANIM_NONE;
1620 /* automatically determine correct start frame, if not defined */
1621 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1622 graphic_info[graphic].anim_start_frame = 0;
1623 else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
1624 graphic_info[graphic].anim_start_frame =
1625 graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1627 graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
1629 /* animation synchronized with global frame counter, not move position */
1630 graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1632 /* optional element for cloning crumble graphics */
1633 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1634 graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1636 /* optional element for cloning digging graphics */
1637 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1638 graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1640 /* optional border size for "crumbling" diggable graphics */
1641 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1642 graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
1644 /* this is only used for player "boring" and "sleeping" actions */
1645 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1646 graphic_info[graphic].anim_delay_fixed =
1647 parameter[GFX_ARG_ANIM_DELAY_FIXED];
1648 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1649 graphic_info[graphic].anim_delay_random =
1650 parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1651 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1652 graphic_info[graphic].post_delay_fixed =
1653 parameter[GFX_ARG_POST_DELAY_FIXED];
1654 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1655 graphic_info[graphic].post_delay_random =
1656 parameter[GFX_ARG_POST_DELAY_RANDOM];
1658 /* this is only used for toon animations */
1659 graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
1660 graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY];
1662 /* this is only used for drawing font characters */
1663 graphic_info[graphic].draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1664 graphic_info[graphic].draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1666 /* this is only used for drawing envelope graphics */
1667 graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1669 /* optional graphic for cloning all graphics settings */
1670 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1671 graphic_info[graphic].clone_from = parameter[GFX_ARG_CLONE_FROM];
1673 /* optional settings for drawing title screens and title messages */
1674 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1675 graphic_info[graphic].fade_mode = parameter[GFX_ARG_FADE_MODE];
1676 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1677 graphic_info[graphic].fade_delay = parameter[GFX_ARG_FADE_DELAY];
1678 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1679 graphic_info[graphic].post_delay = parameter[GFX_ARG_POST_DELAY];
1680 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1681 graphic_info[graphic].auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1682 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1683 graphic_info[graphic].align = parameter[GFX_ARG_ALIGN];
1684 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1685 graphic_info[graphic].valign = parameter[GFX_ARG_VALIGN];
1686 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1687 graphic_info[graphic].sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1690 UPDATE_BUSY_STATE();
1693 static void set_cloned_graphic_parameters(int graphic)
1695 int fallback_graphic = IMG_CHAR_EXCLAM;
1696 int max_num_images = getImageListSize();
1697 int clone_graphic = graphic_info[graphic].clone_from;
1698 int num_references_followed = 1;
1700 while (graphic_info[clone_graphic].clone_from != -1 &&
1701 num_references_followed < max_num_images)
1703 clone_graphic = graphic_info[clone_graphic].clone_from;
1705 num_references_followed++;
1708 if (num_references_followed >= max_num_images)
1710 Error(ERR_INFO_LINE, "-");
1711 Error(ERR_INFO, "warning: error found in config file:");
1712 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1713 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1714 Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1715 Error(ERR_INFO, "custom graphic rejected for this element/action");
1717 if (graphic == fallback_graphic)
1718 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1720 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1721 Error(ERR_INFO_LINE, "-");
1723 graphic_info[graphic] = graphic_info[fallback_graphic];
1727 graphic_info[graphic] = graphic_info[clone_graphic];
1728 graphic_info[graphic].clone_from = clone_graphic;
1732 static void InitGraphicInfo()
1734 int fallback_graphic = IMG_CHAR_EXCLAM;
1735 int num_images = getImageListSize();
1738 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1739 static boolean clipmasks_initialized = FALSE;
1741 XGCValues clip_gc_values;
1742 unsigned long clip_gc_valuemask;
1743 GC copy_clipmask_gc = None;
1746 /* use image size as default values for width and height for these images */
1747 static int full_size_graphics[] =
1752 IMG_BACKGROUND_ENVELOPE_1,
1753 IMG_BACKGROUND_ENVELOPE_2,
1754 IMG_BACKGROUND_ENVELOPE_3,
1755 IMG_BACKGROUND_ENVELOPE_4,
1758 IMG_BACKGROUND_TITLE_INITIAL,
1759 IMG_BACKGROUND_TITLE,
1760 IMG_BACKGROUND_MAIN,
1761 IMG_BACKGROUND_LEVELS,
1762 IMG_BACKGROUND_SCORES,
1763 IMG_BACKGROUND_EDITOR,
1764 IMG_BACKGROUND_INFO,
1765 IMG_BACKGROUND_INFO_ELEMENTS,
1766 IMG_BACKGROUND_INFO_MUSIC,
1767 IMG_BACKGROUND_INFO_CREDITS,
1768 IMG_BACKGROUND_INFO_PROGRAM,
1769 IMG_BACKGROUND_INFO_LEVELSET,
1770 IMG_BACKGROUND_SETUP,
1771 IMG_BACKGROUND_DOOR,
1773 IMG_TITLESCREEN_INITIAL_1,
1774 IMG_TITLESCREEN_INITIAL_2,
1775 IMG_TITLESCREEN_INITIAL_3,
1776 IMG_TITLESCREEN_INITIAL_4,
1777 IMG_TITLESCREEN_INITIAL_5,
1787 checked_free(graphic_info);
1789 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1792 /* initialize "use_image_size" flag with default value */
1793 for (i = 0; i < num_images; i++)
1794 graphic_info[i].use_image_size = FALSE;
1796 /* initialize "use_image_size" flag from static configuration above */
1797 for (i = 0; full_size_graphics[i] != -1; i++)
1798 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1801 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1802 if (clipmasks_initialized)
1804 for (i = 0; i < num_images; i++)
1806 if (graphic_info[i].clip_mask)
1807 XFreePixmap(display, graphic_info[i].clip_mask);
1808 if (graphic_info[i].clip_gc)
1809 XFreeGC(display, graphic_info[i].clip_gc);
1811 graphic_info[i].clip_mask = None;
1812 graphic_info[i].clip_gc = None;
1817 /* first set all graphic paramaters ... */
1818 for (i = 0; i < num_images; i++)
1819 set_graphic_parameters(i);
1821 /* ... then copy these parameters for cloned graphics */
1822 for (i = 0; i < num_images; i++)
1823 if (graphic_info[i].clone_from != -1)
1824 set_cloned_graphic_parameters(i);
1826 for (i = 0; i < num_images; i++)
1831 int first_frame, last_frame;
1832 int src_bitmap_width, src_bitmap_height;
1834 /* now check if no animation frames are outside of the loaded image */
1836 if (graphic_info[i].bitmap == NULL)
1837 continue; /* skip check for optional images that are undefined */
1839 /* get image size (this can differ from the standard element tile size!) */
1840 width = graphic_info[i].width;
1841 height = graphic_info[i].height;
1843 /* get final bitmap size (with scaling, but without small images) */
1844 src_bitmap_width = graphic_info[i].src_image_width;
1845 src_bitmap_height = graphic_info[i].src_image_height;
1847 /* check if first animation frame is inside specified bitmap */
1850 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1853 /* this avoids calculating wrong start position for out-of-bounds frame */
1854 src_x = graphic_info[i].src_x;
1855 src_y = graphic_info[i].src_y;
1858 if (src_x < 0 || src_y < 0 ||
1859 src_x + width > src_bitmap_width ||
1860 src_y + height > src_bitmap_height)
1862 Error(ERR_INFO_LINE, "-");
1863 Error(ERR_INFO, "warning: error found in config file:");
1864 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1865 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1866 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1868 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1869 src_x, src_y, src_bitmap_width, src_bitmap_height);
1870 Error(ERR_INFO, "custom graphic rejected for this element/action");
1872 if (i == fallback_graphic)
1873 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1875 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1876 Error(ERR_INFO_LINE, "-");
1878 graphic_info[i] = graphic_info[fallback_graphic];
1881 /* check if last animation frame is inside specified bitmap */
1883 last_frame = graphic_info[i].anim_frames - 1;
1884 getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1886 if (src_x < 0 || src_y < 0 ||
1887 src_x + width > src_bitmap_width ||
1888 src_y + height > src_bitmap_height)
1890 Error(ERR_INFO_LINE, "-");
1891 Error(ERR_INFO, "warning: error found in config file:");
1892 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1893 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1894 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1896 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1897 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1898 Error(ERR_INFO, "custom graphic rejected for this element/action");
1900 if (i == fallback_graphic)
1901 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1903 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1904 Error(ERR_INFO_LINE, "-");
1906 graphic_info[i] = graphic_info[fallback_graphic];
1909 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1910 /* currently we only need a tile clip mask from the first frame */
1911 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1913 if (copy_clipmask_gc == None)
1915 clip_gc_values.graphics_exposures = False;
1916 clip_gc_valuemask = GCGraphicsExposures;
1917 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
1918 clip_gc_valuemask, &clip_gc_values);
1921 graphic_info[i].clip_mask =
1922 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
1924 src_pixmap = src_bitmap->clip_mask;
1925 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
1926 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
1928 clip_gc_values.graphics_exposures = False;
1929 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
1930 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
1932 graphic_info[i].clip_gc =
1933 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
1937 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1938 if (copy_clipmask_gc)
1939 XFreeGC(display, copy_clipmask_gc);
1941 clipmasks_initialized = TRUE;
1945 static void InitElementSoundInfo()
1947 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1948 int num_property_mappings = getSoundListPropertyMappingSize();
1951 /* set values to -1 to identify later as "uninitialized" values */
1952 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1953 for (act = 0; act < NUM_ACTIONS; act++)
1954 element_info[i].sound[act] = -1;
1956 /* initialize element/sound mapping from static configuration */
1957 for (i = 0; element_to_sound[i].element > -1; i++)
1959 int element = element_to_sound[i].element;
1960 int action = element_to_sound[i].action;
1961 int sound = element_to_sound[i].sound;
1962 boolean is_class = element_to_sound[i].is_class;
1965 action = ACTION_DEFAULT;
1968 element_info[element].sound[action] = sound;
1970 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1971 if (strEqual(element_info[j].class_name,
1972 element_info[element].class_name))
1973 element_info[j].sound[action] = sound;
1976 /* initialize element class/sound mapping from dynamic configuration */
1977 for (i = 0; i < num_property_mappings; i++)
1979 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1980 int action = property_mapping[i].ext1_index;
1981 int sound = property_mapping[i].artwork_index;
1983 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1987 action = ACTION_DEFAULT;
1989 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1990 if (strEqual(element_info[j].class_name,
1991 element_info[element_class].class_name))
1992 element_info[j].sound[action] = sound;
1995 /* initialize element/sound mapping from dynamic configuration */
1996 for (i = 0; i < num_property_mappings; i++)
1998 int element = property_mapping[i].base_index;
1999 int action = property_mapping[i].ext1_index;
2000 int sound = property_mapping[i].artwork_index;
2002 if (element >= MAX_NUM_ELEMENTS)
2006 action = ACTION_DEFAULT;
2008 element_info[element].sound[action] = sound;
2011 /* now set all '-1' values to element specific default values */
2012 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2014 for (act = 0; act < NUM_ACTIONS; act++)
2016 /* generic default action sound (defined by "[default]" directive) */
2017 int default_action_sound = element_info[EL_DEFAULT].sound[act];
2019 /* look for special default action sound (classic game specific) */
2020 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
2021 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
2022 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
2023 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
2024 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
2025 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
2027 /* !!! there's no such thing as a "default action sound" !!! */
2029 /* look for element specific default sound (independent from action) */
2030 if (element_info[i].sound[ACTION_DEFAULT] != -1)
2031 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
2035 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
2036 /* !!! make this better !!! */
2037 if (i == EL_EMPTY_SPACE)
2038 default_action_sound = element_info[EL_DEFAULT].sound[act];
2041 /* no sound for this specific action -- use default action sound */
2042 if (element_info[i].sound[act] == -1)
2043 element_info[i].sound[act] = default_action_sound;
2047 /* copy sound settings to some elements that are only stored in level file
2048 in native R'n'D levels, but are used by game engine in native EM levels */
2049 for (i = 0; copy_properties[i][0] != -1; i++)
2050 for (j = 1; j <= 4; j++)
2051 for (act = 0; act < NUM_ACTIONS; act++)
2052 element_info[copy_properties[i][j]].sound[act] =
2053 element_info[copy_properties[i][0]].sound[act];
2056 static void InitGameModeSoundInfo()
2060 /* set values to -1 to identify later as "uninitialized" values */
2061 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2064 /* initialize gamemode/sound mapping from static configuration */
2065 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
2067 int gamemode = gamemode_to_sound[i].gamemode;
2068 int sound = gamemode_to_sound[i].sound;
2071 gamemode = GAME_MODE_DEFAULT;
2073 menu.sound[gamemode] = sound;
2076 /* now set all '-1' values to levelset specific default values */
2077 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2078 if (menu.sound[i] == -1)
2079 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
2082 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2083 if (menu.sound[i] != -1)
2084 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
2088 static void set_sound_parameters(int sound, char **parameter_raw)
2090 int parameter[NUM_SND_ARGS];
2093 /* get integer values from string parameters */
2094 for (i = 0; i < NUM_SND_ARGS; i++)
2096 get_parameter_value(parameter_raw[i],
2097 sound_config_suffix[i].token,
2098 sound_config_suffix[i].type);
2100 /* explicit loop mode setting in configuration overrides default value */
2101 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2102 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
2104 /* sound volume to change the original volume when loading the sound file */
2105 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
2107 /* sound priority to give certain sounds a higher or lower priority */
2108 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
2111 static void InitSoundInfo()
2113 int *sound_effect_properties;
2114 int num_sounds = getSoundListSize();
2117 checked_free(sound_info);
2119 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
2120 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
2122 /* initialize sound effect for all elements to "no sound" */
2123 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2124 for (j = 0; j < NUM_ACTIONS; j++)
2125 element_info[i].sound[j] = SND_UNDEFINED;
2127 for (i = 0; i < num_sounds; i++)
2129 struct FileInfo *sound = getSoundListEntry(i);
2130 int len_effect_text = strlen(sound->token);
2132 sound_effect_properties[i] = ACTION_OTHER;
2133 sound_info[i].loop = FALSE; /* default: play sound only once */
2136 printf("::: sound %d: '%s'\n", i, sound->token);
2139 /* determine all loop sounds and identify certain sound classes */
2141 for (j = 0; element_action_info[j].suffix; j++)
2143 int len_action_text = strlen(element_action_info[j].suffix);
2145 if (len_action_text < len_effect_text &&
2146 strEqual(&sound->token[len_effect_text - len_action_text],
2147 element_action_info[j].suffix))
2149 sound_effect_properties[i] = element_action_info[j].value;
2150 sound_info[i].loop = element_action_info[j].is_loop_sound;
2156 /* associate elements and some selected sound actions */
2158 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2160 if (element_info[j].class_name)
2162 int len_class_text = strlen(element_info[j].class_name);
2164 if (len_class_text + 1 < len_effect_text &&
2165 strncmp(sound->token,
2166 element_info[j].class_name, len_class_text) == 0 &&
2167 sound->token[len_class_text] == '.')
2169 int sound_action_value = sound_effect_properties[i];
2171 element_info[j].sound[sound_action_value] = i;
2176 set_sound_parameters(i, sound->parameter);
2179 free(sound_effect_properties);
2182 static void InitGameModeMusicInfo()
2184 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
2185 int num_property_mappings = getMusicListPropertyMappingSize();
2186 int default_levelset_music = -1;
2189 /* set values to -1 to identify later as "uninitialized" values */
2190 for (i = 0; i < MAX_LEVELS; i++)
2191 levelset.music[i] = -1;
2192 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2195 /* initialize gamemode/music mapping from static configuration */
2196 for (i = 0; gamemode_to_music[i].music > -1; i++)
2198 int gamemode = gamemode_to_music[i].gamemode;
2199 int music = gamemode_to_music[i].music;
2202 printf("::: gamemode == %d, music == %d\n", gamemode, music);
2206 gamemode = GAME_MODE_DEFAULT;
2208 menu.music[gamemode] = music;
2211 /* initialize gamemode/music mapping from dynamic configuration */
2212 for (i = 0; i < num_property_mappings; i++)
2214 int prefix = property_mapping[i].base_index;
2215 int gamemode = property_mapping[i].ext1_index;
2216 int level = property_mapping[i].ext2_index;
2217 int music = property_mapping[i].artwork_index;
2220 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
2221 prefix, gamemode, level, music);
2224 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
2228 gamemode = GAME_MODE_DEFAULT;
2230 /* level specific music only allowed for in-game music */
2231 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
2232 gamemode = GAME_MODE_PLAYING;
2237 default_levelset_music = music;
2240 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
2241 levelset.music[level] = music;
2242 if (gamemode != GAME_MODE_PLAYING)
2243 menu.music[gamemode] = music;
2246 /* now set all '-1' values to menu specific default values */
2247 /* (undefined values of "levelset.music[]" might stay at "-1" to
2248 allow dynamic selection of music files from music directory!) */
2249 for (i = 0; i < MAX_LEVELS; i++)
2250 if (levelset.music[i] == -1)
2251 levelset.music[i] = default_levelset_music;
2252 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2253 if (menu.music[i] == -1)
2254 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
2257 for (i = 0; i < MAX_LEVELS; i++)
2258 if (levelset.music[i] != -1)
2259 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
2260 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2261 if (menu.music[i] != -1)
2262 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
2266 static void set_music_parameters(int music, char **parameter_raw)
2268 int parameter[NUM_MUS_ARGS];
2271 /* get integer values from string parameters */
2272 for (i = 0; i < NUM_MUS_ARGS; i++)
2274 get_parameter_value(parameter_raw[i],
2275 music_config_suffix[i].token,
2276 music_config_suffix[i].type);
2278 /* explicit loop mode setting in configuration overrides default value */
2279 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2280 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
2283 static void InitMusicInfo()
2285 int num_music = getMusicListSize();
2288 checked_free(music_info);
2290 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
2292 for (i = 0; i < num_music; i++)
2294 struct FileInfo *music = getMusicListEntry(i);
2295 int len_music_text = strlen(music->token);
2297 music_info[i].loop = TRUE; /* default: play music in loop mode */
2299 /* determine all loop music */
2301 for (j = 0; music_prefix_info[j].prefix; j++)
2303 int len_prefix_text = strlen(music_prefix_info[j].prefix);
2305 if (len_prefix_text < len_music_text &&
2306 strncmp(music->token,
2307 music_prefix_info[j].prefix, len_prefix_text) == 0)
2309 music_info[i].loop = music_prefix_info[j].is_loop_music;
2315 set_music_parameters(i, music->parameter);
2319 static void ReinitializeGraphics()
2321 print_init_timestamp("INIT ReinitializeGraphics");
2323 InitGraphicInfo(); /* graphic properties mapping */
2324 print_init_timestamp("TIME InitGraphicInfo");
2325 InitElementGraphicInfo(); /* element game graphic mapping */
2326 print_init_timestamp("TIME InitElementGraphicInfo");
2327 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
2328 print_init_timestamp("TIME InitElementSpecialGraphicInfo");
2330 InitElementSmallImages(); /* scale elements to all needed sizes */
2331 print_init_timestamp("TIME InitElementSmallImages");
2332 InitScaledImages(); /* scale all other images, if needed */
2333 print_init_timestamp("TIME InitScaledImages");
2334 InitFontGraphicInfo(); /* initialize text drawing functions */
2335 print_init_timestamp("TIME InitFontGraphicInfo");
2337 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
2338 print_init_timestamp("TIME InitGraphicInfo_EM");
2340 SetMainBackgroundImage(IMG_BACKGROUND);
2341 print_init_timestamp("TIME SetMainBackgroundImage");
2342 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2343 print_init_timestamp("TIME SetDoorBackgroundImage");
2346 print_init_timestamp("TIME InitGadgets");
2348 print_init_timestamp("TIME InitToons");
2350 print_init_timestamp("DONE ReinitializeGraphics");
2353 static void ReinitializeSounds()
2355 InitSoundInfo(); /* sound properties mapping */
2356 InitElementSoundInfo(); /* element game sound mapping */
2357 InitGameModeSoundInfo(); /* game mode sound mapping */
2359 InitPlayLevelSound(); /* internal game sound settings */
2362 static void ReinitializeMusic()
2364 InitMusicInfo(); /* music properties mapping */
2365 InitGameModeMusicInfo(); /* game mode music mapping */
2368 static int get_special_property_bit(int element, int property_bit_nr)
2370 struct PropertyBitInfo
2376 static struct PropertyBitInfo pb_can_move_into_acid[] =
2378 /* the player may be able fall into acid when gravity is activated */
2383 { EL_SP_MURPHY, 0 },
2384 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2386 /* all elements that can move may be able to also move into acid */
2389 { EL_BUG_RIGHT, 1 },
2392 { EL_SPACESHIP, 2 },
2393 { EL_SPACESHIP_LEFT, 2 },
2394 { EL_SPACESHIP_RIGHT, 2 },
2395 { EL_SPACESHIP_UP, 2 },
2396 { EL_SPACESHIP_DOWN, 2 },
2397 { EL_BD_BUTTERFLY, 3 },
2398 { EL_BD_BUTTERFLY_LEFT, 3 },
2399 { EL_BD_BUTTERFLY_RIGHT, 3 },
2400 { EL_BD_BUTTERFLY_UP, 3 },
2401 { EL_BD_BUTTERFLY_DOWN, 3 },
2402 { EL_BD_FIREFLY, 4 },
2403 { EL_BD_FIREFLY_LEFT, 4 },
2404 { EL_BD_FIREFLY_RIGHT, 4 },
2405 { EL_BD_FIREFLY_UP, 4 },
2406 { EL_BD_FIREFLY_DOWN, 4 },
2408 { EL_YAMYAM_LEFT, 5 },
2409 { EL_YAMYAM_RIGHT, 5 },
2410 { EL_YAMYAM_UP, 5 },
2411 { EL_YAMYAM_DOWN, 5 },
2412 { EL_DARK_YAMYAM, 6 },
2415 { EL_PACMAN_LEFT, 8 },
2416 { EL_PACMAN_RIGHT, 8 },
2417 { EL_PACMAN_UP, 8 },
2418 { EL_PACMAN_DOWN, 8 },
2420 { EL_MOLE_LEFT, 9 },
2421 { EL_MOLE_RIGHT, 9 },
2423 { EL_MOLE_DOWN, 9 },
2427 { EL_SATELLITE, 13 },
2428 { EL_SP_SNIKSNAK, 14 },
2429 { EL_SP_ELECTRON, 15 },
2432 { EL_EMC_ANDROID, 18 },
2437 static struct PropertyBitInfo pb_dont_collide_with[] =
2439 { EL_SP_SNIKSNAK, 0 },
2440 { EL_SP_ELECTRON, 1 },
2448 struct PropertyBitInfo *pb_info;
2451 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2452 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2457 struct PropertyBitInfo *pb_info = NULL;
2460 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2461 if (pb_definition[i].bit_nr == property_bit_nr)
2462 pb_info = pb_definition[i].pb_info;
2464 if (pb_info == NULL)
2467 for (i = 0; pb_info[i].element != -1; i++)
2468 if (pb_info[i].element == element)
2469 return pb_info[i].bit_nr;
2474 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2475 boolean property_value)
2477 int bit_nr = get_special_property_bit(element, property_bit_nr);
2482 *bitfield |= (1 << bit_nr);
2484 *bitfield &= ~(1 << bit_nr);
2488 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2490 int bit_nr = get_special_property_bit(element, property_bit_nr);
2493 return ((*bitfield & (1 << bit_nr)) != 0);
2498 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2500 static int group_nr;
2501 static struct ElementGroupInfo *group;
2502 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2505 if (actual_group == NULL) /* not yet initialized */
2508 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
2510 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2511 group_element - EL_GROUP_START + 1);
2513 /* replace element which caused too deep recursion by question mark */
2514 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2519 if (recursion_depth == 0) /* initialization */
2521 group = actual_group;
2522 group_nr = GROUP_NR(group_element);
2524 group->num_elements_resolved = 0;
2525 group->choice_pos = 0;
2527 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2528 element_info[i].in_group[group_nr] = FALSE;
2531 for (i = 0; i < actual_group->num_elements; i++)
2533 int element = actual_group->element[i];
2535 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2538 if (IS_GROUP_ELEMENT(element))
2539 ResolveGroupElementExt(element, recursion_depth + 1);
2542 group->element_resolved[group->num_elements_resolved++] = element;
2543 element_info[element].in_group[group_nr] = TRUE;
2548 void ResolveGroupElement(int group_element)
2550 ResolveGroupElementExt(group_element, 0);
2553 void InitElementPropertiesStatic()
2555 static int ep_diggable[] =
2560 EL_SP_BUGGY_BASE_ACTIVATING,
2563 EL_INVISIBLE_SAND_ACTIVE,
2566 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2567 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2572 EL_SP_BUGGY_BASE_ACTIVE,
2579 static int ep_collectible_only[] =
2601 EL_DYNABOMB_INCREASE_NUMBER,
2602 EL_DYNABOMB_INCREASE_SIZE,
2603 EL_DYNABOMB_INCREASE_POWER,
2621 /* !!! handle separately !!! */
2622 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2628 static int ep_dont_run_into[] =
2630 /* same elements as in 'ep_dont_touch' */
2636 /* same elements as in 'ep_dont_collide_with' */
2648 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2653 EL_SP_BUGGY_BASE_ACTIVE,
2660 static int ep_dont_collide_with[] =
2662 /* same elements as in 'ep_dont_touch' */
2679 static int ep_dont_touch[] =
2689 static int ep_indestructible[] =
2693 EL_ACID_POOL_TOPLEFT,
2694 EL_ACID_POOL_TOPRIGHT,
2695 EL_ACID_POOL_BOTTOMLEFT,
2696 EL_ACID_POOL_BOTTOM,
2697 EL_ACID_POOL_BOTTOMRIGHT,
2698 EL_SP_HARDWARE_GRAY,
2699 EL_SP_HARDWARE_GREEN,
2700 EL_SP_HARDWARE_BLUE,
2702 EL_SP_HARDWARE_YELLOW,
2703 EL_SP_HARDWARE_BASE_1,
2704 EL_SP_HARDWARE_BASE_2,
2705 EL_SP_HARDWARE_BASE_3,
2706 EL_SP_HARDWARE_BASE_4,
2707 EL_SP_HARDWARE_BASE_5,
2708 EL_SP_HARDWARE_BASE_6,
2709 EL_INVISIBLE_STEELWALL,
2710 EL_INVISIBLE_STEELWALL_ACTIVE,
2711 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2712 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2713 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2714 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2715 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2716 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2717 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2718 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2719 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2720 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2721 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2722 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2724 EL_LIGHT_SWITCH_ACTIVE,
2725 EL_SIGN_EXCLAMATION,
2726 EL_SIGN_RADIOACTIVITY,
2733 EL_SIGN_ENTRY_FORBIDDEN,
2734 EL_SIGN_EMERGENCY_EXIT,
2742 EL_STEEL_EXIT_CLOSED,
2744 EL_EM_STEEL_EXIT_CLOSED,
2745 EL_EM_STEEL_EXIT_OPEN,
2746 EL_DC_STEELWALL_1_LEFT,
2747 EL_DC_STEELWALL_1_RIGHT,
2748 EL_DC_STEELWALL_1_TOP,
2749 EL_DC_STEELWALL_1_BOTTOM,
2750 EL_DC_STEELWALL_1_HORIZONTAL,
2751 EL_DC_STEELWALL_1_VERTICAL,
2752 EL_DC_STEELWALL_1_TOPLEFT,
2753 EL_DC_STEELWALL_1_TOPRIGHT,
2754 EL_DC_STEELWALL_1_BOTTOMLEFT,
2755 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2756 EL_DC_STEELWALL_1_TOPLEFT_2,
2757 EL_DC_STEELWALL_1_TOPRIGHT_2,
2758 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2759 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2760 EL_DC_STEELWALL_2_LEFT,
2761 EL_DC_STEELWALL_2_RIGHT,
2762 EL_DC_STEELWALL_2_TOP,
2763 EL_DC_STEELWALL_2_BOTTOM,
2764 EL_DC_STEELWALL_2_HORIZONTAL,
2765 EL_DC_STEELWALL_2_VERTICAL,
2766 EL_DC_STEELWALL_2_MIDDLE,
2767 EL_DC_STEELWALL_2_SINGLE,
2768 EL_STEELWALL_SLIPPERY,
2782 EL_GATE_1_GRAY_ACTIVE,
2783 EL_GATE_2_GRAY_ACTIVE,
2784 EL_GATE_3_GRAY_ACTIVE,
2785 EL_GATE_4_GRAY_ACTIVE,
2794 EL_EM_GATE_1_GRAY_ACTIVE,
2795 EL_EM_GATE_2_GRAY_ACTIVE,
2796 EL_EM_GATE_3_GRAY_ACTIVE,
2797 EL_EM_GATE_4_GRAY_ACTIVE,
2806 EL_EMC_GATE_5_GRAY_ACTIVE,
2807 EL_EMC_GATE_6_GRAY_ACTIVE,
2808 EL_EMC_GATE_7_GRAY_ACTIVE,
2809 EL_EMC_GATE_8_GRAY_ACTIVE,
2811 EL_DC_GATE_WHITE_GRAY,
2812 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2813 EL_DC_GATE_FAKE_GRAY,
2815 EL_SWITCHGATE_OPENING,
2816 EL_SWITCHGATE_CLOSED,
2817 EL_SWITCHGATE_CLOSING,
2819 EL_DC_SWITCHGATE_SWITCH_UP,
2820 EL_DC_SWITCHGATE_SWITCH_DOWN,
2823 EL_TIMEGATE_OPENING,
2825 EL_TIMEGATE_CLOSING,
2827 EL_DC_TIMEGATE_SWITCH,
2828 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2833 EL_TUBE_VERTICAL_LEFT,
2834 EL_TUBE_VERTICAL_RIGHT,
2835 EL_TUBE_HORIZONTAL_UP,
2836 EL_TUBE_HORIZONTAL_DOWN,
2841 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2842 EL_EXPANDABLE_STEELWALL_VERTICAL,
2843 EL_EXPANDABLE_STEELWALL_ANY,
2848 static int ep_slippery[] =
2862 EL_ROBOT_WHEEL_ACTIVE,
2868 EL_ACID_POOL_TOPLEFT,
2869 EL_ACID_POOL_TOPRIGHT,
2879 EL_STEELWALL_SLIPPERY,
2882 EL_EMC_WALL_SLIPPERY_1,
2883 EL_EMC_WALL_SLIPPERY_2,
2884 EL_EMC_WALL_SLIPPERY_3,
2885 EL_EMC_WALL_SLIPPERY_4,
2887 EL_EMC_MAGIC_BALL_ACTIVE,
2892 static int ep_can_change[] =
2897 static int ep_can_move[] =
2899 /* same elements as in 'pb_can_move_into_acid' */
2922 static int ep_can_fall[] =
2936 EL_QUICKSAND_FAST_FULL,
2938 EL_BD_MAGIC_WALL_FULL,
2939 EL_DC_MAGIC_WALL_FULL,
2953 static int ep_can_smash_player[] =
2979 static int ep_can_smash_enemies[] =
2988 static int ep_can_smash_everything[] =
2997 static int ep_explodes_by_fire[] =
2999 /* same elements as in 'ep_explodes_impact' */
3004 /* same elements as in 'ep_explodes_smashed' */
3014 EL_EM_DYNAMITE_ACTIVE,
3015 EL_DYNABOMB_PLAYER_1_ACTIVE,
3016 EL_DYNABOMB_PLAYER_2_ACTIVE,
3017 EL_DYNABOMB_PLAYER_3_ACTIVE,
3018 EL_DYNABOMB_PLAYER_4_ACTIVE,
3019 EL_DYNABOMB_INCREASE_NUMBER,
3020 EL_DYNABOMB_INCREASE_SIZE,
3021 EL_DYNABOMB_INCREASE_POWER,
3022 EL_SP_DISK_RED_ACTIVE,
3036 static int ep_explodes_smashed[] =
3038 /* same elements as in 'ep_explodes_impact' */
3052 static int ep_explodes_impact[] =
3061 static int ep_walkable_over[] =
3065 EL_SOKOBAN_FIELD_EMPTY,
3071 EL_EM_STEEL_EXIT_OPEN,
3080 EL_GATE_1_GRAY_ACTIVE,
3081 EL_GATE_2_GRAY_ACTIVE,
3082 EL_GATE_3_GRAY_ACTIVE,
3083 EL_GATE_4_GRAY_ACTIVE,
3091 static int ep_walkable_inside[] =
3096 EL_TUBE_VERTICAL_LEFT,
3097 EL_TUBE_VERTICAL_RIGHT,
3098 EL_TUBE_HORIZONTAL_UP,
3099 EL_TUBE_HORIZONTAL_DOWN,
3108 static int ep_walkable_under[] =
3113 static int ep_passable_over[] =
3123 EL_EM_GATE_1_GRAY_ACTIVE,
3124 EL_EM_GATE_2_GRAY_ACTIVE,
3125 EL_EM_GATE_3_GRAY_ACTIVE,
3126 EL_EM_GATE_4_GRAY_ACTIVE,
3135 EL_EMC_GATE_5_GRAY_ACTIVE,
3136 EL_EMC_GATE_6_GRAY_ACTIVE,
3137 EL_EMC_GATE_7_GRAY_ACTIVE,
3138 EL_EMC_GATE_8_GRAY_ACTIVE,
3140 EL_DC_GATE_WHITE_GRAY,
3141 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3148 static int ep_passable_inside[] =
3154 EL_SP_PORT_HORIZONTAL,
3155 EL_SP_PORT_VERTICAL,
3157 EL_SP_GRAVITY_PORT_LEFT,
3158 EL_SP_GRAVITY_PORT_RIGHT,
3159 EL_SP_GRAVITY_PORT_UP,
3160 EL_SP_GRAVITY_PORT_DOWN,
3161 EL_SP_GRAVITY_ON_PORT_LEFT,
3162 EL_SP_GRAVITY_ON_PORT_RIGHT,
3163 EL_SP_GRAVITY_ON_PORT_UP,
3164 EL_SP_GRAVITY_ON_PORT_DOWN,
3165 EL_SP_GRAVITY_OFF_PORT_LEFT,
3166 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3167 EL_SP_GRAVITY_OFF_PORT_UP,
3168 EL_SP_GRAVITY_OFF_PORT_DOWN,
3173 static int ep_passable_under[] =
3178 static int ep_droppable[] =
3183 static int ep_explodes_1x1_old[] =
3188 static int ep_pushable[] =
3200 EL_SOKOBAN_FIELD_FULL,
3209 static int ep_explodes_cross_old[] =
3214 static int ep_protected[] =
3216 /* same elements as in 'ep_walkable_inside' */
3220 EL_TUBE_VERTICAL_LEFT,
3221 EL_TUBE_VERTICAL_RIGHT,
3222 EL_TUBE_HORIZONTAL_UP,
3223 EL_TUBE_HORIZONTAL_DOWN,
3229 /* same elements as in 'ep_passable_over' */
3238 EL_EM_GATE_1_GRAY_ACTIVE,
3239 EL_EM_GATE_2_GRAY_ACTIVE,
3240 EL_EM_GATE_3_GRAY_ACTIVE,
3241 EL_EM_GATE_4_GRAY_ACTIVE,
3250 EL_EMC_GATE_5_GRAY_ACTIVE,
3251 EL_EMC_GATE_6_GRAY_ACTIVE,
3252 EL_EMC_GATE_7_GRAY_ACTIVE,
3253 EL_EMC_GATE_8_GRAY_ACTIVE,
3255 EL_DC_GATE_WHITE_GRAY,
3256 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3260 /* same elements as in 'ep_passable_inside' */
3265 EL_SP_PORT_HORIZONTAL,
3266 EL_SP_PORT_VERTICAL,
3268 EL_SP_GRAVITY_PORT_LEFT,
3269 EL_SP_GRAVITY_PORT_RIGHT,
3270 EL_SP_GRAVITY_PORT_UP,
3271 EL_SP_GRAVITY_PORT_DOWN,
3272 EL_SP_GRAVITY_ON_PORT_LEFT,
3273 EL_SP_GRAVITY_ON_PORT_RIGHT,
3274 EL_SP_GRAVITY_ON_PORT_UP,
3275 EL_SP_GRAVITY_ON_PORT_DOWN,
3276 EL_SP_GRAVITY_OFF_PORT_LEFT,
3277 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3278 EL_SP_GRAVITY_OFF_PORT_UP,
3279 EL_SP_GRAVITY_OFF_PORT_DOWN,
3284 static int ep_throwable[] =
3289 static int ep_can_explode[] =
3291 /* same elements as in 'ep_explodes_impact' */
3296 /* same elements as in 'ep_explodes_smashed' */
3302 /* elements that can explode by explosion or by dragonfire */
3306 EL_EM_DYNAMITE_ACTIVE,
3307 EL_DYNABOMB_PLAYER_1_ACTIVE,
3308 EL_DYNABOMB_PLAYER_2_ACTIVE,
3309 EL_DYNABOMB_PLAYER_3_ACTIVE,
3310 EL_DYNABOMB_PLAYER_4_ACTIVE,
3311 EL_DYNABOMB_INCREASE_NUMBER,
3312 EL_DYNABOMB_INCREASE_SIZE,
3313 EL_DYNABOMB_INCREASE_POWER,
3314 EL_SP_DISK_RED_ACTIVE,
3322 /* elements that can explode only by explosion */
3328 static int ep_gravity_reachable[] =
3334 EL_INVISIBLE_SAND_ACTIVE,
3339 EL_SP_PORT_HORIZONTAL,
3340 EL_SP_PORT_VERTICAL,
3342 EL_SP_GRAVITY_PORT_LEFT,
3343 EL_SP_GRAVITY_PORT_RIGHT,
3344 EL_SP_GRAVITY_PORT_UP,
3345 EL_SP_GRAVITY_PORT_DOWN,
3346 EL_SP_GRAVITY_ON_PORT_LEFT,
3347 EL_SP_GRAVITY_ON_PORT_RIGHT,
3348 EL_SP_GRAVITY_ON_PORT_UP,
3349 EL_SP_GRAVITY_ON_PORT_DOWN,
3350 EL_SP_GRAVITY_OFF_PORT_LEFT,
3351 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3352 EL_SP_GRAVITY_OFF_PORT_UP,
3353 EL_SP_GRAVITY_OFF_PORT_DOWN,
3359 static int ep_player[] =
3366 EL_SOKOBAN_FIELD_PLAYER,
3372 static int ep_can_pass_magic_wall[] =
3386 static int ep_can_pass_dc_magic_wall[] =
3402 static int ep_switchable[] =
3406 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3407 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3408 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3409 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3410 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3411 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3412 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3413 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3414 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3415 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3416 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3417 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3418 EL_SWITCHGATE_SWITCH_UP,
3419 EL_SWITCHGATE_SWITCH_DOWN,
3420 EL_DC_SWITCHGATE_SWITCH_UP,
3421 EL_DC_SWITCHGATE_SWITCH_DOWN,
3423 EL_LIGHT_SWITCH_ACTIVE,
3425 EL_DC_TIMEGATE_SWITCH,
3426 EL_BALLOON_SWITCH_LEFT,
3427 EL_BALLOON_SWITCH_RIGHT,
3428 EL_BALLOON_SWITCH_UP,
3429 EL_BALLOON_SWITCH_DOWN,
3430 EL_BALLOON_SWITCH_ANY,
3431 EL_BALLOON_SWITCH_NONE,
3434 EL_EMC_MAGIC_BALL_SWITCH,
3435 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3440 static int ep_bd_element[] =
3474 static int ep_sp_element[] =
3476 /* should always be valid */
3479 /* standard classic Supaplex elements */
3486 EL_SP_HARDWARE_GRAY,
3494 EL_SP_GRAVITY_PORT_RIGHT,
3495 EL_SP_GRAVITY_PORT_DOWN,
3496 EL_SP_GRAVITY_PORT_LEFT,
3497 EL_SP_GRAVITY_PORT_UP,
3502 EL_SP_PORT_VERTICAL,
3503 EL_SP_PORT_HORIZONTAL,
3509 EL_SP_HARDWARE_BASE_1,
3510 EL_SP_HARDWARE_GREEN,
3511 EL_SP_HARDWARE_BLUE,
3513 EL_SP_HARDWARE_YELLOW,
3514 EL_SP_HARDWARE_BASE_2,
3515 EL_SP_HARDWARE_BASE_3,
3516 EL_SP_HARDWARE_BASE_4,
3517 EL_SP_HARDWARE_BASE_5,
3518 EL_SP_HARDWARE_BASE_6,
3522 /* additional elements that appeared in newer Supaplex levels */
3525 /* additional gravity port elements (not switching, but setting gravity) */
3526 EL_SP_GRAVITY_ON_PORT_LEFT,
3527 EL_SP_GRAVITY_ON_PORT_RIGHT,
3528 EL_SP_GRAVITY_ON_PORT_UP,
3529 EL_SP_GRAVITY_ON_PORT_DOWN,
3530 EL_SP_GRAVITY_OFF_PORT_LEFT,
3531 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3532 EL_SP_GRAVITY_OFF_PORT_UP,
3533 EL_SP_GRAVITY_OFF_PORT_DOWN,
3535 /* more than one Murphy in a level results in an inactive clone */
3538 /* runtime Supaplex elements */
3539 EL_SP_DISK_RED_ACTIVE,
3540 EL_SP_TERMINAL_ACTIVE,
3541 EL_SP_BUGGY_BASE_ACTIVATING,
3542 EL_SP_BUGGY_BASE_ACTIVE,
3549 static int ep_sb_element[] =
3554 EL_SOKOBAN_FIELD_EMPTY,
3555 EL_SOKOBAN_FIELD_FULL,
3556 EL_SOKOBAN_FIELD_PLAYER,
3561 EL_INVISIBLE_STEELWALL,
3566 static int ep_gem[] =
3578 static int ep_food_dark_yamyam[] =
3606 static int ep_food_penguin[] =
3620 static int ep_food_pig[] =
3632 static int ep_historic_wall[] =
3643 EL_GATE_1_GRAY_ACTIVE,
3644 EL_GATE_2_GRAY_ACTIVE,
3645 EL_GATE_3_GRAY_ACTIVE,
3646 EL_GATE_4_GRAY_ACTIVE,
3655 EL_EM_GATE_1_GRAY_ACTIVE,
3656 EL_EM_GATE_2_GRAY_ACTIVE,
3657 EL_EM_GATE_3_GRAY_ACTIVE,
3658 EL_EM_GATE_4_GRAY_ACTIVE,
3665 EL_EXPANDABLE_WALL_HORIZONTAL,
3666 EL_EXPANDABLE_WALL_VERTICAL,
3667 EL_EXPANDABLE_WALL_ANY,
3668 EL_EXPANDABLE_WALL_GROWING,
3669 EL_BD_EXPANDABLE_WALL,
3676 EL_SP_HARDWARE_GRAY,
3677 EL_SP_HARDWARE_GREEN,
3678 EL_SP_HARDWARE_BLUE,
3680 EL_SP_HARDWARE_YELLOW,
3681 EL_SP_HARDWARE_BASE_1,
3682 EL_SP_HARDWARE_BASE_2,
3683 EL_SP_HARDWARE_BASE_3,
3684 EL_SP_HARDWARE_BASE_4,
3685 EL_SP_HARDWARE_BASE_5,
3686 EL_SP_HARDWARE_BASE_6,
3688 EL_SP_TERMINAL_ACTIVE,
3691 EL_INVISIBLE_STEELWALL,
3692 EL_INVISIBLE_STEELWALL_ACTIVE,
3694 EL_INVISIBLE_WALL_ACTIVE,
3695 EL_STEELWALL_SLIPPERY,
3712 static int ep_historic_solid[] =
3716 EL_EXPANDABLE_WALL_HORIZONTAL,
3717 EL_EXPANDABLE_WALL_VERTICAL,
3718 EL_EXPANDABLE_WALL_ANY,
3719 EL_BD_EXPANDABLE_WALL,
3732 EL_QUICKSAND_FILLING,
3733 EL_QUICKSAND_EMPTYING,
3735 EL_MAGIC_WALL_ACTIVE,
3736 EL_MAGIC_WALL_EMPTYING,
3737 EL_MAGIC_WALL_FILLING,
3741 EL_BD_MAGIC_WALL_ACTIVE,
3742 EL_BD_MAGIC_WALL_EMPTYING,
3743 EL_BD_MAGIC_WALL_FULL,
3744 EL_BD_MAGIC_WALL_FILLING,
3745 EL_BD_MAGIC_WALL_DEAD,
3754 EL_SP_TERMINAL_ACTIVE,
3758 EL_INVISIBLE_WALL_ACTIVE,
3759 EL_SWITCHGATE_SWITCH_UP,
3760 EL_SWITCHGATE_SWITCH_DOWN,
3761 EL_DC_SWITCHGATE_SWITCH_UP,
3762 EL_DC_SWITCHGATE_SWITCH_DOWN,
3764 EL_TIMEGATE_SWITCH_ACTIVE,
3765 EL_DC_TIMEGATE_SWITCH,
3766 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3778 /* the following elements are a direct copy of "indestructible" elements,
3779 except "EL_ACID", which is "indestructible", but not "solid"! */
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,
3789 EL_SP_HARDWARE_GRAY,
3790 EL_SP_HARDWARE_GREEN,
3791 EL_SP_HARDWARE_BLUE,
3793 EL_SP_HARDWARE_YELLOW,
3794 EL_SP_HARDWARE_BASE_1,
3795 EL_SP_HARDWARE_BASE_2,
3796 EL_SP_HARDWARE_BASE_3,
3797 EL_SP_HARDWARE_BASE_4,
3798 EL_SP_HARDWARE_BASE_5,
3799 EL_SP_HARDWARE_BASE_6,
3800 EL_INVISIBLE_STEELWALL,
3801 EL_INVISIBLE_STEELWALL_ACTIVE,
3802 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3803 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3804 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3805 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3806 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3807 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3808 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3809 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3810 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3811 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3812 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3813 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3815 EL_LIGHT_SWITCH_ACTIVE,
3816 EL_SIGN_EXCLAMATION,
3817 EL_SIGN_RADIOACTIVITY,
3824 EL_SIGN_ENTRY_FORBIDDEN,
3825 EL_SIGN_EMERGENCY_EXIT,
3833 EL_STEEL_EXIT_CLOSED,
3835 EL_DC_STEELWALL_1_LEFT,
3836 EL_DC_STEELWALL_1_RIGHT,
3837 EL_DC_STEELWALL_1_TOP,
3838 EL_DC_STEELWALL_1_BOTTOM,
3839 EL_DC_STEELWALL_1_HORIZONTAL,
3840 EL_DC_STEELWALL_1_VERTICAL,
3841 EL_DC_STEELWALL_1_TOPLEFT,
3842 EL_DC_STEELWALL_1_TOPRIGHT,
3843 EL_DC_STEELWALL_1_BOTTOMLEFT,
3844 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3845 EL_DC_STEELWALL_1_TOPLEFT_2,
3846 EL_DC_STEELWALL_1_TOPRIGHT_2,
3847 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3848 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3849 EL_DC_STEELWALL_2_LEFT,
3850 EL_DC_STEELWALL_2_RIGHT,
3851 EL_DC_STEELWALL_2_TOP,
3852 EL_DC_STEELWALL_2_BOTTOM,
3853 EL_DC_STEELWALL_2_HORIZONTAL,
3854 EL_DC_STEELWALL_2_VERTICAL,
3855 EL_DC_STEELWALL_2_MIDDLE,
3856 EL_DC_STEELWALL_2_SINGLE,
3857 EL_STEELWALL_SLIPPERY,
3871 EL_GATE_1_GRAY_ACTIVE,
3872 EL_GATE_2_GRAY_ACTIVE,
3873 EL_GATE_3_GRAY_ACTIVE,
3874 EL_GATE_4_GRAY_ACTIVE,
3883 EL_EM_GATE_1_GRAY_ACTIVE,
3884 EL_EM_GATE_2_GRAY_ACTIVE,
3885 EL_EM_GATE_3_GRAY_ACTIVE,
3886 EL_EM_GATE_4_GRAY_ACTIVE,
3888 EL_SWITCHGATE_OPENING,
3889 EL_SWITCHGATE_CLOSED,
3890 EL_SWITCHGATE_CLOSING,
3892 EL_TIMEGATE_OPENING,
3894 EL_TIMEGATE_CLOSING,
3898 EL_TUBE_VERTICAL_LEFT,
3899 EL_TUBE_VERTICAL_RIGHT,
3900 EL_TUBE_HORIZONTAL_UP,
3901 EL_TUBE_HORIZONTAL_DOWN,
3910 static int ep_classic_enemy[] =
3927 static int ep_belt[] =
3929 EL_CONVEYOR_BELT_1_LEFT,
3930 EL_CONVEYOR_BELT_1_MIDDLE,
3931 EL_CONVEYOR_BELT_1_RIGHT,
3932 EL_CONVEYOR_BELT_2_LEFT,
3933 EL_CONVEYOR_BELT_2_MIDDLE,
3934 EL_CONVEYOR_BELT_2_RIGHT,
3935 EL_CONVEYOR_BELT_3_LEFT,
3936 EL_CONVEYOR_BELT_3_MIDDLE,
3937 EL_CONVEYOR_BELT_3_RIGHT,
3938 EL_CONVEYOR_BELT_4_LEFT,
3939 EL_CONVEYOR_BELT_4_MIDDLE,
3940 EL_CONVEYOR_BELT_4_RIGHT,
3945 static int ep_belt_active[] =
3947 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3948 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3949 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3950 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3951 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3952 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3953 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3954 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3955 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3956 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3957 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3958 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3963 static int ep_belt_switch[] =
3965 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3966 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3967 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3968 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3969 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3970 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3971 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3972 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3973 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3974 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3975 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3976 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3981 static int ep_tube[] =
3988 EL_TUBE_HORIZONTAL_UP,
3989 EL_TUBE_HORIZONTAL_DOWN,
3991 EL_TUBE_VERTICAL_LEFT,
3992 EL_TUBE_VERTICAL_RIGHT,
3998 static int ep_acid_pool[] =
4000 EL_ACID_POOL_TOPLEFT,
4001 EL_ACID_POOL_TOPRIGHT,
4002 EL_ACID_POOL_BOTTOMLEFT,
4003 EL_ACID_POOL_BOTTOM,
4004 EL_ACID_POOL_BOTTOMRIGHT,
4009 static int ep_keygate[] =
4019 EL_GATE_1_GRAY_ACTIVE,
4020 EL_GATE_2_GRAY_ACTIVE,
4021 EL_GATE_3_GRAY_ACTIVE,
4022 EL_GATE_4_GRAY_ACTIVE,
4031 EL_EM_GATE_1_GRAY_ACTIVE,
4032 EL_EM_GATE_2_GRAY_ACTIVE,
4033 EL_EM_GATE_3_GRAY_ACTIVE,
4034 EL_EM_GATE_4_GRAY_ACTIVE,
4043 EL_EMC_GATE_5_GRAY_ACTIVE,
4044 EL_EMC_GATE_6_GRAY_ACTIVE,
4045 EL_EMC_GATE_7_GRAY_ACTIVE,
4046 EL_EMC_GATE_8_GRAY_ACTIVE,
4048 EL_DC_GATE_WHITE_GRAY,
4049 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4054 static int ep_amoeboid[] =
4066 static int ep_amoebalive[] =
4077 static int ep_has_editor_content[] =
4099 static int ep_can_turn_each_move[] =
4101 /* !!! do something with this one !!! */
4105 static int ep_can_grow[] =
4119 static int ep_active_bomb[] =
4122 EL_EM_DYNAMITE_ACTIVE,
4123 EL_DYNABOMB_PLAYER_1_ACTIVE,
4124 EL_DYNABOMB_PLAYER_2_ACTIVE,
4125 EL_DYNABOMB_PLAYER_3_ACTIVE,
4126 EL_DYNABOMB_PLAYER_4_ACTIVE,
4127 EL_SP_DISK_RED_ACTIVE,
4132 static int ep_inactive[] =
4142 EL_QUICKSAND_FAST_EMPTY,
4165 EL_GATE_1_GRAY_ACTIVE,
4166 EL_GATE_2_GRAY_ACTIVE,
4167 EL_GATE_3_GRAY_ACTIVE,
4168 EL_GATE_4_GRAY_ACTIVE,
4177 EL_EM_GATE_1_GRAY_ACTIVE,
4178 EL_EM_GATE_2_GRAY_ACTIVE,
4179 EL_EM_GATE_3_GRAY_ACTIVE,
4180 EL_EM_GATE_4_GRAY_ACTIVE,
4189 EL_EMC_GATE_5_GRAY_ACTIVE,
4190 EL_EMC_GATE_6_GRAY_ACTIVE,
4191 EL_EMC_GATE_7_GRAY_ACTIVE,
4192 EL_EMC_GATE_8_GRAY_ACTIVE,
4194 EL_DC_GATE_WHITE_GRAY,
4195 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4196 EL_DC_GATE_FAKE_GRAY,
4199 EL_INVISIBLE_STEELWALL,
4207 EL_WALL_EMERALD_YELLOW,
4208 EL_DYNABOMB_INCREASE_NUMBER,
4209 EL_DYNABOMB_INCREASE_SIZE,
4210 EL_DYNABOMB_INCREASE_POWER,
4214 EL_SOKOBAN_FIELD_EMPTY,
4215 EL_SOKOBAN_FIELD_FULL,
4216 EL_WALL_EMERALD_RED,
4217 EL_WALL_EMERALD_PURPLE,
4218 EL_ACID_POOL_TOPLEFT,
4219 EL_ACID_POOL_TOPRIGHT,
4220 EL_ACID_POOL_BOTTOMLEFT,
4221 EL_ACID_POOL_BOTTOM,
4222 EL_ACID_POOL_BOTTOMRIGHT,
4226 EL_BD_MAGIC_WALL_DEAD,
4228 EL_DC_MAGIC_WALL_DEAD,
4229 EL_AMOEBA_TO_DIAMOND,
4237 EL_SP_GRAVITY_PORT_RIGHT,
4238 EL_SP_GRAVITY_PORT_DOWN,
4239 EL_SP_GRAVITY_PORT_LEFT,
4240 EL_SP_GRAVITY_PORT_UP,
4241 EL_SP_PORT_HORIZONTAL,
4242 EL_SP_PORT_VERTICAL,
4253 EL_SP_HARDWARE_GRAY,
4254 EL_SP_HARDWARE_GREEN,
4255 EL_SP_HARDWARE_BLUE,
4257 EL_SP_HARDWARE_YELLOW,
4258 EL_SP_HARDWARE_BASE_1,
4259 EL_SP_HARDWARE_BASE_2,
4260 EL_SP_HARDWARE_BASE_3,
4261 EL_SP_HARDWARE_BASE_4,
4262 EL_SP_HARDWARE_BASE_5,
4263 EL_SP_HARDWARE_BASE_6,
4264 EL_SP_GRAVITY_ON_PORT_LEFT,
4265 EL_SP_GRAVITY_ON_PORT_RIGHT,
4266 EL_SP_GRAVITY_ON_PORT_UP,
4267 EL_SP_GRAVITY_ON_PORT_DOWN,
4268 EL_SP_GRAVITY_OFF_PORT_LEFT,
4269 EL_SP_GRAVITY_OFF_PORT_RIGHT,
4270 EL_SP_GRAVITY_OFF_PORT_UP,
4271 EL_SP_GRAVITY_OFF_PORT_DOWN,
4272 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4273 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4274 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4275 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4276 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4277 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4278 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4279 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4280 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4281 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4282 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4283 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4284 EL_SIGN_EXCLAMATION,
4285 EL_SIGN_RADIOACTIVITY,
4292 EL_SIGN_ENTRY_FORBIDDEN,
4293 EL_SIGN_EMERGENCY_EXIT,
4301 EL_DC_STEELWALL_1_LEFT,
4302 EL_DC_STEELWALL_1_RIGHT,
4303 EL_DC_STEELWALL_1_TOP,
4304 EL_DC_STEELWALL_1_BOTTOM,
4305 EL_DC_STEELWALL_1_HORIZONTAL,
4306 EL_DC_STEELWALL_1_VERTICAL,
4307 EL_DC_STEELWALL_1_TOPLEFT,
4308 EL_DC_STEELWALL_1_TOPRIGHT,
4309 EL_DC_STEELWALL_1_BOTTOMLEFT,
4310 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4311 EL_DC_STEELWALL_1_TOPLEFT_2,
4312 EL_DC_STEELWALL_1_TOPRIGHT_2,
4313 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4314 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4315 EL_DC_STEELWALL_2_LEFT,
4316 EL_DC_STEELWALL_2_RIGHT,
4317 EL_DC_STEELWALL_2_TOP,
4318 EL_DC_STEELWALL_2_BOTTOM,
4319 EL_DC_STEELWALL_2_HORIZONTAL,
4320 EL_DC_STEELWALL_2_VERTICAL,
4321 EL_DC_STEELWALL_2_MIDDLE,
4322 EL_DC_STEELWALL_2_SINGLE,
4323 EL_STEELWALL_SLIPPERY,
4328 EL_EMC_WALL_SLIPPERY_1,
4329 EL_EMC_WALL_SLIPPERY_2,
4330 EL_EMC_WALL_SLIPPERY_3,
4331 EL_EMC_WALL_SLIPPERY_4,
4352 static int ep_em_slippery_wall[] =
4357 static int ep_gfx_crumbled[] =
4368 static int ep_editor_cascade_active[] =
4370 EL_INTERNAL_CASCADE_BD_ACTIVE,
4371 EL_INTERNAL_CASCADE_EM_ACTIVE,
4372 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4373 EL_INTERNAL_CASCADE_RND_ACTIVE,
4374 EL_INTERNAL_CASCADE_SB_ACTIVE,
4375 EL_INTERNAL_CASCADE_SP_ACTIVE,
4376 EL_INTERNAL_CASCADE_DC_ACTIVE,
4377 EL_INTERNAL_CASCADE_DX_ACTIVE,
4378 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4379 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4380 EL_INTERNAL_CASCADE_CE_ACTIVE,
4381 EL_INTERNAL_CASCADE_GE_ACTIVE,
4382 EL_INTERNAL_CASCADE_REF_ACTIVE,
4383 EL_INTERNAL_CASCADE_USER_ACTIVE,
4384 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4389 static int ep_editor_cascade_inactive[] =
4391 EL_INTERNAL_CASCADE_BD,
4392 EL_INTERNAL_CASCADE_EM,
4393 EL_INTERNAL_CASCADE_EMC,
4394 EL_INTERNAL_CASCADE_RND,
4395 EL_INTERNAL_CASCADE_SB,
4396 EL_INTERNAL_CASCADE_SP,
4397 EL_INTERNAL_CASCADE_DC,
4398 EL_INTERNAL_CASCADE_DX,
4399 EL_INTERNAL_CASCADE_CHARS,
4400 EL_INTERNAL_CASCADE_STEEL_CHARS,
4401 EL_INTERNAL_CASCADE_CE,
4402 EL_INTERNAL_CASCADE_GE,
4403 EL_INTERNAL_CASCADE_REF,
4404 EL_INTERNAL_CASCADE_USER,
4405 EL_INTERNAL_CASCADE_DYNAMIC,
4410 static int ep_obsolete[] =
4414 EL_EM_KEY_1_FILE_OBSOLETE,
4415 EL_EM_KEY_2_FILE_OBSOLETE,
4416 EL_EM_KEY_3_FILE_OBSOLETE,
4417 EL_EM_KEY_4_FILE_OBSOLETE,
4418 EL_ENVELOPE_OBSOLETE,
4427 } element_properties[] =
4429 { ep_diggable, EP_DIGGABLE },
4430 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4431 { ep_dont_run_into, EP_DONT_RUN_INTO },
4432 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4433 { ep_dont_touch, EP_DONT_TOUCH },
4434 { ep_indestructible, EP_INDESTRUCTIBLE },
4435 { ep_slippery, EP_SLIPPERY },
4436 { ep_can_change, EP_CAN_CHANGE },
4437 { ep_can_move, EP_CAN_MOVE },
4438 { ep_can_fall, EP_CAN_FALL },
4439 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4440 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4441 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4442 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4443 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4444 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4445 { ep_walkable_over, EP_WALKABLE_OVER },
4446 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4447 { ep_walkable_under, EP_WALKABLE_UNDER },
4448 { ep_passable_over, EP_PASSABLE_OVER },
4449 { ep_passable_inside, EP_PASSABLE_INSIDE },
4450 { ep_passable_under, EP_PASSABLE_UNDER },
4451 { ep_droppable, EP_DROPPABLE },
4452 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4453 { ep_pushable, EP_PUSHABLE },
4454 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4455 { ep_protected, EP_PROTECTED },
4456 { ep_throwable, EP_THROWABLE },
4457 { ep_can_explode, EP_CAN_EXPLODE },
4458 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4460 { ep_player, EP_PLAYER },
4461 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4462 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4463 { ep_switchable, EP_SWITCHABLE },
4464 { ep_bd_element, EP_BD_ELEMENT },
4465 { ep_sp_element, EP_SP_ELEMENT },
4466 { ep_sb_element, EP_SB_ELEMENT },
4468 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4469 { ep_food_penguin, EP_FOOD_PENGUIN },
4470 { ep_food_pig, EP_FOOD_PIG },
4471 { ep_historic_wall, EP_HISTORIC_WALL },
4472 { ep_historic_solid, EP_HISTORIC_SOLID },
4473 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4474 { ep_belt, EP_BELT },
4475 { ep_belt_active, EP_BELT_ACTIVE },
4476 { ep_belt_switch, EP_BELT_SWITCH },
4477 { ep_tube, EP_TUBE },
4478 { ep_acid_pool, EP_ACID_POOL },
4479 { ep_keygate, EP_KEYGATE },
4480 { ep_amoeboid, EP_AMOEBOID },
4481 { ep_amoebalive, EP_AMOEBALIVE },
4482 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4483 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4484 { ep_can_grow, EP_CAN_GROW },
4485 { ep_active_bomb, EP_ACTIVE_BOMB },
4486 { ep_inactive, EP_INACTIVE },
4488 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4490 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4492 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4493 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4495 { ep_obsolete, EP_OBSOLETE },
4502 /* always start with reliable default values (element has no properties) */
4503 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4504 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4505 SET_PROPERTY(i, j, FALSE);
4507 /* set all base element properties from above array definitions */
4508 for (i = 0; element_properties[i].elements != NULL; i++)
4509 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4510 SET_PROPERTY((element_properties[i].elements)[j],
4511 element_properties[i].property, TRUE);
4513 /* copy properties to some elements that are only stored in level file */
4514 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4515 for (j = 0; copy_properties[j][0] != -1; j++)
4516 if (HAS_PROPERTY(copy_properties[j][0], i))
4517 for (k = 1; k <= 4; k++)
4518 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4520 /* set static element properties that are not listed in array definitions */
4521 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4522 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4525 void InitElementPropertiesEngine(int engine_version)
4527 static int no_wall_properties[] =
4530 EP_COLLECTIBLE_ONLY,
4532 EP_DONT_COLLIDE_WITH,
4535 EP_CAN_SMASH_PLAYER,
4536 EP_CAN_SMASH_ENEMIES,
4537 EP_CAN_SMASH_EVERYTHING,
4542 EP_FOOD_DARK_YAMYAM,
4558 /* important: after initialization in InitElementPropertiesStatic(), the
4559 elements are not again initialized to a default value; therefore all
4560 changes have to make sure that they leave the element with a defined
4561 property (which means that conditional property changes must be set to
4562 a reliable default value before) */
4564 /* resolve group elements */
4565 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4566 ResolveGroupElement(EL_GROUP_START + i);
4568 /* set all special, combined or engine dependent element properties */
4569 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4571 /* ---------- INACTIVE ------------------------------------------------- */
4572 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4573 i <= EL_CHAR_END) ||
4574 (i >= EL_STEEL_CHAR_START &&
4575 i <= EL_STEEL_CHAR_END)));
4577 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4578 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4579 IS_WALKABLE_INSIDE(i) ||
4580 IS_WALKABLE_UNDER(i)));
4582 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4583 IS_PASSABLE_INSIDE(i) ||
4584 IS_PASSABLE_UNDER(i)));
4586 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4587 IS_PASSABLE_OVER(i)));
4589 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4590 IS_PASSABLE_INSIDE(i)));
4592 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4593 IS_PASSABLE_UNDER(i)));
4595 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4598 /* ---------- COLLECTIBLE ---------------------------------------------- */
4599 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4603 /* ---------- SNAPPABLE ------------------------------------------------ */
4604 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4605 IS_COLLECTIBLE(i) ||
4609 /* ---------- WALL ----------------------------------------------------- */
4610 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4612 for (j = 0; no_wall_properties[j] != -1; j++)
4613 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4614 i >= EL_FIRST_RUNTIME_UNREAL)
4615 SET_PROPERTY(i, EP_WALL, FALSE);
4617 if (IS_HISTORIC_WALL(i))
4618 SET_PROPERTY(i, EP_WALL, TRUE);
4620 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4621 if (engine_version < VERSION_IDENT(2,2,0,0))
4622 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4624 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4626 !IS_COLLECTIBLE(i)));
4628 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4629 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4630 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4632 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4633 IS_INDESTRUCTIBLE(i)));
4635 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4637 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4638 else if (engine_version < VERSION_IDENT(2,2,0,0))
4639 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4641 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4645 if (IS_CUSTOM_ELEMENT(i))
4647 /* these are additional properties which are initially false when set */
4649 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4651 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4652 if (DONT_COLLIDE_WITH(i))
4653 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4655 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4656 if (CAN_SMASH_EVERYTHING(i))
4657 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4658 if (CAN_SMASH_ENEMIES(i))
4659 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4662 /* ---------- CAN_SMASH ------------------------------------------------ */
4663 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4664 CAN_SMASH_ENEMIES(i) ||
4665 CAN_SMASH_EVERYTHING(i)));
4667 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4668 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4669 EXPLODES_BY_FIRE(i)));
4671 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4672 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4673 EXPLODES_SMASHED(i)));
4675 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4676 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4677 EXPLODES_IMPACT(i)));
4679 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4680 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4682 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4683 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4684 i == EL_BLACK_ORB));
4686 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4687 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4689 IS_CUSTOM_ELEMENT(i)));
4691 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4692 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4693 i == EL_SP_ELECTRON));
4695 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4696 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4697 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4698 getMoveIntoAcidProperty(&level, i));
4700 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4701 if (MAYBE_DONT_COLLIDE_WITH(i))
4702 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4703 getDontCollideWithProperty(&level, i));
4705 /* ---------- SP_PORT -------------------------------------------------- */
4706 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4707 IS_PASSABLE_INSIDE(i)));
4709 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4710 for (j = 0; j < level.num_android_clone_elements; j++)
4711 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4713 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4715 /* ---------- CAN_CHANGE ----------------------------------------------- */
4716 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4717 for (j = 0; j < element_info[i].num_change_pages; j++)
4718 if (element_info[i].change_page[j].can_change)
4719 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4721 /* ---------- HAS_ACTION ----------------------------------------------- */
4722 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4723 for (j = 0; j < element_info[i].num_change_pages; j++)
4724 if (element_info[i].change_page[j].has_action)
4725 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4727 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4728 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4731 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4733 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4734 element_info[i].crumbled[ACTION_DEFAULT] !=
4735 element_info[i].graphic[ACTION_DEFAULT]);
4737 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
4738 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4739 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
4742 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4743 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4744 IS_EDITOR_CASCADE_INACTIVE(i)));
4747 /* dynamically adjust element properties according to game engine version */
4749 static int ep_em_slippery_wall[] =
4754 EL_EXPANDABLE_WALL_HORIZONTAL,
4755 EL_EXPANDABLE_WALL_VERTICAL,
4756 EL_EXPANDABLE_WALL_ANY,
4757 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4758 EL_EXPANDABLE_STEELWALL_VERTICAL,
4759 EL_EXPANDABLE_STEELWALL_ANY,
4760 EL_EXPANDABLE_STEELWALL_GROWING,
4764 /* special EM style gems behaviour */
4765 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4766 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4767 level.em_slippery_gems);
4769 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4770 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4771 (level.em_slippery_gems &&
4772 engine_version > VERSION_IDENT(2,0,1,0)));
4775 /* this is needed because some graphics depend on element properties */
4776 if (game_status == GAME_MODE_PLAYING)
4777 InitElementGraphicInfo();
4780 void InitElementPropertiesAfterLoading(int engine_version)
4784 /* set some other uninitialized values of custom elements in older levels */
4785 if (engine_version < VERSION_IDENT(3,1,0,0))
4787 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4789 int element = EL_CUSTOM_START + i;
4791 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4793 element_info[element].explosion_delay = 17;
4794 element_info[element].ignition_delay = 8;
4799 static void InitGlobal()
4803 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4805 /* check if element_name_info entry defined for each element in "main.h" */
4806 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4807 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4809 element_info[i].token_name = element_name_info[i].token_name;
4810 element_info[i].class_name = element_name_info[i].class_name;
4811 element_info[i].editor_description= element_name_info[i].editor_description;
4814 printf("%04d: %s\n", i, element_name_info[i].token_name);
4818 /* always start with reliable default values (all elements) */
4819 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4820 ActiveElement[i] = i;
4822 /* now add all entries that have an active state (active elements) */
4823 for (i = 0; element_with_active_state[i].element != -1; i++)
4825 int element = element_with_active_state[i].element;
4826 int element_active = element_with_active_state[i].element_active;
4828 ActiveElement[element] = element_active;
4831 /* always start with reliable default values (all buttons) */
4832 for (i = 0; i < NUM_IMAGE_FILES; i++)
4833 ActiveButton[i] = i;
4835 /* now add all entries that have an active state (active buttons) */
4836 for (i = 0; button_with_active_state[i].button != -1; i++)
4838 int button = button_with_active_state[i].button;
4839 int button_active = button_with_active_state[i].button_active;
4841 ActiveButton[button] = button_active;
4844 /* always start with reliable default values (all fonts) */
4845 for (i = 0; i < NUM_FONTS; i++)
4848 /* now add all entries that have an active state (active fonts) */
4849 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4851 int font = font_with_active_state[i].font_nr;
4852 int font_active = font_with_active_state[i].font_nr_active;
4854 ActiveFont[font] = font_active;
4857 global.autoplay_leveldir = NULL;
4858 global.convert_leveldir = NULL;
4860 global.frames_per_second = 0;
4861 global.fps_slowdown = FALSE;
4862 global.fps_slowdown_factor = 1;
4864 global.border_status = GAME_MODE_MAIN;
4866 global.fading_status = GAME_MODE_MAIN;
4867 global.fading_type = TYPE_ENTER_MENU;
4871 void Execute_Command(char *command)
4875 if (strEqual(command, "print graphicsinfo.conf"))
4877 printf("# You can configure additional/alternative image files here.\n");
4878 printf("# (The entries below are default and therefore commented out.)\n");
4880 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4882 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4885 for (i = 0; image_config[i].token != NULL; i++)
4886 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
4887 image_config[i].value));
4891 else if (strEqual(command, "print soundsinfo.conf"))
4893 printf("# You can configure additional/alternative sound files here.\n");
4894 printf("# (The entries below are default and therefore commented out.)\n");
4896 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4898 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4901 for (i = 0; sound_config[i].token != NULL; i++)
4902 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4903 sound_config[i].value));
4907 else if (strEqual(command, "print musicinfo.conf"))
4909 printf("# You can configure additional/alternative music files here.\n");
4910 printf("# (The entries below are default and therefore commented out.)\n");
4912 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4914 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4917 for (i = 0; music_config[i].token != NULL; i++)
4918 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
4919 music_config[i].value));
4923 else if (strEqual(command, "print editorsetup.conf"))
4925 printf("# You can configure your personal editor element list here.\n");
4926 printf("# (The entries below are default and therefore commented out.)\n");
4929 /* this is needed to be able to check element list for cascade elements */
4930 InitElementPropertiesStatic();
4931 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4933 PrintEditorElementList();
4937 else if (strEqual(command, "print helpanim.conf"))
4939 printf("# You can configure different element help animations here.\n");
4940 printf("# (The entries below are default and therefore commented out.)\n");
4943 for (i = 0; helpanim_config[i].token != NULL; i++)
4945 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4946 helpanim_config[i].value));
4948 if (strEqual(helpanim_config[i].token, "end"))
4954 else if (strEqual(command, "print helptext.conf"))
4956 printf("# You can configure different element help text here.\n");
4957 printf("# (The entries below are default and therefore commented out.)\n");
4960 for (i = 0; helptext_config[i].token != NULL; i++)
4961 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4962 helptext_config[i].value));
4966 else if (strncmp(command, "dump level ", 11) == 0)
4968 char *filename = &command[11];
4970 if (!fileExists(filename))
4971 Error(ERR_EXIT, "cannot open file '%s'", filename);
4973 LoadLevelFromFilename(&level, filename);
4978 else if (strncmp(command, "dump tape ", 10) == 0)
4980 char *filename = &command[10];
4982 if (!fileExists(filename))
4983 Error(ERR_EXIT, "cannot open file '%s'", filename);
4985 LoadTapeFromFilename(filename);
4990 else if (strncmp(command, "autoplay ", 9) == 0)
4992 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
4994 while (*str_ptr != '\0') /* continue parsing string */
4996 /* cut leading whitespace from string, replace it by string terminator */
4997 while (*str_ptr == ' ' || *str_ptr == '\t')
5000 if (*str_ptr == '\0') /* end of string reached */
5003 if (global.autoplay_leveldir == NULL) /* read level set string */
5005 global.autoplay_leveldir = str_ptr;
5006 global.autoplay_all = TRUE; /* default: play all tapes */
5008 for (i = 0; i < MAX_TAPES_PER_SET; i++)
5009 global.autoplay_level[i] = FALSE;
5011 else /* read level number string */
5013 int level_nr = atoi(str_ptr); /* get level_nr value */
5015 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5016 global.autoplay_level[level_nr] = TRUE;
5018 global.autoplay_all = FALSE;
5021 /* advance string pointer to the next whitespace (or end of string) */
5022 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5026 else if (strncmp(command, "convert ", 8) == 0)
5028 char *str_copy = getStringCopy(&command[8]);
5029 char *str_ptr = strchr(str_copy, ' ');
5031 global.convert_leveldir = str_copy;
5032 global.convert_level_nr = -1;
5034 if (str_ptr != NULL) /* level number follows */
5036 *str_ptr++ = '\0'; /* terminate leveldir string */
5037 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
5042 #if defined(TARGET_SDL)
5043 else if (strEqual(command, "SDL_ListModes"))
5048 SDL_Init(SDL_INIT_VIDEO);
5050 /* get available fullscreen/hardware modes */
5051 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
5053 /* check if there are any modes available */
5056 printf("No modes available!\n");
5061 /* check if our resolution is restricted */
5062 if (modes == (SDL_Rect **)-1)
5064 printf("All resolutions available.\n");
5068 printf("Available Modes:\n");
5070 for(i = 0; modes[i]; i++)
5071 printf(" %d x %d\n", modes[i]->w, modes[i]->h);
5081 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
5085 static void InitSetup()
5087 LoadSetup(); /* global setup info */
5089 /* set some options from setup file */
5091 if (setup.options.verbose)
5092 options.verbose = TRUE;
5095 static void InitGameInfo()
5097 game.restart_level = FALSE;
5100 static void InitPlayerInfo()
5104 /* choose default local player */
5105 local_player = &stored_player[0];
5107 for (i = 0; i < MAX_PLAYERS; i++)
5108 stored_player[i].connected = FALSE;
5110 local_player->connected = TRUE;
5113 static void InitArtworkInfo()
5118 static char *get_string_in_brackets(char *string)
5120 char *string_in_brackets = checked_malloc(strlen(string) + 3);
5122 sprintf(string_in_brackets, "[%s]", string);
5124 return string_in_brackets;
5127 static char *get_level_id_suffix(int id_nr)
5129 char *id_suffix = checked_malloc(1 + 3 + 1);
5131 if (id_nr < 0 || id_nr > 999)
5134 sprintf(id_suffix, ".%03d", id_nr);
5140 static char *get_element_class_token(int element)
5142 char *element_class_name = element_info[element].class_name;
5143 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
5145 sprintf(element_class_token, "[%s]", element_class_name);
5147 return element_class_token;
5150 static char *get_action_class_token(int action)
5152 char *action_class_name = &element_action_info[action].suffix[1];
5153 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
5155 sprintf(action_class_token, "[%s]", action_class_name);
5157 return action_class_token;
5161 static void InitArtworkConfig()
5163 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
5164 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
5165 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
5166 static char *action_id_suffix[NUM_ACTIONS + 1];
5167 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5168 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5169 static char *level_id_suffix[MAX_LEVELS + 1];
5170 static char *dummy[1] = { NULL };
5171 static char *ignore_generic_tokens[] =
5177 static char **ignore_image_tokens;
5178 static char **ignore_sound_tokens;
5179 static char **ignore_music_tokens;
5180 int num_ignore_generic_tokens;
5181 int num_ignore_image_tokens;
5182 int num_ignore_sound_tokens;
5183 int num_ignore_music_tokens;
5186 /* dynamically determine list of generic tokens to be ignored */
5187 num_ignore_generic_tokens = 0;
5188 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5189 num_ignore_generic_tokens++;
5191 /* dynamically determine list of image tokens to be ignored */
5192 num_ignore_image_tokens = num_ignore_generic_tokens;
5193 for (i = 0; image_config_vars[i].token != NULL; i++)
5194 num_ignore_image_tokens++;
5195 ignore_image_tokens =
5196 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5197 for (i = 0; i < num_ignore_generic_tokens; i++)
5198 ignore_image_tokens[i] = ignore_generic_tokens[i];
5199 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5200 ignore_image_tokens[num_ignore_generic_tokens + i] =
5201 image_config_vars[i].token;
5202 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5204 /* dynamically determine list of sound tokens to be ignored */
5205 num_ignore_sound_tokens = num_ignore_generic_tokens;
5206 ignore_sound_tokens =
5207 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5208 for (i = 0; i < num_ignore_generic_tokens; i++)
5209 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5210 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5212 /* dynamically determine list of music tokens to be ignored */
5213 num_ignore_music_tokens = num_ignore_generic_tokens;
5214 ignore_music_tokens =
5215 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5216 for (i = 0; i < num_ignore_generic_tokens; i++)
5217 ignore_music_tokens[i] = ignore_generic_tokens[i];
5218 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5220 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5221 image_id_prefix[i] = element_info[i].token_name;
5222 for (i = 0; i < NUM_FONTS; i++)
5223 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5224 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
5226 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5227 sound_id_prefix[i] = element_info[i].token_name;
5228 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5229 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5230 get_string_in_brackets(element_info[i].class_name);
5231 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
5233 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5234 music_id_prefix[i] = music_prefix_info[i].prefix;
5235 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
5237 for (i = 0; i < NUM_ACTIONS; i++)
5238 action_id_suffix[i] = element_action_info[i].suffix;
5239 action_id_suffix[NUM_ACTIONS] = NULL;
5241 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5242 direction_id_suffix[i] = element_direction_info[i].suffix;
5243 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5245 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5246 special_id_suffix[i] = special_suffix_info[i].suffix;
5247 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5249 for (i = 0; i < MAX_LEVELS; i++)
5250 level_id_suffix[i] = get_level_id_suffix(i);
5251 level_id_suffix[MAX_LEVELS] = NULL;
5253 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5254 image_id_prefix, action_id_suffix, direction_id_suffix,
5255 special_id_suffix, ignore_image_tokens);
5256 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5257 sound_id_prefix, action_id_suffix, dummy,
5258 special_id_suffix, ignore_sound_tokens);
5259 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5260 music_id_prefix, special_id_suffix, level_id_suffix,
5261 dummy, ignore_music_tokens);
5264 static void InitMixer()
5272 char *filename_font_initial = NULL;
5273 char *filename_anim_initial = NULL;
5274 Bitmap *bitmap_font_initial = NULL;
5278 /* determine settings for initial font (for displaying startup messages) */
5279 for (i = 0; image_config[i].token != NULL; i++)
5281 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5283 char font_token[128];
5286 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5287 len_font_token = strlen(font_token);
5289 if (strEqual(image_config[i].token, font_token))
5290 filename_font_initial = image_config[i].value;
5291 else if (strlen(image_config[i].token) > len_font_token &&
5292 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5294 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5295 font_initial[j].src_x = atoi(image_config[i].value);
5296 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5297 font_initial[j].src_y = atoi(image_config[i].value);
5298 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5299 font_initial[j].width = atoi(image_config[i].value);
5300 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5301 font_initial[j].height = atoi(image_config[i].value);
5306 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5308 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5309 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5312 if (filename_font_initial == NULL) /* should not happen */
5313 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5315 /* create additional image buffers for double-buffering and cross-fading */
5316 bitmap_db_cross = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5317 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
5318 bitmap_db_panel = CreateBitmap(DXSIZE, DYSIZE, DEFAULT_DEPTH);
5319 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
5321 /* initialize screen properties */
5322 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5323 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5325 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5326 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5327 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5329 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5331 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5332 font_initial[j].bitmap = bitmap_font_initial;
5334 InitFontGraphicInfo();
5336 font_height = getFontHeight(FC_RED);
5339 DrawInitText(getWindowTitleString(), 20, FC_YELLOW);
5341 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
5343 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
5344 DrawInitText(PROGRAM_WEBSITE_STRING, WIN_YSIZE - 20 - font_height, FC_RED);
5346 DrawInitText("Loading graphics", 120, FC_GREEN);
5350 /* initialize busy animation with default values */
5351 int parameter[NUM_GFX_ARGS];
5352 for (i = 0; i < NUM_GFX_ARGS; i++)
5353 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5354 image_config_suffix[i].token,
5355 image_config_suffix[i].type);
5357 for (i = 0; i < NUM_GFX_ARGS; i++)
5358 printf("::: '%s' => %d\n", image_config_suffix[i].token, parameter[i]);
5362 /* determine settings for busy animation (when displaying startup messages) */
5363 for (i = 0; image_config[i].token != NULL; i++)
5365 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5366 int len_anim_token = strlen(anim_token);
5368 if (strEqual(image_config[i].token, anim_token))
5369 filename_anim_initial = image_config[i].value;
5370 else if (strlen(image_config[i].token) > len_anim_token &&
5371 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5374 for (j = 0; image_config_suffix[j].token != NULL; j++)
5376 if (strEqual(&image_config[i].token[len_anim_token],
5377 image_config_suffix[j].token))
5379 get_graphic_parameter_value(image_config[i].value,
5380 image_config_suffix[j].token,
5381 image_config_suffix[j].type);
5384 if (strEqual(&image_config[i].token[len_anim_token], ".x"))
5385 anim_initial.src_x = atoi(image_config[i].value);
5386 else if (strEqual(&image_config[i].token[len_anim_token], ".y"))
5387 anim_initial.src_y = atoi(image_config[i].value);
5388 else if (strEqual(&image_config[i].token[len_anim_token], ".width"))
5389 anim_initial.width = atoi(image_config[i].value);
5390 else if (strEqual(&image_config[i].token[len_anim_token], ".height"))
5391 anim_initial.height = atoi(image_config[i].value);
5392 else if (strEqual(&image_config[i].token[len_anim_token], ".frames"))
5393 anim_initial.anim_frames = atoi(image_config[i].value);
5394 else if (strEqual(&image_config[i].token[len_anim_token],
5395 ".frames_per_line"))
5396 anim_initial.anim_frames_per_line = atoi(image_config[i].value);
5397 else if (strEqual(&image_config[i].token[len_anim_token], ".delay"))
5398 anim_initial.anim_delay = atoi(image_config[i].value);
5403 set_graphic_parameters_ext(0, &anim_initial, parameter, NULL);
5405 if (filename_anim_initial == NULL) /* should not happen */
5406 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5408 anim_initial.bitmap = LoadCustomImage(filename_anim_initial);
5410 init.busy.width = anim_initial.width;
5411 init.busy.height = anim_initial.height;
5413 InitMenuDesignSettings_Static();
5414 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5418 void RedrawBackground()
5420 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
5421 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
5423 redraw_mask = REDRAW_ALL;
5426 void InitGfxBackground()
5430 fieldbuffer = bitmap_db_field;
5431 SetDrawtoField(DRAW_BACKBUFFER);
5434 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5438 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
5439 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
5442 for (x = 0; x < MAX_BUF_XSIZE; x++)
5443 for (y = 0; y < MAX_BUF_YSIZE; y++)
5446 redraw_mask = REDRAW_ALL;
5449 static void InitLevelInfo()
5451 LoadLevelInfo(); /* global level info */
5452 LoadLevelSetup_LastSeries(); /* last played series info */
5453 LoadLevelSetup_SeriesInfo(); /* last played level info */
5456 void InitLevelArtworkInfo()
5458 LoadLevelArtworkInfo();
5461 static void InitImages()
5463 print_init_timestamp("INIT InitImages");
5465 setLevelArtworkDir(artwork.gfx_first);
5468 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5469 leveldir_current->identifier,
5470 artwork.gfx_current_identifier,
5471 artwork.gfx_current->identifier,
5472 leveldir_current->graphics_set,
5473 leveldir_current->graphics_path);
5476 UPDATE_BUSY_STATE();
5478 ReloadCustomImages();
5479 print_init_timestamp("TIME ReloadCustomImages");
5481 UPDATE_BUSY_STATE();
5483 LoadCustomElementDescriptions();
5484 print_init_timestamp("TIME LoadCustomElementDescriptions");
5486 UPDATE_BUSY_STATE();
5488 LoadMenuDesignSettings();
5489 print_init_timestamp("TIME LoadMenuDesignSettings");
5491 UPDATE_BUSY_STATE();
5493 ReinitializeGraphics();
5494 print_init_timestamp("TIME ReinitializeGraphics");
5496 UPDATE_BUSY_STATE();
5498 print_init_timestamp("DONE InitImages");
5501 static void InitSound(char *identifier)
5503 print_init_timestamp("INIT InitSound");
5505 if (identifier == NULL)
5506 identifier = artwork.snd_current->identifier;
5508 /* set artwork path to send it to the sound server process */
5509 setLevelArtworkDir(artwork.snd_first);
5511 InitReloadCustomSounds(identifier);
5512 print_init_timestamp("TIME InitReloadCustomSounds");
5514 ReinitializeSounds();
5515 print_init_timestamp("TIME ReinitializeSounds");
5517 print_init_timestamp("DONE InitSound");
5520 static void InitMusic(char *identifier)
5522 print_init_timestamp("INIT InitMusic");
5524 if (identifier == NULL)
5525 identifier = artwork.mus_current->identifier;
5527 /* set artwork path to send it to the sound server process */
5528 setLevelArtworkDir(artwork.mus_first);
5530 InitReloadCustomMusic(identifier);
5531 print_init_timestamp("TIME InitReloadCustomMusic");
5533 ReinitializeMusic();
5534 print_init_timestamp("TIME ReinitializeMusic");
5536 print_init_timestamp("DONE InitMusic");
5539 void InitNetworkServer()
5541 #if defined(NETWORK_AVALIABLE)
5545 if (!options.network)
5548 #if defined(NETWORK_AVALIABLE)
5549 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5551 if (!ConnectToServer(options.server_host, options.server_port))
5552 Error(ERR_EXIT, "cannot connect to network game server");
5554 SendToServer_PlayerName(setup.player_name);
5555 SendToServer_ProtocolVersion();
5558 SendToServer_NrWanted(nr_wanted);
5562 static char *getNewArtworkIdentifier(int type)
5564 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5565 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5566 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5567 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5568 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5569 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
5570 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5571 char *leveldir_identifier = leveldir_current->identifier;
5573 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
5574 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5576 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
5578 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5579 char *artwork_current_identifier;
5580 char *artwork_new_identifier = NULL; /* default: nothing has changed */
5582 /* leveldir_current may be invalid (level group, parent link) */
5583 if (!validLevelSeries(leveldir_current))
5586 /* 1st step: determine artwork set to be activated in descending order:
5587 --------------------------------------------------------------------
5588 1. setup artwork (when configured to override everything else)
5589 2. artwork set configured in "levelinfo.conf" of current level set
5590 (artwork in level directory will have priority when loading later)
5591 3. artwork in level directory (stored in artwork sub-directory)
5592 4. setup artwork (currently configured in setup menu) */
5594 if (setup_override_artwork)
5595 artwork_current_identifier = setup_artwork_set;
5596 else if (leveldir_artwork_set != NULL)
5597 artwork_current_identifier = leveldir_artwork_set;
5598 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5599 artwork_current_identifier = leveldir_identifier;
5601 artwork_current_identifier = setup_artwork_set;
5604 /* 2nd step: check if it is really needed to reload artwork set
5605 ------------------------------------------------------------ */
5608 if (type == ARTWORK_TYPE_GRAPHICS)
5609 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
5610 artwork_new_identifier,
5611 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5612 artwork_current_identifier,
5613 leveldir_current->graphics_set,
5614 leveldir_current->identifier);
5617 /* ---------- reload if level set and also artwork set has changed ------- */
5618 if (leveldir_current_identifier[type] != leveldir_identifier &&
5619 (last_has_level_artwork_set[type] || has_level_artwork_set))
5620 artwork_new_identifier = artwork_current_identifier;
5622 leveldir_current_identifier[type] = leveldir_identifier;
5623 last_has_level_artwork_set[type] = has_level_artwork_set;
5626 if (type == ARTWORK_TYPE_GRAPHICS)
5627 printf("::: 1: '%s'\n", artwork_new_identifier);
5630 /* ---------- reload if "override artwork" setting has changed ----------- */
5631 if (last_override_level_artwork[type] != setup_override_artwork)
5632 artwork_new_identifier = artwork_current_identifier;
5634 last_override_level_artwork[type] = setup_override_artwork;
5637 if (type == ARTWORK_TYPE_GRAPHICS)
5638 printf("::: 2: '%s'\n", artwork_new_identifier);
5641 /* ---------- reload if current artwork identifier has changed ----------- */
5642 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5643 artwork_current_identifier))
5644 artwork_new_identifier = artwork_current_identifier;
5646 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5649 if (type == ARTWORK_TYPE_GRAPHICS)
5650 printf("::: 3: '%s'\n", artwork_new_identifier);
5653 /* ---------- do not reload directly after starting ---------------------- */
5654 if (!initialized[type])
5655 artwork_new_identifier = NULL;
5657 initialized[type] = TRUE;
5660 if (type == ARTWORK_TYPE_GRAPHICS)
5661 printf("::: 4: '%s'\n", artwork_new_identifier);
5665 if (type == ARTWORK_TYPE_GRAPHICS)
5666 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
5667 artwork.gfx_current_identifier, artwork_current_identifier,
5668 artwork.gfx_current->identifier, leveldir_current->graphics_set,
5669 artwork_new_identifier);
5672 return artwork_new_identifier;
5675 void ReloadCustomArtwork(int force_reload)
5677 char *gfx_new_identifier;
5678 char *snd_new_identifier;
5679 char *mus_new_identifier;
5680 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5681 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5682 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5683 boolean reload_needed;
5685 force_reload_gfx |= AdjustGraphicsForEMC();
5687 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5688 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5689 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5691 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
5692 snd_new_identifier != NULL || force_reload_snd ||
5693 mus_new_identifier != NULL || force_reload_mus);
5698 print_init_timestamp("INIT ReloadCustomArtwork");
5700 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
5701 print_init_timestamp("TIME ClearRectangle");
5703 if (gfx_new_identifier != NULL || force_reload_gfx)
5706 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5707 artwork.gfx_current_identifier,
5709 artwork.gfx_current->identifier,
5710 leveldir_current->graphics_set);
5714 print_init_timestamp("TIME InitImages");
5717 if (snd_new_identifier != NULL || force_reload_snd)
5719 InitSound(snd_new_identifier);
5720 print_init_timestamp("TIME InitSound");
5723 if (mus_new_identifier != NULL || force_reload_mus)
5725 InitMusic(mus_new_identifier);
5726 print_init_timestamp("TIME InitMusic");
5731 /* force redraw of (open or closed) door graphics */
5732 SetDoorState(DOOR_OPEN_ALL);
5733 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5737 FadeSetEnterScreen();
5738 // FadeSkipNextFadeOut();
5739 // FadeSetDisabled();
5744 fading = fading_none;
5747 print_init_timestamp("DONE ReloadCustomArtwork");
5750 void KeyboardAutoRepeatOffUnlessAutoplay()
5752 if (global.autoplay_leveldir == NULL)
5753 KeyboardAutoRepeatOff();
5757 /* ========================================================================= */
5759 /* ========================================================================= */
5763 print_init_timestamp("INIT OpenAll");
5765 InitGlobal(); /* initialize some global variables */
5767 if (options.execute_command)
5768 Execute_Command(options.execute_command);
5770 if (options.serveronly)
5772 #if defined(PLATFORM_UNIX)
5773 NetworkServer(options.server_port, options.serveronly);
5775 Error(ERR_WARN, "networking only supported in Unix version");
5778 exit(0); /* never reached, server loops forever */
5785 InitArtworkInfo(); /* needed before loading gfx, sound & music */
5786 InitArtworkConfig(); /* needed before forking sound child process */
5791 InitRND(NEW_RANDOMIZE);
5792 InitSimpleRandom(NEW_RANDOMIZE);
5796 print_init_timestamp("TIME [pre-video]");
5799 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
5801 InitEventFilter(FilterMouseMotionEvents);
5803 InitElementPropertiesStatic();
5804 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5806 print_init_timestamp("TIME [post-video]");
5810 print_init_timestamp("TIME InitGfx");
5813 print_init_timestamp("TIME InitLevelInfo");
5815 InitLevelArtworkInfo();
5816 print_init_timestamp("TIME InitLevelArtworkInfo");
5818 InitImages(); /* needs to know current level directory */
5819 print_init_timestamp("TIME InitImages");
5821 InitSound(NULL); /* needs to know current level directory */
5822 print_init_timestamp("TIME InitSound");
5824 InitMusic(NULL); /* needs to know current level directory */
5825 print_init_timestamp("TIME InitMusic");
5827 InitGfxBackground();
5833 if (global.autoplay_leveldir)
5838 else if (global.convert_leveldir)
5844 game_status = GAME_MODE_MAIN;
5847 FadeSetEnterScreen();
5848 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
5849 FadeSkipNextFadeOut();
5850 // FadeSetDisabled();
5852 fading = fading_none;
5855 print_init_timestamp("TIME [post-artwork]");
5857 print_init_timestamp("DONE OpenAll");
5861 InitNetworkServer();
5864 void CloseAllAndExit(int exit_value)
5869 CloseAudio(); /* called after freeing sounds (needed for SDL) */
5877 #if defined(TARGET_SDL)
5878 if (network_server) /* terminate network server */
5879 SDL_KillThread(server_thread);
5882 CloseVideoDisplay();
5883 ClosePlatformDependentStuff();
5885 if (exit_value != 0)
5886 NotifyUserAboutErrorFile();