1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2002 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 */
37 #define CONFIG_TOKEN_FONT_INITIAL "font.initial"
40 static struct FontBitmapInfo font_initial[NUM_INITIAL_FONTS];
42 static int copy_properties[][5] =
46 EL_BUG_LEFT, EL_BUG_RIGHT,
47 EL_BUG_UP, EL_BUG_DOWN
51 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
52 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
56 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
57 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
61 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
62 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
66 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
67 EL_PACMAN_UP, EL_PACMAN_DOWN
71 EL_MOLE_LEFT, EL_MOLE_RIGHT,
72 EL_MOLE_UP, EL_MOLE_DOWN
80 static void InitTileClipmasks()
83 #if defined(TARGET_X11)
84 XGCValues clip_gc_values;
85 unsigned long clip_gc_valuemask;
87 #if defined(TARGET_X11_NATIVE)
97 tile_needs_clipping[] =
99 { GFX_SPIELER1_UP, 4 },
100 { GFX_SPIELER1_DOWN, 4 },
101 { GFX_SPIELER1_LEFT, 4 },
102 { GFX_SPIELER1_RIGHT, 4 },
103 { GFX_SPIELER1_PUSH_LEFT, 4 },
104 { GFX_SPIELER1_PUSH_RIGHT, 4 },
105 { GFX_SPIELER2_UP, 4 },
106 { GFX_SPIELER2_DOWN, 4 },
107 { GFX_SPIELER2_LEFT, 4 },
108 { GFX_SPIELER2_RIGHT, 4 },
109 { GFX_SPIELER2_PUSH_LEFT, 4 },
110 { GFX_SPIELER2_PUSH_RIGHT, 4 },
111 { GFX_SPIELER3_UP, 4 },
112 { GFX_SPIELER3_DOWN, 4 },
113 { GFX_SPIELER3_LEFT, 4 },
114 { GFX_SPIELER3_RIGHT, 4 },
115 { GFX_SPIELER3_PUSH_LEFT, 4 },
116 { GFX_SPIELER3_PUSH_RIGHT, 4 },
117 { GFX_SPIELER4_UP, 4 },
118 { GFX_SPIELER4_DOWN, 4 },
119 { GFX_SPIELER4_LEFT, 4 },
120 { GFX_SPIELER4_RIGHT, 4 },
121 { GFX_SPIELER4_PUSH_LEFT, 4 },
122 { GFX_SPIELER4_PUSH_RIGHT, 4 },
123 { GFX_SP_MURPHY, 1 },
124 { GFX_MURPHY_GO_LEFT, 3 },
125 { GFX_MURPHY_GO_RIGHT, 3 },
126 { GFX_MURPHY_SNAP_UP, 1 },
127 { GFX_MURPHY_SNAP_DOWN, 1 },
128 { GFX_MURPHY_SNAP_RIGHT, 1 },
129 { GFX_MURPHY_SNAP_LEFT, 1 },
130 { GFX_MURPHY_PUSH_RIGHT, 1 },
131 { GFX_MURPHY_PUSH_LEFT, 1 },
132 { GFX_GEBLUBBER, 4 },
135 { GFX_EXPLOSION, 8 },
136 { GFX_SOKOBAN_OBJEKT, 1 },
137 { GFX_FUNKELN_BLAU, 3 },
138 { GFX_FUNKELN_WEISS, 3 },
139 { GFX2_SHIELD_PASSIVE, 3 },
140 { GFX2_SHIELD_ACTIVE, 3 },
145 #endif /* TARGET_X11_NATIVE */
146 #endif /* TARGET_X11 */
150 /* initialize pixmap array for special X11 tile clipping to Pixmap 'None' */
151 for (i = 0; i < NUM_TILES; i++)
152 tile_clipmask[i] = None;
154 #if defined(TARGET_X11)
155 /* This stuff is needed because X11 (XSetClipOrigin(), to be precise) is
156 often very slow when preparing a masked XCopyArea() for big Pixmaps.
157 To prevent this, create small (tile-sized) mask Pixmaps which will then
158 be set much faster with XSetClipOrigin() and speed things up a lot. */
160 clip_gc_values.graphics_exposures = False;
161 clip_gc_valuemask = GCGraphicsExposures;
162 tile_clip_gc = XCreateGC(display, window->drawable,
163 clip_gc_valuemask, &clip_gc_values);
166 for (i = 0; i < NUM_BITMAPS; i++)
168 if (pix[i]->clip_mask)
170 clip_gc_values.graphics_exposures = False;
171 clip_gc_values.clip_mask = pix[i]->clip_mask;
172 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
173 pix[i]->stored_clip_gc = XCreateGC(display, window->drawable,
174 clip_gc_valuemask, &clip_gc_values);
179 #if defined(TARGET_X11_NATIVE)
182 /* create graphic context structures needed for clipping */
183 clip_gc_values.graphics_exposures = False;
184 clip_gc_valuemask = GCGraphicsExposures;
185 copy_clipmask_gc = XCreateGC(display, pix[PIX_BACK]->clip_mask,
186 clip_gc_valuemask, &clip_gc_values);
188 /* create only those clipping Pixmaps we really need */
189 for (i = 0; tile_needs_clipping[i].start >= 0; i++)
193 for (j = 0; j < tile_needs_clipping[i].count; j++)
195 int tile = tile_needs_clipping[i].start + j;
201 getGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
202 src_pixmap = src_bitmap->clip_mask;
204 tile_clipmask[tile] = XCreatePixmap(display, window->drawable,
207 XCopyArea(display, src_pixmap, tile_clipmask[tile], copy_clipmask_gc,
208 src_x, src_y, TILEX, TILEY, 0, 0);
212 XFreeGC(display, copy_clipmask_gc);
215 #endif /* TARGET_X11_NATIVE */
216 #endif /* TARGET_X11 */
220 void FreeTileClipmasks()
223 #if defined(TARGET_X11)
226 for (i = 0; i < NUM_TILES; i++)
228 if (tile_clipmask[i] != None)
230 XFreePixmap(display, tile_clipmask[i]);
231 tile_clipmask[i] = None;
236 XFreeGC(display, tile_clip_gc);
240 for (i = 0; i < NUM_BITMAPS; i++)
242 if (pix[i] != NULL && pix[i]->stored_clip_gc)
244 XFreeGC(display, pix[i]->stored_clip_gc);
245 pix[i]->stored_clip_gc = None;
250 #endif /* TARGET_X11 */
256 FreeLevelEditorGadgets();
265 static boolean gadgets_initialized = FALSE;
267 if (gadgets_initialized)
270 CreateLevelEditorGadgets();
274 CreateScreenGadgets();
276 gadgets_initialized = TRUE;
279 inline void InitElementSmallImagesScaledUp(int graphic)
281 CreateImageWithSmallImages(graphic, graphic_info[graphic].scale_up_factor);
284 void InitElementSmallImages()
286 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
287 int num_property_mappings = getImageListPropertyMappingSize();
290 /* initialize normal images from static configuration */
291 for (i = 0; element_to_graphic[i].element > -1; i++)
292 InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
294 /* initialize special images from static configuration */
295 for (i = 0; element_to_special_graphic[i].element > -1; i++)
296 InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
298 /* initialize images from dynamic configuration (may be elements or other) */
300 for (i = 0; i < num_property_mappings; i++)
301 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
303 /* !!! THIS DOES NOT WORK -- "artwork_index" is graphic, not element !!! */
304 /* !!! ALSO, non-element graphics might need scaling-up !!! */
305 for (i = 0; i < num_property_mappings; i++)
306 if (property_mapping[i].artwork_index < MAX_NUM_ELEMENTS)
307 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
311 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
312 for (i = IMG_EMC_OBJECT; i <= IMG_EMC_SPRITE; i++)
313 InitElementSmallImagesScaledUp(i);
318 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
319 void SetBitmaps_EM(Bitmap **em_bitmap)
321 em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
322 em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].bitmap;
326 static int getFontBitmapID(int font_nr)
330 if (game_status >= GAME_MODE_MAIN && game_status <= GAME_MODE_PSEUDO_PREVIEW)
331 special = game_status;
332 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
333 special = GFX_SPECIAL_ARG_MAIN;
334 else if (game_status == GAME_MODE_PLAYING)
335 special = GFX_SPECIAL_ARG_DOOR;
338 return font_info[font_nr].special_bitmap_id[special];
343 void InitFontGraphicInfo()
345 static struct FontBitmapInfo *font_bitmap_info = NULL;
346 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
347 int num_property_mappings = getImageListPropertyMappingSize();
348 int num_font_bitmaps = NUM_FONTS;
351 if (graphic_info == NULL) /* still at startup phase */
353 InitFontInfo(font_initial, NUM_INITIAL_FONTS, getFontBitmapID);
358 /* ---------- initialize font graphic definitions ---------- */
360 /* always start with reliable default values (normal font graphics) */
362 for (i = 0; i < NUM_FONTS; i++)
363 font_info[i].graphic = IMG_FONT_INITIAL_1;
365 for (i = 0; i < NUM_FONTS; i++)
366 font_info[i].graphic = FONT_INITIAL_1;
369 /* initialize normal font/graphic mapping from static configuration */
370 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
372 int font_nr = font_to_graphic[i].font_nr;
373 int special = font_to_graphic[i].special;
374 int graphic = font_to_graphic[i].graphic;
379 font_info[font_nr].graphic = graphic;
382 /* always start with reliable default values (special font graphics) */
383 for (i = 0; i < NUM_FONTS; i++)
385 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
387 font_info[i].special_graphic[j] = font_info[i].graphic;
388 font_info[i].special_bitmap_id[j] = i;
392 /* initialize special font/graphic mapping from static configuration */
393 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
395 int font_nr = font_to_graphic[i].font_nr;
396 int special = font_to_graphic[i].special;
397 int graphic = font_to_graphic[i].graphic;
399 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
401 font_info[font_nr].special_graphic[special] = graphic;
402 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
407 /* initialize special element/graphic mapping from dynamic configuration */
408 for (i = 0; i < num_property_mappings; i++)
410 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
411 int special = property_mapping[i].ext3_index;
412 int graphic = property_mapping[i].artwork_index;
417 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
419 font_info[font_nr].special_graphic[special] = graphic;
420 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
425 /* ---------- initialize font bitmap array ---------- */
427 if (font_bitmap_info != NULL)
428 FreeFontInfo(font_bitmap_info);
431 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
433 /* ---------- initialize font bitmap definitions ---------- */
435 for (i = 0; i < NUM_FONTS; i++)
437 if (i < NUM_INITIAL_FONTS)
439 font_bitmap_info[i] = font_initial[i];
443 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
445 int font_bitmap_id = font_info[i].special_bitmap_id[j];
446 int graphic = font_info[i].special_graphic[j];
448 /* set 'graphic_info' for font entries, if uninitialized (guessed) */
449 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
451 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
452 graphic_info[graphic].anim_frames_per_line= DEFAULT_NUM_CHARS_PER_LINE;
455 /* copy font relevant information from graphics information */
456 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
457 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
458 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
459 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
460 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
461 font_bitmap_info[font_bitmap_id].draw_x = graphic_info[graphic].draw_x;
462 font_bitmap_info[font_bitmap_id].draw_y = graphic_info[graphic].draw_y;
464 font_bitmap_info[font_bitmap_id].num_chars =
465 graphic_info[graphic].anim_frames;
466 font_bitmap_info[font_bitmap_id].num_chars_per_line =
467 graphic_info[graphic].anim_frames_per_line;
471 InitFontInfo(font_bitmap_info, num_font_bitmaps, getFontBitmapID);
474 void InitElementGraphicInfo()
476 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
477 int num_property_mappings = getImageListPropertyMappingSize();
480 if (graphic_info == NULL) /* still at startup phase */
483 /* set values to -1 to identify later as "uninitialized" values */
484 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
486 for (act = 0; act < NUM_ACTIONS; act++)
488 element_info[i].graphic[act] = -1;
489 element_info[i].crumbled[act] = -1;
491 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
493 element_info[i].direction_graphic[act][dir] = -1;
494 element_info[i].direction_crumbled[act][dir] = -1;
499 /* initialize normal element/graphic mapping from static configuration */
500 for (i = 0; element_to_graphic[i].element > -1; i++)
502 int element = element_to_graphic[i].element;
503 int action = element_to_graphic[i].action;
504 int direction = element_to_graphic[i].direction;
505 boolean crumbled = element_to_graphic[i].crumbled;
506 int graphic = element_to_graphic[i].graphic;
507 int base_graphic = el2baseimg(element);
509 if (graphic_info[graphic].bitmap == NULL)
512 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
515 boolean base_redefined =
516 getImageListEntryFromImageID(base_graphic)->redefined;
517 boolean act_dir_redefined =
518 getImageListEntryFromImageID(graphic)->redefined;
520 /* if the base graphic ("emerald", for example) has been redefined,
521 but not the action graphic ("emerald.falling", for example), do not
522 use an existing (in this case considered obsolete) action graphic
523 anymore, but use the automatically determined default graphic */
524 if (base_redefined && !act_dir_redefined)
529 action = ACTION_DEFAULT;
534 element_info[element].direction_crumbled[action][direction] = graphic;
536 element_info[element].crumbled[action] = graphic;
541 element_info[element].direction_graphic[action][direction] = graphic;
543 element_info[element].graphic[action] = graphic;
547 /* initialize normal element/graphic mapping from dynamic configuration */
548 for (i = 0; i < num_property_mappings; i++)
550 int element = property_mapping[i].base_index;
551 int action = property_mapping[i].ext1_index;
552 int direction = property_mapping[i].ext2_index;
553 int special = property_mapping[i].ext3_index;
554 int graphic = property_mapping[i].artwork_index;
555 boolean crumbled = FALSE;
557 if (special == GFX_SPECIAL_ARG_CRUMBLED)
563 if (graphic_info[graphic].bitmap == NULL)
566 if (element >= MAX_NUM_ELEMENTS || special != -1)
570 action = ACTION_DEFAULT;
575 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
576 element_info[element].direction_crumbled[action][dir] = -1;
579 element_info[element].direction_crumbled[action][direction] = graphic;
581 element_info[element].crumbled[action] = graphic;
586 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
587 element_info[element].direction_graphic[action][dir] = -1;
590 element_info[element].direction_graphic[action][direction] = graphic;
592 element_info[element].graphic[action] = graphic;
596 /* now copy all graphics that are defined to be cloned from other graphics */
597 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
599 int graphic = element_info[i].graphic[ACTION_DEFAULT];
600 int crumbled_like, diggable_like;
605 crumbled_like = graphic_info[graphic].crumbled_like;
606 diggable_like = graphic_info[graphic].diggable_like;
608 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
610 for (act = 0; act < NUM_ACTIONS; act++)
611 element_info[i].crumbled[act] =
612 element_info[crumbled_like].crumbled[act];
613 for (act = 0; act < NUM_ACTIONS; act++)
614 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
615 element_info[i].direction_crumbled[act][dir] =
616 element_info[crumbled_like].direction_crumbled[act][dir];
619 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
621 element_info[i].graphic[ACTION_DIGGING] =
622 element_info[diggable_like].graphic[ACTION_DIGGING];
623 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
624 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
625 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
630 /* set hardcoded definitions for some runtime elements without graphic */
631 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
635 /* now set all undefined/invalid graphics to -1 to set to default after it */
636 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
638 for (act = 0; act < NUM_ACTIONS; act++)
642 graphic = element_info[i].graphic[act];
643 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
644 element_info[i].graphic[act] = -1;
646 graphic = element_info[i].crumbled[act];
647 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
648 element_info[i].crumbled[act] = -1;
650 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
652 graphic = element_info[i].direction_graphic[act][dir];
653 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
654 element_info[i].direction_graphic[act][dir] = -1;
656 graphic = element_info[i].direction_crumbled[act][dir];
657 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
658 element_info[i].direction_crumbled[act][dir] = -1;
665 /* adjust graphics with 2nd tile for movement according to direction
666 (do this before correcting '-1' values to minimize calculations) */
667 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
669 for (act = 0; act < NUM_ACTIONS; act++)
671 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
673 int graphic = element_info[i].direction_graphic[act][dir];
674 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
676 if (act == ACTION_FALLING) /* special case */
677 graphic = element_info[i].graphic[act];
680 graphic_info[graphic].double_movement &&
681 graphic_info[graphic].swap_double_tiles != 0)
683 struct GraphicInfo *g = &graphic_info[graphic];
684 int src_x_front = g->src_x;
685 int src_y_front = g->src_y;
686 int src_x_back = g->src_x + g->offset2_x;
687 int src_y_back = g->src_y + g->offset2_y;
688 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
690 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
691 src_y_front < src_y_back);
693 boolean second_tile_is_back =
694 ((move_dir == MV_BIT_LEFT && front_is_left_or_upper) ||
695 (move_dir == MV_BIT_UP && front_is_left_or_upper));
696 boolean second_tile_is_front =
697 ((move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
698 (move_dir == MV_BIT_DOWN && front_is_left_or_upper));
699 boolean second_tile_should_be_front =
700 (g->second_tile_is_start == 0);
701 boolean second_tile_should_be_back =
702 (g->second_tile_is_start == 1);
704 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
705 boolean swap_movement_tiles_autodetected =
706 (!frames_are_ordered_diagonally &&
707 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
708 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
709 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
710 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
714 printf("::: CHECKING element %d ('%s'), '%s', dir %d [(%d -> %d, %d), %d => %d]\n",
715 i, element_info[i].token_name,
716 element_action_info[act].suffix, move_dir,
717 g->swap_double_tiles,
718 swap_movement_tiles_never,
719 swap_movement_tiles_always,
720 swap_movement_tiles_autodetected,
721 swap_movement_tiles);
724 /* swap frontside and backside graphic tile coordinates, if needed */
725 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
727 /* get current (wrong) backside tile coordinates */
728 getGraphicSourceExt(graphic, 0, &dummy, &src_x_back, &src_y_back,
731 /* set frontside tile coordinates to backside tile coordinates */
732 g->src_x = src_x_back;
733 g->src_y = src_y_back;
735 /* invert tile offset to point to new backside tile coordinates */
739 /* do not swap front and backside tiles again after correction */
740 g->swap_double_tiles = 0;
743 printf(" CORRECTED\n");
752 /* now set all '-1' values to element specific default values */
753 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
755 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
756 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
757 int default_direction_graphic[NUM_DIRECTIONS];
758 int default_direction_crumbled[NUM_DIRECTIONS];
760 if (default_graphic == -1)
761 default_graphic = IMG_UNKNOWN;
763 if (default_crumbled == -1)
764 default_crumbled = default_graphic;
766 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
767 if (default_crumbled == -1)
768 default_crumbled = IMG_EMPTY;
771 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
773 default_direction_graphic[dir] =
774 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
775 default_direction_crumbled[dir] =
776 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
778 if (default_direction_graphic[dir] == -1)
779 default_direction_graphic[dir] = default_graphic;
781 if (default_direction_crumbled[dir] == -1)
782 default_direction_crumbled[dir] = default_direction_graphic[dir];
784 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
785 if (default_direction_crumbled[dir] == -1)
786 default_direction_crumbled[dir] = default_crumbled;
790 for (act = 0; act < NUM_ACTIONS; act++)
792 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
793 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
794 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
795 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
796 act == ACTION_TURNING_FROM_RIGHT ||
797 act == ACTION_TURNING_FROM_UP ||
798 act == ACTION_TURNING_FROM_DOWN);
800 /* generic default action graphic (defined by "[default]" directive) */
801 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
802 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
803 int default_remove_graphic = IMG_EMPTY;
805 if (act_remove && default_action_graphic != -1)
806 default_remove_graphic = default_action_graphic;
808 /* look for special default action graphic (classic game specific) */
809 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
810 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
811 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
812 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
813 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
814 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
816 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
817 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
818 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
819 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
820 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
821 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
824 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
825 /* !!! make this better !!! */
826 if (i == EL_EMPTY_SPACE)
828 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
829 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
833 if (default_action_graphic == -1)
834 default_action_graphic = default_graphic;
836 if (default_action_crumbled == -1)
837 default_action_crumbled = default_action_graphic;
839 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
840 if (default_action_crumbled == -1)
841 default_action_crumbled = default_crumbled;
844 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
846 /* use action graphic as the default direction graphic, if undefined */
847 int default_action_direction_graphic = element_info[i].graphic[act];
848 int default_action_direction_crumbled = element_info[i].crumbled[act];
850 /* no graphic for current action -- use default direction graphic */
851 if (default_action_direction_graphic == -1)
852 default_action_direction_graphic =
853 (act_remove ? default_remove_graphic :
855 element_info[i].direction_graphic[ACTION_TURNING][dir] :
856 default_action_graphic != default_graphic ?
857 default_action_graphic :
858 default_direction_graphic[dir]);
860 if (element_info[i].direction_graphic[act][dir] == -1)
861 element_info[i].direction_graphic[act][dir] =
862 default_action_direction_graphic;
865 if (default_action_direction_crumbled == -1)
866 default_action_direction_crumbled =
867 element_info[i].direction_graphic[act][dir];
869 if (default_action_direction_crumbled == -1)
870 default_action_direction_crumbled =
871 (act_remove ? default_remove_graphic :
873 element_info[i].direction_crumbled[ACTION_TURNING][dir] :
874 default_action_crumbled != default_crumbled ?
875 default_action_crumbled :
876 default_direction_crumbled[dir]);
879 if (element_info[i].direction_crumbled[act][dir] == -1)
880 element_info[i].direction_crumbled[act][dir] =
881 default_action_direction_crumbled;
884 if (i == EL_EMC_GRASS &&
885 act == ACTION_DIGGING &&
887 printf("::: direction_crumbled == %d, %d, %d\n",
888 element_info[i].direction_crumbled[act][dir],
889 default_action_direction_crumbled,
890 element_info[i].crumbled[act]);
894 /* no graphic for this specific action -- use default action graphic */
895 if (element_info[i].graphic[act] == -1)
896 element_info[i].graphic[act] =
897 (act_remove ? default_remove_graphic :
898 act_turning ? element_info[i].graphic[ACTION_TURNING] :
899 default_action_graphic);
901 if (element_info[i].crumbled[act] == -1)
902 element_info[i].crumbled[act] = element_info[i].graphic[act];
904 if (element_info[i].crumbled[act] == -1)
905 element_info[i].crumbled[act] =
906 (act_remove ? default_remove_graphic :
907 act_turning ? element_info[i].crumbled[ACTION_TURNING] :
908 default_action_crumbled);
914 /* set animation mode to "none" for each graphic with only 1 frame */
915 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
917 for (act = 0; act < NUM_ACTIONS; act++)
919 int graphic = element_info[i].graphic[act];
920 int crumbled = element_info[i].crumbled[act];
922 if (graphic_info[graphic].anim_frames == 1)
923 graphic_info[graphic].anim_mode = ANIM_NONE;
924 if (graphic_info[crumbled].anim_frames == 1)
925 graphic_info[crumbled].anim_mode = ANIM_NONE;
927 for (dir = 0; dir < NUM_DIRECTIONS; dir++)
929 graphic = element_info[i].direction_graphic[act][dir];
930 crumbled = element_info[i].direction_crumbled[act][dir];
932 if (graphic_info[graphic].anim_frames == 1)
933 graphic_info[graphic].anim_mode = ANIM_NONE;
934 if (graphic_info[crumbled].anim_frames == 1)
935 graphic_info[crumbled].anim_mode = ANIM_NONE;
945 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
946 if (element_info[i].graphic[ACTION_DEFAULT] == IMG_UNKNOWN &&
948 Error(ERR_RETURN, "warning: no graphic for element '%s' (%d)",
949 element_info[i].token_name, i);
955 void InitElementSpecialGraphicInfo()
957 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
958 int num_property_mappings = getImageListPropertyMappingSize();
961 /* always start with reliable default values */
962 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
963 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
964 element_info[i].special_graphic[j] =
965 element_info[i].graphic[ACTION_DEFAULT];
967 /* initialize special element/graphic mapping from static configuration */
968 for (i = 0; element_to_special_graphic[i].element > -1; i++)
970 int element = element_to_special_graphic[i].element;
971 int special = element_to_special_graphic[i].special;
972 int graphic = element_to_special_graphic[i].graphic;
973 int base_graphic = el2baseimg(element);
974 boolean base_redefined =
975 getImageListEntryFromImageID(base_graphic)->redefined;
976 boolean special_redefined =
977 getImageListEntryFromImageID(graphic)->redefined;
979 /* if the base graphic ("emerald", for example) has been redefined,
980 but not the special graphic ("emerald.EDITOR", for example), do not
981 use an existing (in this case considered obsolete) special graphic
982 anymore, but use the automatically created (down-scaled) graphic */
983 if (base_redefined && !special_redefined)
986 element_info[element].special_graphic[special] = graphic;
989 /* initialize special element/graphic mapping from dynamic configuration */
990 for (i = 0; i < num_property_mappings; i++)
992 int element = property_mapping[i].base_index;
993 int special = property_mapping[i].ext3_index;
994 int graphic = property_mapping[i].artwork_index;
996 if (element >= MAX_NUM_ELEMENTS)
999 if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
1000 element_info[element].special_graphic[special] = graphic;
1004 /* now set all undefined/invalid graphics to default */
1005 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1006 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1007 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
1008 element_info[i].special_graphic[j] =
1009 element_info[i].graphic[ACTION_DEFAULT];
1013 static int get_element_from_token(char *token)
1017 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1018 if (strcmp(element_info[i].token_name, token) == 0)
1024 static int get_scaled_graphic_width(int graphic)
1026 int original_width = getOriginalImageWidthFromImageID(graphic);
1027 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1029 return original_width * scale_up_factor;
1032 static int get_scaled_graphic_height(int graphic)
1034 int original_height = getOriginalImageHeightFromImageID(graphic);
1035 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1037 return original_height * scale_up_factor;
1040 static void set_graphic_parameters(int graphic, int graphic_copy_from)
1042 struct FileInfo *image = getImageListEntryFromImageID(graphic_copy_from);
1043 char **parameter_raw = image->parameter;
1044 Bitmap *src_bitmap = getBitmapFromImageID(graphic_copy_from);
1045 int parameter[NUM_GFX_ARGS];
1046 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1047 int anim_frames_per_line = 1;
1053 /* !!! NEW ARTWORK FALLBACK CODE !!! NEARLY UNTESTED !!! */
1054 /* if fallback to default artwork is done, also use the default parameters */
1055 if (image->fallback_to_default)
1058 printf("::: FALLBACK for %d\n", graphic_copy_from);
1061 parameter_raw = image->default_parameter;
1066 /* !!! ARTWORK FALLBACK CODE !!! NEARLY UNTESTED !!! */
1067 /* (better try to set a "fallback -> use default parameters" flag) */
1070 int len_source_filename = strlen(src_bitmap->source_filename);
1071 int len_default_filename = strlen(image->default_filename);
1072 int pos_basename = len_source_filename - len_default_filename;
1073 char *source_basename = &src_bitmap->source_filename[pos_basename];
1076 printf("::: src_bitmap->source_filename -> '%s'\n",
1077 src_bitmap->source_filename);
1078 printf("::: image->default_filename -> '%s'\n",
1079 image->default_filename);
1080 printf("::: image->filename -> '%s'\n",
1084 /* check if there was a fallback to the default artwork file */
1085 if (strcmp(image->filename, image->default_filename) != 0 &&
1086 pos_basename >= 0 &&
1087 strcmp(source_basename, image->default_filename) == 0)
1088 parameter_raw = image->default_parameter;
1093 /* get integer values from string parameters */
1094 for (i = 0; i < NUM_GFX_ARGS; i++)
1097 get_parameter_value(image_config_suffix[i].token, parameter_raw[i],
1098 image_config_suffix[i].type);
1100 if (image_config_suffix[i].type == TYPE_TOKEN)
1101 parameter[i] = get_element_from_token(parameter_raw[i]);
1104 graphic_info[graphic].bitmap = src_bitmap;
1106 /* start with reliable default values */
1107 graphic_info[graphic].src_x = 0;
1108 graphic_info[graphic].src_y = 0;
1109 graphic_info[graphic].width = TILEX;
1110 graphic_info[graphic].height = TILEY;
1111 graphic_info[graphic].offset_x = 0; /* one or both of these values ... */
1112 graphic_info[graphic].offset_y = 0; /* ... will be corrected later */
1113 graphic_info[graphic].offset2_x = 0; /* one or both of these values ... */
1114 graphic_info[graphic].offset2_y = 0; /* ... will be corrected later */
1115 graphic_info[graphic].swap_double_tiles = -1; /* auto-detect tile swapping */
1116 graphic_info[graphic].crumbled_like = -1; /* do not use clone element */
1117 graphic_info[graphic].diggable_like = -1; /* do not use clone element */
1118 graphic_info[graphic].border_size = TILEX / 8; /* "CRUMBLED" border size */
1119 graphic_info[graphic].scale_up_factor = 1; /* default: no scaling up */
1120 graphic_info[graphic].anim_delay_fixed = 0;
1121 graphic_info[graphic].anim_delay_random = 0;
1122 graphic_info[graphic].post_delay_fixed = 0;
1123 graphic_info[graphic].post_delay_random = 0;
1125 /* optional x and y tile position of animation frame sequence */
1126 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1127 graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
1128 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1129 graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
1131 /* optional x and y pixel position of animation frame sequence */
1132 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1133 graphic_info[graphic].src_x = parameter[GFX_ARG_X];
1134 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1135 graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
1137 /* optional width and height of each animation frame */
1138 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1139 graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
1140 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1141 graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
1143 /* optional zoom factor for scaling up the image to a larger size */
1144 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1145 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1146 if (graphic_info[graphic].scale_up_factor < 1)
1147 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
1151 /* get final bitmap size (with scaling, but without small images) */
1152 int src_bitmap_width = get_scaled_graphic_width(graphic);
1153 int src_bitmap_height = get_scaled_graphic_height(graphic);
1155 anim_frames_per_row = src_bitmap_width / graphic_info[graphic].width;
1156 anim_frames_per_col = src_bitmap_height / graphic_info[graphic].height;
1159 /* correct x or y offset dependent of vertical or horizontal frame order */
1160 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1162 graphic_info[graphic].offset_y =
1163 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1164 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
1165 anim_frames_per_line = anim_frames_per_col;
1167 else /* frames are ordered horizontally */
1169 graphic_info[graphic].offset_x =
1170 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1171 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
1172 anim_frames_per_line = anim_frames_per_row;
1175 /* optionally, the x and y offset of frames can be specified directly */
1176 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1177 graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
1178 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1179 graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
1181 /* optionally, moving animations may have separate start and end graphics */
1182 graphic_info[graphic].double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1184 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1185 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1187 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1188 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1189 graphic_info[graphic].offset2_y =
1190 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1191 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].height);
1192 else /* frames are ordered horizontally */
1193 graphic_info[graphic].offset2_x =
1194 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1195 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].width);
1197 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1198 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1199 graphic_info[graphic].offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1200 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1201 graphic_info[graphic].offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1203 /* optionally, the second movement tile can be specified as start tile */
1204 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1205 graphic_info[graphic].swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1207 /* automatically determine correct number of frames, if not defined */
1208 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1209 graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
1210 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1211 graphic_info[graphic].anim_frames = anim_frames_per_row;
1212 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1213 graphic_info[graphic].anim_frames = anim_frames_per_col;
1215 graphic_info[graphic].anim_frames = 1;
1217 graphic_info[graphic].anim_frames_per_line =
1218 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1219 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1221 graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
1222 if (graphic_info[graphic].anim_delay == 0) /* delay must be at least 1 */
1223 graphic_info[graphic].anim_delay = 1;
1225 graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
1227 if (graphic_info[graphic].anim_frames == 1)
1228 graphic_info[graphic].anim_mode = ANIM_NONE;
1231 /* automatically determine correct start frame, if not defined */
1232 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1233 graphic_info[graphic].anim_start_frame = 0;
1234 else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
1235 graphic_info[graphic].anim_start_frame =
1236 graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1238 graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
1240 /* animation synchronized with global frame counter, not move position */
1241 graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1243 /* optional element for cloning crumble graphics */
1244 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1245 graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1247 /* optional element for cloning digging graphics */
1248 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1249 graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1251 /* optional border size for "crumbling" diggable graphics */
1252 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1253 graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
1255 /* this is only used for player "boring" and "sleeping" actions */
1256 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1257 graphic_info[graphic].anim_delay_fixed =
1258 parameter[GFX_ARG_ANIM_DELAY_FIXED];
1259 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1260 graphic_info[graphic].anim_delay_random =
1261 parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1262 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1263 graphic_info[graphic].post_delay_fixed =
1264 parameter[GFX_ARG_POST_DELAY_FIXED];
1265 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1266 graphic_info[graphic].post_delay_random =
1267 parameter[GFX_ARG_POST_DELAY_RANDOM];
1269 /* this is only used for toon animations */
1270 graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
1271 graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY];
1273 /* this is only used for drawing font characters */
1274 graphic_info[graphic].draw_x = parameter[GFX_ARG_DRAW_XOFFSET];
1275 graphic_info[graphic].draw_y = parameter[GFX_ARG_DRAW_YOFFSET];
1277 /* this is only used for drawing envelope graphics */
1278 graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1281 static void InitGraphicInfo()
1283 int fallback_graphic = IMG_CHAR_EXCLAM;
1284 int num_images = getImageListSize();
1287 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1288 static boolean clipmasks_initialized = FALSE;
1290 XGCValues clip_gc_values;
1291 unsigned long clip_gc_valuemask;
1292 GC copy_clipmask_gc = None;
1295 checked_free(graphic_info);
1297 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1300 printf("::: graphic_info: %d entries\n", num_images);
1303 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1304 if (clipmasks_initialized)
1306 for (i = 0; i < num_images; i++)
1308 if (graphic_info[i].clip_mask)
1309 XFreePixmap(display, graphic_info[i].clip_mask);
1310 if (graphic_info[i].clip_gc)
1311 XFreeGC(display, graphic_info[i].clip_gc);
1313 graphic_info[i].clip_mask = None;
1314 graphic_info[i].clip_gc = None;
1319 for (i = 0; i < num_images; i++)
1323 int first_frame, last_frame;
1324 int src_bitmap_width, src_bitmap_height;
1327 printf("::: image: '%s' [%d]\n", image->token, i);
1331 printf("::: image # %d: '%s' ['%s']\n",
1333 getTokenFromImageID(i));
1336 set_graphic_parameters(i, i);
1338 /* now check if no animation frames are outside of the loaded image */
1340 if (graphic_info[i].bitmap == NULL)
1341 continue; /* skip check for optional images that are undefined */
1343 /* get final bitmap size (with scaling, but without small images) */
1344 src_bitmap_width = get_scaled_graphic_width(i);
1345 src_bitmap_height = get_scaled_graphic_height(i);
1348 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1349 if (src_x < 0 || src_y < 0 ||
1350 src_x + TILEX > src_bitmap_width ||
1351 src_y + TILEY > src_bitmap_height)
1353 Error(ERR_RETURN_LINE, "-");
1354 Error(ERR_RETURN, "warning: error found in config file:");
1355 Error(ERR_RETURN, "- config file: '%s'",
1356 getImageConfigFilename());
1357 Error(ERR_RETURN, "- config token: '%s'",
1358 getTokenFromImageID(i));
1359 Error(ERR_RETURN, "- image file: '%s'",
1360 src_bitmap->source_filename);
1362 "error: first animation frame out of bounds (%d, %d)",
1364 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1367 Error(ERR_RETURN, "scale_up_factor == %d", scale_up_factor);
1370 if (i == fallback_graphic)
1371 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1373 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1374 Error(ERR_RETURN_LINE, "-");
1376 set_graphic_parameters(i, fallback_graphic);
1379 last_frame = graphic_info[i].anim_frames - 1;
1380 getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1381 if (src_x < 0 || src_y < 0 ||
1382 src_x + TILEX > src_bitmap_width ||
1383 src_y + TILEY > src_bitmap_height)
1385 Error(ERR_RETURN_LINE, "-");
1386 Error(ERR_RETURN, "warning: error found in config file:");
1387 Error(ERR_RETURN, "- config file: '%s'",
1388 getImageConfigFilename());
1389 Error(ERR_RETURN, "- config token: '%s'",
1390 getTokenFromImageID(i));
1391 Error(ERR_RETURN, "- image file: '%s'",
1392 src_bitmap->source_filename);
1394 "error: last animation frame (%d) out of bounds (%d, %d)",
1395 last_frame, src_x, src_y);
1396 Error(ERR_RETURN, "custom graphic rejected for this element/action");
1398 if (i == fallback_graphic)
1399 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1401 Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1402 Error(ERR_RETURN_LINE, "-");
1404 set_graphic_parameters(i, fallback_graphic);
1407 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1408 /* currently we only need a tile clip mask from the first frame */
1409 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1411 if (copy_clipmask_gc == None)
1413 clip_gc_values.graphics_exposures = False;
1414 clip_gc_valuemask = GCGraphicsExposures;
1415 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
1416 clip_gc_valuemask, &clip_gc_values);
1419 graphic_info[i].clip_mask =
1420 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
1422 src_pixmap = src_bitmap->clip_mask;
1423 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
1424 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
1426 clip_gc_values.graphics_exposures = False;
1427 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
1428 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
1430 graphic_info[i].clip_gc =
1431 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
1435 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1436 if (copy_clipmask_gc)
1437 XFreeGC(display, copy_clipmask_gc);
1439 clipmasks_initialized = TRUE;
1443 static void InitElementSoundInfo()
1445 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1446 int num_property_mappings = getSoundListPropertyMappingSize();
1449 /* set values to -1 to identify later as "uninitialized" values */
1450 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1451 for (act = 0; act < NUM_ACTIONS; act++)
1452 element_info[i].sound[act] = -1;
1454 /* initialize element/sound mapping from static configuration */
1455 for (i = 0; element_to_sound[i].element > -1; i++)
1457 int element = element_to_sound[i].element;
1458 int action = element_to_sound[i].action;
1459 int sound = element_to_sound[i].sound;
1460 boolean is_class = element_to_sound[i].is_class;
1463 action = ACTION_DEFAULT;
1466 element_info[element].sound[action] = sound;
1468 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1469 if (strcmp(element_info[j].class_name,
1470 element_info[element].class_name) == 0)
1471 element_info[j].sound[action] = sound;
1474 /* initialize element class/sound mapping from dynamic configuration */
1475 for (i = 0; i < num_property_mappings; i++)
1477 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1478 int action = property_mapping[i].ext1_index;
1479 int sound = property_mapping[i].artwork_index;
1481 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1485 action = ACTION_DEFAULT;
1487 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1488 if (strcmp(element_info[j].class_name,
1489 element_info[element_class].class_name) == 0)
1490 element_info[j].sound[action] = sound;
1493 /* initialize element/sound mapping from dynamic configuration */
1494 for (i = 0; i < num_property_mappings; i++)
1496 int element = property_mapping[i].base_index;
1497 int action = property_mapping[i].ext1_index;
1498 int sound = property_mapping[i].artwork_index;
1500 if (element >= MAX_NUM_ELEMENTS)
1504 action = ACTION_DEFAULT;
1506 element_info[element].sound[action] = sound;
1509 /* now set all '-1' values to element specific default values */
1510 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1512 for (act = 0; act < NUM_ACTIONS; act++)
1514 /* generic default action sound (defined by "[default]" directive) */
1515 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1517 /* look for special default action sound (classic game specific) */
1518 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1519 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1520 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1521 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1522 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1523 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1525 /* !!! there's no such thing as a "default action sound" !!! */
1527 /* look for element specific default sound (independent from action) */
1528 if (element_info[i].sound[ACTION_DEFAULT] != -1)
1529 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
1533 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1534 /* !!! make this better !!! */
1535 if (i == EL_EMPTY_SPACE)
1536 default_action_sound = element_info[EL_DEFAULT].sound[act];
1539 /* no sound for this specific action -- use default action sound */
1540 if (element_info[i].sound[act] == -1)
1541 element_info[i].sound[act] = default_action_sound;
1546 /* copy sound settings to some elements that are only stored in level file
1547 in native R'n'D levels, but are used by game engine in native EM levels */
1548 for (i = 0; copy_properties[i][0] != -1; i++)
1549 for (j = 1; j <= 4; j++)
1550 for (act = 0; act < NUM_ACTIONS; act++)
1551 element_info[copy_properties[i][j]].sound[act] =
1552 element_info[copy_properties[i][0]].sound[act];
1556 static void InitGameModeSoundInfo()
1560 /* set values to -1 to identify later as "uninitialized" values */
1561 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1564 /* initialize gamemode/sound mapping from static configuration */
1565 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1567 int gamemode = gamemode_to_sound[i].gamemode;
1568 int sound = gamemode_to_sound[i].sound;
1571 gamemode = GAME_MODE_DEFAULT;
1573 menu.sound[gamemode] = sound;
1576 /* now set all '-1' values to levelset specific default values */
1577 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1578 if (menu.sound[i] == -1)
1579 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1583 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1584 if (menu.sound[i] != -1)
1585 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
1589 static void set_sound_parameters(int sound, char **parameter_raw)
1591 int parameter[NUM_SND_ARGS];
1594 /* get integer values from string parameters */
1595 for (i = 0; i < NUM_SND_ARGS; i++)
1597 get_parameter_value(sound_config_suffix[i].token, parameter_raw[i],
1598 sound_config_suffix[i].type);
1600 /* explicit loop mode setting in configuration overrides default value */
1601 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1602 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1604 /* sound volume to change the original volume when loading the sound file */
1605 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1607 /* sound priority to give certain sounds a higher or lower priority */
1608 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1611 static void InitSoundInfo()
1614 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1615 int num_property_mappings = getSoundListPropertyMappingSize();
1617 int *sound_effect_properties;
1618 int num_sounds = getSoundListSize();
1621 checked_free(sound_info);
1623 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1624 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1626 /* initialize sound effect for all elements to "no sound" */
1627 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1628 for (j = 0; j < NUM_ACTIONS; j++)
1629 element_info[i].sound[j] = SND_UNDEFINED;
1631 for (i = 0; i < num_sounds; i++)
1633 struct FileInfo *sound = getSoundListEntry(i);
1634 int len_effect_text = strlen(sound->token);
1636 sound_effect_properties[i] = ACTION_OTHER;
1637 sound_info[i].loop = FALSE; /* default: play sound only once */
1640 printf("::: sound %d: '%s'\n", i, sound->token);
1643 /* determine all loop sounds and identify certain sound classes */
1645 for (j = 0; element_action_info[j].suffix; j++)
1647 int len_action_text = strlen(element_action_info[j].suffix);
1649 if (len_action_text < len_effect_text &&
1650 strcmp(&sound->token[len_effect_text - len_action_text],
1651 element_action_info[j].suffix) == 0)
1653 sound_effect_properties[i] = element_action_info[j].value;
1654 sound_info[i].loop = element_action_info[j].is_loop_sound;
1661 if (strcmp(sound->token, "custom_42") == 0)
1662 printf("::: '%s' -> %d\n", sound->token, sound_info[i].loop);
1665 /* associate elements and some selected sound actions */
1667 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1669 if (element_info[j].class_name)
1671 int len_class_text = strlen(element_info[j].class_name);
1673 if (len_class_text + 1 < len_effect_text &&
1674 strncmp(sound->token,
1675 element_info[j].class_name, len_class_text) == 0 &&
1676 sound->token[len_class_text] == '.')
1678 int sound_action_value = sound_effect_properties[i];
1680 element_info[j].sound[sound_action_value] = i;
1685 set_sound_parameters(i, sound->parameter);
1688 free(sound_effect_properties);
1691 /* !!! MOVED TO "InitElementSoundInfo()" !!! */
1692 /* !!! everything defined here gets overwritten there !!! */
1694 /* copy sound settings to some elements that are only stored in level file
1695 in native R'n'D levels, but are used by game engine in native EM levels */
1696 for (i = 0; i < NUM_ACTIONS; i++)
1697 for (j = 0; copy_properties[j][0] != -1; j++)
1698 for (k = 1; k <= 4; k++)
1699 element_info[copy_properties[j][k]].sound[i] =
1700 element_info[copy_properties[j][0]].sound[i];
1702 printf("::: bug -> %d\n", element_info[EL_BUG].sound[ACTION_MOVING]);
1703 printf("::: bug_r -> %d\n", element_info[EL_BUG_RIGHT].sound[ACTION_MOVING]);
1707 /* !!! now handled in InitElementSoundInfo() !!! */
1708 /* initialize element/sound mapping from dynamic configuration */
1709 for (i = 0; i < num_property_mappings; i++)
1711 int element = property_mapping[i].base_index;
1712 int action = property_mapping[i].ext1_index;
1713 int sound = property_mapping[i].artwork_index;
1716 action = ACTION_DEFAULT;
1718 printf("::: %d: %d, %d, %d ['%s']\n",
1719 i, element, action, sound, element_info[element].token_name);
1721 element_info[element].sound[action] = sound;
1728 int element = EL_CUSTOM_11;
1731 while (element_action_info[j].suffix)
1733 printf("element %d, sound action '%s' == %d\n",
1734 element, element_action_info[j].suffix,
1735 element_info[element].sound[j]);
1740 PlaySoundLevelElementAction(0,0, EL_CUSTOM_11, ACTION_PUSHING);
1746 int element = EL_SAND;
1747 int sound_action = ACTION_DIGGING;
1750 while (element_action_info[j].suffix)
1752 if (element_action_info[j].value == sound_action)
1753 printf("element %d, sound action '%s' == %d\n",
1754 element, element_action_info[j].suffix,
1755 element_info[element].sound[sound_action]);
1762 static void InitGameModeMusicInfo()
1764 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1765 int num_property_mappings = getMusicListPropertyMappingSize();
1766 int default_levelset_music = -1;
1769 /* set values to -1 to identify later as "uninitialized" values */
1770 for (i = 0; i < MAX_LEVELS; i++)
1771 levelset.music[i] = -1;
1772 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1775 /* initialize gamemode/music mapping from static configuration */
1776 for (i = 0; gamemode_to_music[i].music > -1; i++)
1778 int gamemode = gamemode_to_music[i].gamemode;
1779 int music = gamemode_to_music[i].music;
1782 printf("::: gamemode == %d, music == %d\n", gamemode, music);
1786 gamemode = GAME_MODE_DEFAULT;
1788 menu.music[gamemode] = music;
1791 /* initialize gamemode/music mapping from dynamic configuration */
1792 for (i = 0; i < num_property_mappings; i++)
1794 int prefix = property_mapping[i].base_index;
1795 int gamemode = property_mapping[i].ext1_index;
1796 int level = property_mapping[i].ext2_index;
1797 int music = property_mapping[i].artwork_index;
1800 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
1801 prefix, gamemode, level, music);
1804 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1808 gamemode = GAME_MODE_DEFAULT;
1810 /* level specific music only allowed for in-game music */
1811 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1812 gamemode = GAME_MODE_PLAYING;
1817 default_levelset_music = music;
1820 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1821 levelset.music[level] = music;
1822 if (gamemode != GAME_MODE_PLAYING)
1823 menu.music[gamemode] = music;
1826 /* now set all '-1' values to menu specific default values */
1827 /* (undefined values of "levelset.music[]" might stay at "-1" to
1828 allow dynamic selection of music files from music directory!) */
1829 for (i = 0; i < MAX_LEVELS; i++)
1830 if (levelset.music[i] == -1)
1831 levelset.music[i] = default_levelset_music;
1832 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1833 if (menu.music[i] == -1)
1834 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1838 for (i = 0; i < MAX_LEVELS; i++)
1839 if (levelset.music[i] != -1)
1840 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
1841 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1842 if (menu.music[i] != -1)
1843 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
1847 static void set_music_parameters(int music, char **parameter_raw)
1849 int parameter[NUM_MUS_ARGS];
1852 /* get integer values from string parameters */
1853 for (i = 0; i < NUM_MUS_ARGS; i++)
1855 get_parameter_value(music_config_suffix[i].token, parameter_raw[i],
1856 music_config_suffix[i].type);
1858 /* explicit loop mode setting in configuration overrides default value */
1859 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1860 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1863 static void InitMusicInfo()
1865 int num_music = getMusicListSize();
1868 checked_free(music_info);
1870 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1872 for (i = 0; i < num_music; i++)
1874 struct FileInfo *music = getMusicListEntry(i);
1875 int len_music_text = strlen(music->token);
1877 music_info[i].loop = TRUE; /* default: play music in loop mode */
1879 /* determine all loop music */
1881 for (j = 0; music_prefix_info[j].prefix; j++)
1883 int len_prefix_text = strlen(music_prefix_info[j].prefix);
1885 if (len_prefix_text < len_music_text &&
1886 strncmp(music->token,
1887 music_prefix_info[j].prefix, len_prefix_text) == 0)
1889 music_info[i].loop = music_prefix_info[j].is_loop_music;
1895 set_music_parameters(i, music->parameter);
1899 static void ReinitializeGraphics()
1901 InitGraphicInfo(); /* graphic properties mapping */
1902 InitElementGraphicInfo(); /* element game graphic mapping */
1903 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
1905 InitElementSmallImages(); /* scale images to all needed sizes */
1906 InitFontGraphicInfo(); /* initialize text drawing functions */
1908 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
1910 SetMainBackgroundImage(IMG_BACKGROUND);
1911 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1917 static void ReinitializeSounds()
1919 InitSoundInfo(); /* sound properties mapping */
1920 InitElementSoundInfo(); /* element game sound mapping */
1921 InitGameModeSoundInfo(); /* game mode sound mapping */
1923 InitPlayLevelSound(); /* internal game sound settings */
1926 static void ReinitializeMusic()
1928 InitMusicInfo(); /* music properties mapping */
1929 InitGameModeMusicInfo(); /* game mode music mapping */
1932 static int get_special_property_bit(int element, int property_bit_nr)
1934 struct PropertyBitInfo
1940 static struct PropertyBitInfo pb_can_move_into_acid[] =
1942 /* the player may be able fall into acid when gravity is activated */
1947 { EL_SP_MURPHY, 0 },
1948 { EL_SOKOBAN_FIELD_PLAYER, 0 },
1950 /* all element that can move may be able to also move into acid */
1953 { EL_BUG_RIGHT, 1 },
1956 { EL_SPACESHIP, 2 },
1957 { EL_SPACESHIP_LEFT, 2 },
1958 { EL_SPACESHIP_RIGHT, 2 },
1959 { EL_SPACESHIP_UP, 2 },
1960 { EL_SPACESHIP_DOWN, 2 },
1961 { EL_BD_BUTTERFLY, 3 },
1962 { EL_BD_BUTTERFLY_LEFT, 3 },
1963 { EL_BD_BUTTERFLY_RIGHT, 3 },
1964 { EL_BD_BUTTERFLY_UP, 3 },
1965 { EL_BD_BUTTERFLY_DOWN, 3 },
1966 { EL_BD_FIREFLY, 4 },
1967 { EL_BD_FIREFLY_LEFT, 4 },
1968 { EL_BD_FIREFLY_RIGHT, 4 },
1969 { EL_BD_FIREFLY_UP, 4 },
1970 { EL_BD_FIREFLY_DOWN, 4 },
1972 { EL_DARK_YAMYAM, 6 },
1975 { EL_PACMAN_LEFT, 8 },
1976 { EL_PACMAN_RIGHT, 8 },
1977 { EL_PACMAN_UP, 8 },
1978 { EL_PACMAN_DOWN, 8 },
1980 { EL_MOLE_LEFT, 9 },
1981 { EL_MOLE_RIGHT, 9 },
1983 { EL_MOLE_DOWN, 9 },
1987 { EL_SATELLITE, 13 },
1988 { EL_SP_SNIKSNAK, 14 },
1989 { EL_SP_ELECTRON, 15 },
1996 static struct PropertyBitInfo pb_dont_collide_with[] =
1998 { EL_SP_SNIKSNAK, 0 },
1999 { EL_SP_ELECTRON, 1 },
2007 struct PropertyBitInfo *pb_info;
2010 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2011 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2016 struct PropertyBitInfo *pb_info = NULL;
2019 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2020 if (pb_definition[i].bit_nr == property_bit_nr)
2021 pb_info = pb_definition[i].pb_info;
2023 if (pb_info == NULL)
2026 for (i = 0; pb_info[i].element != -1; i++)
2027 if (pb_info[i].element == element)
2028 return pb_info[i].bit_nr;
2034 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2035 boolean property_value)
2037 int bit_nr = get_special_property_bit(element, property_bit_nr);
2042 *bitfield |= (1 << bit_nr);
2044 *bitfield &= ~(1 << bit_nr);
2048 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2050 int bit_nr = get_special_property_bit(element, property_bit_nr);
2053 return ((*bitfield & (1 << bit_nr)) != 0);
2060 void setMoveIntoAcidProperty(struct LevelInfo *level, int element, boolean set)
2062 int bit_nr = get_special_property_bit(element, EP_CAN_MOVE_INTO_ACID);
2066 level->can_move_into_acid_bits &= ~(1 << bit_nr);
2069 level->can_move_into_acid_bits |= (1 << bit_nr);
2073 boolean getMoveIntoAcidProperty(struct LevelInfo *level, int element)
2075 int bit_nr = get_special_property_bit(element, EP_CAN_MOVE_INTO_ACID);
2078 return ((level->can_move_into_acid_bits & (1 << bit_nr)) != 0);
2084 void InitElementPropertiesStatic()
2086 static int ep_diggable[] =
2091 EL_SP_BUGGY_BASE_ACTIVATING,
2094 EL_INVISIBLE_SAND_ACTIVE,
2097 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2098 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2102 EL_SP_BUGGY_BASE_ACTIVE,
2108 static int ep_collectible_only[] =
2129 EL_DYNABOMB_INCREASE_NUMBER,
2130 EL_DYNABOMB_INCREASE_SIZE,
2131 EL_DYNABOMB_INCREASE_POWER,
2150 static int ep_dont_run_into[] =
2152 /* same elements as in 'ep_dont_touch' */
2158 /* same elements as in 'ep_dont_collide_with' */
2170 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2174 EL_SP_BUGGY_BASE_ACTIVE,
2180 static int ep_dont_collide_with[] =
2182 /* same elements as in 'ep_dont_touch' */
2198 static int ep_dont_touch[] =
2207 static int ep_indestructible[] =
2211 EL_ACID_POOL_TOPLEFT,
2212 EL_ACID_POOL_TOPRIGHT,
2213 EL_ACID_POOL_BOTTOMLEFT,
2214 EL_ACID_POOL_BOTTOM,
2215 EL_ACID_POOL_BOTTOMRIGHT,
2216 EL_SP_HARDWARE_GRAY,
2217 EL_SP_HARDWARE_GREEN,
2218 EL_SP_HARDWARE_BLUE,
2220 EL_SP_HARDWARE_YELLOW,
2221 EL_SP_HARDWARE_BASE_1,
2222 EL_SP_HARDWARE_BASE_2,
2223 EL_SP_HARDWARE_BASE_3,
2224 EL_SP_HARDWARE_BASE_4,
2225 EL_SP_HARDWARE_BASE_5,
2226 EL_SP_HARDWARE_BASE_6,
2227 EL_INVISIBLE_STEELWALL,
2228 EL_INVISIBLE_STEELWALL_ACTIVE,
2229 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2230 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2231 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2232 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2233 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2234 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2235 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2236 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2237 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2238 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2239 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2240 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2242 EL_LIGHT_SWITCH_ACTIVE,
2243 EL_SIGN_EXCLAMATION,
2244 EL_SIGN_RADIOACTIVITY,
2255 EL_STEELWALL_SLIPPERY,
2286 EL_SWITCHGATE_OPENING,
2287 EL_SWITCHGATE_CLOSED,
2288 EL_SWITCHGATE_CLOSING,
2290 EL_SWITCHGATE_SWITCH_UP,
2291 EL_SWITCHGATE_SWITCH_DOWN,
2294 EL_TIMEGATE_OPENING,
2296 EL_TIMEGATE_CLOSING,
2299 EL_TIMEGATE_SWITCH_ACTIVE,
2304 EL_TUBE_VERTICAL_LEFT,
2305 EL_TUBE_VERTICAL_RIGHT,
2306 EL_TUBE_HORIZONTAL_UP,
2307 EL_TUBE_HORIZONTAL_DOWN,
2315 static int ep_slippery[] =
2329 EL_ROBOT_WHEEL_ACTIVE,
2335 EL_ACID_POOL_TOPLEFT,
2336 EL_ACID_POOL_TOPRIGHT,
2346 EL_STEELWALL_SLIPPERY,
2349 EL_EMC_WALL_SLIPPERY_1,
2350 EL_EMC_WALL_SLIPPERY_2,
2351 EL_EMC_WALL_SLIPPERY_3,
2352 EL_EMC_WALL_SLIPPERY_4,
2356 static int ep_can_change[] =
2361 static int ep_can_move[] =
2363 /* same elements as in 'pb_can_move_into_acid' */
2385 static int ep_can_fall[] =
2400 EL_BD_MAGIC_WALL_FULL,
2413 static int ep_can_smash_player[] =
2438 static int ep_can_smash_enemies[] =
2446 static int ep_can_smash_everything[] =
2454 static int ep_explodes_by_fire[] =
2456 /* same elements as in 'ep_explodes_impact' */
2461 /* same elements as in 'ep_explodes_smashed' */
2470 EL_DYNABOMB_PLAYER_1_ACTIVE,
2471 EL_DYNABOMB_PLAYER_2_ACTIVE,
2472 EL_DYNABOMB_PLAYER_3_ACTIVE,
2473 EL_DYNABOMB_PLAYER_4_ACTIVE,
2474 EL_DYNABOMB_INCREASE_NUMBER,
2475 EL_DYNABOMB_INCREASE_SIZE,
2476 EL_DYNABOMB_INCREASE_POWER,
2477 EL_SP_DISK_RED_ACTIVE,
2490 static int ep_explodes_smashed[] =
2492 /* same elements as in 'ep_explodes_impact' */
2505 static int ep_explodes_impact[] =
2513 static int ep_walkable_over[] =
2517 EL_SOKOBAN_FIELD_EMPTY,
2535 static int ep_walkable_inside[] =
2540 EL_TUBE_VERTICAL_LEFT,
2541 EL_TUBE_VERTICAL_RIGHT,
2542 EL_TUBE_HORIZONTAL_UP,
2543 EL_TUBE_HORIZONTAL_DOWN,
2551 static int ep_walkable_under[] =
2556 static int ep_passable_over[] =
2579 static int ep_passable_inside[] =
2585 EL_SP_PORT_HORIZONTAL,
2586 EL_SP_PORT_VERTICAL,
2588 EL_SP_GRAVITY_PORT_LEFT,
2589 EL_SP_GRAVITY_PORT_RIGHT,
2590 EL_SP_GRAVITY_PORT_UP,
2591 EL_SP_GRAVITY_PORT_DOWN,
2592 EL_SP_GRAVITY_ON_PORT_LEFT,
2593 EL_SP_GRAVITY_ON_PORT_RIGHT,
2594 EL_SP_GRAVITY_ON_PORT_UP,
2595 EL_SP_GRAVITY_ON_PORT_DOWN,
2596 EL_SP_GRAVITY_OFF_PORT_LEFT,
2597 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2598 EL_SP_GRAVITY_OFF_PORT_UP,
2599 EL_SP_GRAVITY_OFF_PORT_DOWN,
2603 static int ep_passable_under[] =
2608 static int ep_droppable[] =
2613 static int ep_explodes_1x1_old[] =
2618 static int ep_pushable[] =
2630 EL_SOKOBAN_FIELD_FULL,
2638 static int ep_explodes_cross_old[] =
2643 static int ep_protected[] =
2645 /* same elements as in 'ep_walkable_inside' */
2649 EL_TUBE_VERTICAL_LEFT,
2650 EL_TUBE_VERTICAL_RIGHT,
2651 EL_TUBE_HORIZONTAL_UP,
2652 EL_TUBE_HORIZONTAL_DOWN,
2658 /* same elements as in 'ep_passable_over' */
2678 /* same elements as in 'ep_passable_inside' */
2683 EL_SP_PORT_HORIZONTAL,
2684 EL_SP_PORT_VERTICAL,
2686 EL_SP_GRAVITY_PORT_LEFT,
2687 EL_SP_GRAVITY_PORT_RIGHT,
2688 EL_SP_GRAVITY_PORT_UP,
2689 EL_SP_GRAVITY_PORT_DOWN,
2690 EL_SP_GRAVITY_ON_PORT_LEFT,
2691 EL_SP_GRAVITY_ON_PORT_RIGHT,
2692 EL_SP_GRAVITY_ON_PORT_UP,
2693 EL_SP_GRAVITY_ON_PORT_DOWN,
2694 EL_SP_GRAVITY_OFF_PORT_LEFT,
2695 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2696 EL_SP_GRAVITY_OFF_PORT_UP,
2697 EL_SP_GRAVITY_OFF_PORT_DOWN,
2701 static int ep_throwable[] =
2706 static int ep_can_explode[] =
2708 /* same elements as in 'ep_explodes_impact' */
2713 /* same elements as in 'ep_explodes_smashed' */
2719 /* elements that can explode by explosion or by dragonfire */
2722 EL_DYNABOMB_PLAYER_1_ACTIVE,
2723 EL_DYNABOMB_PLAYER_2_ACTIVE,
2724 EL_DYNABOMB_PLAYER_3_ACTIVE,
2725 EL_DYNABOMB_PLAYER_4_ACTIVE,
2726 EL_DYNABOMB_INCREASE_NUMBER,
2727 EL_DYNABOMB_INCREASE_SIZE,
2728 EL_DYNABOMB_INCREASE_POWER,
2729 EL_SP_DISK_RED_ACTIVE,
2737 /* elements that can explode only by explosion */
2742 static int ep_gravity_reachable[] =
2748 EL_INVISIBLE_SAND_ACTIVE,
2753 EL_SP_PORT_HORIZONTAL,
2754 EL_SP_PORT_VERTICAL,
2756 EL_SP_GRAVITY_PORT_LEFT,
2757 EL_SP_GRAVITY_PORT_RIGHT,
2758 EL_SP_GRAVITY_PORT_UP,
2759 EL_SP_GRAVITY_PORT_DOWN,
2760 EL_SP_GRAVITY_ON_PORT_LEFT,
2761 EL_SP_GRAVITY_ON_PORT_RIGHT,
2762 EL_SP_GRAVITY_ON_PORT_UP,
2763 EL_SP_GRAVITY_ON_PORT_DOWN,
2764 EL_SP_GRAVITY_OFF_PORT_LEFT,
2765 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2766 EL_SP_GRAVITY_OFF_PORT_UP,
2767 EL_SP_GRAVITY_OFF_PORT_DOWN,
2772 static int ep_player[] =
2779 EL_SOKOBAN_FIELD_PLAYER,
2784 static int ep_can_pass_magic_wall[] =
2797 static int ep_switchable[] =
2801 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2802 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2803 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2804 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2805 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2806 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2807 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2808 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2809 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2810 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2811 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2812 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2813 EL_SWITCHGATE_SWITCH_UP,
2814 EL_SWITCHGATE_SWITCH_DOWN,
2816 EL_LIGHT_SWITCH_ACTIVE,
2818 EL_BALLOON_SWITCH_LEFT,
2819 EL_BALLOON_SWITCH_RIGHT,
2820 EL_BALLOON_SWITCH_UP,
2821 EL_BALLOON_SWITCH_DOWN,
2822 EL_BALLOON_SWITCH_ANY,
2825 EL_EMC_MAGIC_BALL_SWITCH,
2829 static int ep_bd_element[] =
2862 static int ep_sp_element[] =
2864 /* should always be valid */
2867 /* standard classic Supaplex elements */
2874 EL_SP_HARDWARE_GRAY,
2882 EL_SP_GRAVITY_PORT_RIGHT,
2883 EL_SP_GRAVITY_PORT_DOWN,
2884 EL_SP_GRAVITY_PORT_LEFT,
2885 EL_SP_GRAVITY_PORT_UP,
2890 EL_SP_PORT_VERTICAL,
2891 EL_SP_PORT_HORIZONTAL,
2897 EL_SP_HARDWARE_BASE_1,
2898 EL_SP_HARDWARE_GREEN,
2899 EL_SP_HARDWARE_BLUE,
2901 EL_SP_HARDWARE_YELLOW,
2902 EL_SP_HARDWARE_BASE_2,
2903 EL_SP_HARDWARE_BASE_3,
2904 EL_SP_HARDWARE_BASE_4,
2905 EL_SP_HARDWARE_BASE_5,
2906 EL_SP_HARDWARE_BASE_6,
2910 /* additional elements that appeared in newer Supaplex levels */
2913 /* additional gravity port elements (not switching, but setting gravity) */
2914 EL_SP_GRAVITY_ON_PORT_LEFT,
2915 EL_SP_GRAVITY_ON_PORT_RIGHT,
2916 EL_SP_GRAVITY_ON_PORT_UP,
2917 EL_SP_GRAVITY_ON_PORT_DOWN,
2918 EL_SP_GRAVITY_OFF_PORT_LEFT,
2919 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2920 EL_SP_GRAVITY_OFF_PORT_UP,
2921 EL_SP_GRAVITY_OFF_PORT_DOWN,
2923 /* more than one Murphy in a level results in an inactive clone */
2926 /* runtime Supaplex elements */
2927 EL_SP_DISK_RED_ACTIVE,
2928 EL_SP_TERMINAL_ACTIVE,
2929 EL_SP_BUGGY_BASE_ACTIVATING,
2930 EL_SP_BUGGY_BASE_ACTIVE,
2936 static int ep_sb_element[] =
2941 EL_SOKOBAN_FIELD_EMPTY,
2942 EL_SOKOBAN_FIELD_FULL,
2943 EL_SOKOBAN_FIELD_PLAYER,
2948 EL_INVISIBLE_STEELWALL,
2952 static int ep_gem[] =
2963 static int ep_food_dark_yamyam[] =
2990 static int ep_food_penguin[] =
3003 static int ep_food_pig[] =
3014 static int ep_historic_wall[] =
3039 EL_EXPANDABLE_WALL_HORIZONTAL,
3040 EL_EXPANDABLE_WALL_VERTICAL,
3041 EL_EXPANDABLE_WALL_ANY,
3042 EL_EXPANDABLE_WALL_GROWING,
3049 EL_SP_HARDWARE_GRAY,
3050 EL_SP_HARDWARE_GREEN,
3051 EL_SP_HARDWARE_BLUE,
3053 EL_SP_HARDWARE_YELLOW,
3054 EL_SP_HARDWARE_BASE_1,
3055 EL_SP_HARDWARE_BASE_2,
3056 EL_SP_HARDWARE_BASE_3,
3057 EL_SP_HARDWARE_BASE_4,
3058 EL_SP_HARDWARE_BASE_5,
3059 EL_SP_HARDWARE_BASE_6,
3061 EL_SP_TERMINAL_ACTIVE,
3064 EL_INVISIBLE_STEELWALL,
3065 EL_INVISIBLE_STEELWALL_ACTIVE,
3067 EL_INVISIBLE_WALL_ACTIVE,
3068 EL_STEELWALL_SLIPPERY,
3084 static int ep_historic_solid[] =
3088 EL_EXPANDABLE_WALL_HORIZONTAL,
3089 EL_EXPANDABLE_WALL_VERTICAL,
3090 EL_EXPANDABLE_WALL_ANY,
3103 EL_QUICKSAND_FILLING,
3104 EL_QUICKSAND_EMPTYING,
3106 EL_MAGIC_WALL_ACTIVE,
3107 EL_MAGIC_WALL_EMPTYING,
3108 EL_MAGIC_WALL_FILLING,
3112 EL_BD_MAGIC_WALL_ACTIVE,
3113 EL_BD_MAGIC_WALL_EMPTYING,
3114 EL_BD_MAGIC_WALL_FULL,
3115 EL_BD_MAGIC_WALL_FILLING,
3116 EL_BD_MAGIC_WALL_DEAD,
3125 EL_SP_TERMINAL_ACTIVE,
3129 EL_INVISIBLE_WALL_ACTIVE,
3130 EL_SWITCHGATE_SWITCH_UP,
3131 EL_SWITCHGATE_SWITCH_DOWN,
3133 EL_TIMEGATE_SWITCH_ACTIVE,
3145 /* the following elements are a direct copy of "indestructible" elements,
3146 except "EL_ACID", which is "indestructible", but not "solid"! */
3151 EL_ACID_POOL_TOPLEFT,
3152 EL_ACID_POOL_TOPRIGHT,
3153 EL_ACID_POOL_BOTTOMLEFT,
3154 EL_ACID_POOL_BOTTOM,
3155 EL_ACID_POOL_BOTTOMRIGHT,
3156 EL_SP_HARDWARE_GRAY,
3157 EL_SP_HARDWARE_GREEN,
3158 EL_SP_HARDWARE_BLUE,
3160 EL_SP_HARDWARE_YELLOW,
3161 EL_SP_HARDWARE_BASE_1,
3162 EL_SP_HARDWARE_BASE_2,
3163 EL_SP_HARDWARE_BASE_3,
3164 EL_SP_HARDWARE_BASE_4,
3165 EL_SP_HARDWARE_BASE_5,
3166 EL_SP_HARDWARE_BASE_6,
3167 EL_INVISIBLE_STEELWALL,
3168 EL_INVISIBLE_STEELWALL_ACTIVE,
3169 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3170 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3171 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3172 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3173 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3174 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3175 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3176 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3177 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3178 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3179 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3180 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3182 EL_LIGHT_SWITCH_ACTIVE,
3183 EL_SIGN_EXCLAMATION,
3184 EL_SIGN_RADIOACTIVITY,
3195 EL_STEELWALL_SLIPPERY,
3218 EL_SWITCHGATE_OPENING,
3219 EL_SWITCHGATE_CLOSED,
3220 EL_SWITCHGATE_CLOSING,
3222 EL_TIMEGATE_OPENING,
3224 EL_TIMEGATE_CLOSING,
3228 EL_TUBE_VERTICAL_LEFT,
3229 EL_TUBE_VERTICAL_RIGHT,
3230 EL_TUBE_HORIZONTAL_UP,
3231 EL_TUBE_HORIZONTAL_DOWN,
3239 static int ep_classic_enemy[] =
3255 static int ep_belt[] =
3257 EL_CONVEYOR_BELT_1_LEFT,
3258 EL_CONVEYOR_BELT_1_MIDDLE,
3259 EL_CONVEYOR_BELT_1_RIGHT,
3260 EL_CONVEYOR_BELT_2_LEFT,
3261 EL_CONVEYOR_BELT_2_MIDDLE,
3262 EL_CONVEYOR_BELT_2_RIGHT,
3263 EL_CONVEYOR_BELT_3_LEFT,
3264 EL_CONVEYOR_BELT_3_MIDDLE,
3265 EL_CONVEYOR_BELT_3_RIGHT,
3266 EL_CONVEYOR_BELT_4_LEFT,
3267 EL_CONVEYOR_BELT_4_MIDDLE,
3268 EL_CONVEYOR_BELT_4_RIGHT,
3272 static int ep_belt_active[] =
3274 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3275 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3276 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3277 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3278 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3279 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3280 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3281 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3282 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3283 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3284 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3285 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3289 static int ep_belt_switch[] =
3291 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3292 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3293 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3294 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3295 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3296 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3297 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3298 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3299 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3300 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3301 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3302 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3306 static int ep_tube[] =
3313 EL_TUBE_HORIZONTAL_UP,
3314 EL_TUBE_HORIZONTAL_DOWN,
3316 EL_TUBE_VERTICAL_LEFT,
3317 EL_TUBE_VERTICAL_RIGHT,
3322 static int ep_keygate[] =
3351 static int ep_amoeboid[] =
3361 static int ep_amoebalive[] =
3370 static int ep_has_content[] =
3380 static int ep_can_turn_each_move[] =
3382 /* !!! do something with this one !!! */
3386 static int ep_can_grow[] =
3398 static int ep_active_bomb[] =
3401 EL_DYNABOMB_PLAYER_1_ACTIVE,
3402 EL_DYNABOMB_PLAYER_2_ACTIVE,
3403 EL_DYNABOMB_PLAYER_3_ACTIVE,
3404 EL_DYNABOMB_PLAYER_4_ACTIVE,
3405 EL_SP_DISK_RED_ACTIVE,
3409 static int ep_inactive[] =
3458 EL_INVISIBLE_STEELWALL,
3466 EL_WALL_EMERALD_YELLOW,
3467 EL_DYNABOMB_INCREASE_NUMBER,
3468 EL_DYNABOMB_INCREASE_SIZE,
3469 EL_DYNABOMB_INCREASE_POWER,
3473 EL_SOKOBAN_FIELD_EMPTY,
3474 EL_SOKOBAN_FIELD_FULL,
3475 EL_WALL_EMERALD_RED,
3476 EL_WALL_EMERALD_PURPLE,
3477 EL_ACID_POOL_TOPLEFT,
3478 EL_ACID_POOL_TOPRIGHT,
3479 EL_ACID_POOL_BOTTOMLEFT,
3480 EL_ACID_POOL_BOTTOM,
3481 EL_ACID_POOL_BOTTOMRIGHT,
3485 EL_BD_MAGIC_WALL_DEAD,
3486 EL_AMOEBA_TO_DIAMOND,
3494 EL_SP_GRAVITY_PORT_RIGHT,
3495 EL_SP_GRAVITY_PORT_DOWN,
3496 EL_SP_GRAVITY_PORT_LEFT,
3497 EL_SP_GRAVITY_PORT_UP,
3498 EL_SP_PORT_HORIZONTAL,
3499 EL_SP_PORT_VERTICAL,
3510 EL_SP_HARDWARE_GRAY,
3511 EL_SP_HARDWARE_GREEN,
3512 EL_SP_HARDWARE_BLUE,
3514 EL_SP_HARDWARE_YELLOW,
3515 EL_SP_HARDWARE_BASE_1,
3516 EL_SP_HARDWARE_BASE_2,
3517 EL_SP_HARDWARE_BASE_3,
3518 EL_SP_HARDWARE_BASE_4,
3519 EL_SP_HARDWARE_BASE_5,
3520 EL_SP_HARDWARE_BASE_6,
3521 EL_SP_GRAVITY_ON_PORT_LEFT,
3522 EL_SP_GRAVITY_ON_PORT_RIGHT,
3523 EL_SP_GRAVITY_ON_PORT_UP,
3524 EL_SP_GRAVITY_ON_PORT_DOWN,
3525 EL_SP_GRAVITY_OFF_PORT_LEFT,
3526 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3527 EL_SP_GRAVITY_OFF_PORT_UP,
3528 EL_SP_GRAVITY_OFF_PORT_DOWN,
3529 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3530 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3531 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3532 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3533 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3534 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3535 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3536 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3537 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3538 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3539 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3540 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3541 EL_SIGN_EXCLAMATION,
3542 EL_SIGN_RADIOACTIVITY,
3553 EL_STEELWALL_SLIPPERY,
3558 EL_EMC_WALL_SLIPPERY_1,
3559 EL_EMC_WALL_SLIPPERY_2,
3560 EL_EMC_WALL_SLIPPERY_3,
3561 EL_EMC_WALL_SLIPPERY_4,
3581 static int ep_em_slippery_wall[] =
3586 static int ep_gfx_crumbled[] =
3599 } element_properties[] =
3601 { ep_diggable, EP_DIGGABLE },
3602 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
3603 { ep_dont_run_into, EP_DONT_RUN_INTO },
3604 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
3605 { ep_dont_touch, EP_DONT_TOUCH },
3606 { ep_indestructible, EP_INDESTRUCTIBLE },
3607 { ep_slippery, EP_SLIPPERY },
3608 { ep_can_change, EP_CAN_CHANGE },
3609 { ep_can_move, EP_CAN_MOVE },
3610 { ep_can_fall, EP_CAN_FALL },
3611 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
3612 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
3613 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
3614 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
3615 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
3616 { ep_explodes_impact, EP_EXPLODES_IMPACT },
3617 { ep_walkable_over, EP_WALKABLE_OVER },
3618 { ep_walkable_inside, EP_WALKABLE_INSIDE },
3619 { ep_walkable_under, EP_WALKABLE_UNDER },
3620 { ep_passable_over, EP_PASSABLE_OVER },
3621 { ep_passable_inside, EP_PASSABLE_INSIDE },
3622 { ep_passable_under, EP_PASSABLE_UNDER },
3623 { ep_droppable, EP_DROPPABLE },
3624 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
3625 { ep_pushable, EP_PUSHABLE },
3626 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
3627 { ep_protected, EP_PROTECTED },
3628 { ep_throwable, EP_THROWABLE },
3629 { ep_can_explode, EP_CAN_EXPLODE },
3630 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
3632 { ep_player, EP_PLAYER },
3633 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
3634 { ep_switchable, EP_SWITCHABLE },
3635 { ep_bd_element, EP_BD_ELEMENT },
3636 { ep_sp_element, EP_SP_ELEMENT },
3637 { ep_sb_element, EP_SB_ELEMENT },
3639 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
3640 { ep_food_penguin, EP_FOOD_PENGUIN },
3641 { ep_food_pig, EP_FOOD_PIG },
3642 { ep_historic_wall, EP_HISTORIC_WALL },
3643 { ep_historic_solid, EP_HISTORIC_SOLID },
3644 { ep_classic_enemy, EP_CLASSIC_ENEMY },
3645 { ep_belt, EP_BELT },
3646 { ep_belt_active, EP_BELT_ACTIVE },
3647 { ep_belt_switch, EP_BELT_SWITCH },
3648 { ep_tube, EP_TUBE },
3649 { ep_keygate, EP_KEYGATE },
3650 { ep_amoeboid, EP_AMOEBOID },
3651 { ep_amoebalive, EP_AMOEBALIVE },
3652 { ep_has_content, EP_HAS_CONTENT },
3653 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
3654 { ep_can_grow, EP_CAN_GROW },
3655 { ep_active_bomb, EP_ACTIVE_BOMB },
3656 { ep_inactive, EP_INACTIVE },
3658 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
3660 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
3667 /* always start with reliable default values (element has no properties) */
3668 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3669 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
3670 SET_PROPERTY(i, j, FALSE);
3672 /* set all base element properties from above array definitions */
3673 for (i = 0; element_properties[i].elements != NULL; i++)
3674 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
3675 SET_PROPERTY((element_properties[i].elements)[j],
3676 element_properties[i].property, TRUE);
3678 /* copy properties to some elements that are only stored in level file */
3679 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
3680 for (j = 0; copy_properties[j][0] != -1; j++)
3681 if (HAS_PROPERTY(copy_properties[j][0], i))
3682 for (k = 1; k <= 4; k++)
3683 SET_PROPERTY(copy_properties[j][k], i, TRUE);
3686 void InitElementPropertiesEngine(int engine_version)
3689 static int active_properties[] =
3694 EP_DONT_COLLIDE_WITH,
3698 EP_CAN_PASS_MAGIC_WALL,
3703 EP_EXPLODES_BY_FIRE,
3716 EP_EM_SLIPPERY_WALL,
3720 static int no_wall_properties[] =
3723 EP_COLLECTIBLE_ONLY,
3725 EP_DONT_COLLIDE_WITH,
3728 EP_CAN_SMASH_PLAYER,
3729 EP_CAN_SMASH_ENEMIES,
3730 EP_CAN_SMASH_EVERYTHING,
3735 EP_FOOD_DARK_YAMYAM,
3752 InitElementPropertiesStatic();
3755 /* important: after initialization in InitElementPropertiesStatic(), the
3756 elements are not again initialized to a default value; therefore all
3757 changes have to make sure that they leave the element with a defined
3758 property (which means that conditional property changes must be set to
3759 a reliable default value before) */
3761 /* set all special, combined or engine dependent element properties */
3762 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3765 for (j = EP_ACCESSIBLE_OVER; j < NUM_ELEMENT_PROPERTIES; j++)
3766 SET_PROPERTY(i, j, FALSE);
3769 /* ---------- INACTIVE ------------------------------------------------- */
3770 SET_PROPERTY(i, EP_INACTIVE, (i >= EL_CHAR_START && i <= EL_CHAR_END));
3772 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
3773 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
3774 IS_WALKABLE_INSIDE(i) ||
3775 IS_WALKABLE_UNDER(i)));
3777 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
3778 IS_PASSABLE_INSIDE(i) ||
3779 IS_PASSABLE_UNDER(i)));
3781 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
3782 IS_PASSABLE_OVER(i)));
3784 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
3785 IS_PASSABLE_INSIDE(i)));
3787 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
3788 IS_PASSABLE_UNDER(i)));
3790 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
3793 /* ---------- COLLECTIBLE ---------------------------------------------- */
3794 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
3798 /* ---------- SNAPPABLE ------------------------------------------------ */
3799 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
3800 IS_COLLECTIBLE(i) ||
3804 /* ---------- WALL ----------------------------------------------------- */
3805 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
3807 for (j = 0; no_wall_properties[j] != -1; j++)
3808 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
3809 i >= EL_FIRST_RUNTIME_UNREAL)
3810 SET_PROPERTY(i, EP_WALL, FALSE);
3812 if (IS_HISTORIC_WALL(i))
3813 SET_PROPERTY(i, EP_WALL, TRUE);
3815 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
3816 if (engine_version < VERSION_IDENT(2,2,0,0))
3817 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
3819 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
3821 !IS_COLLECTIBLE(i)));
3824 /* ---------- PROTECTED ------------------------------------------------ */
3825 if (IS_ACCESSIBLE_INSIDE(i))
3826 SET_PROPERTY(i, EP_PROTECTED, TRUE);
3829 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
3831 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
3832 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
3834 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
3835 IS_INDESTRUCTIBLE(i)));
3837 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
3839 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
3840 else if (engine_version < VERSION_IDENT(2,2,0,0))
3841 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
3844 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3849 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3850 !IS_WALKABLE_OVER(i) &&
3851 !IS_WALKABLE_UNDER(i)));
3853 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3858 if (IS_CUSTOM_ELEMENT(i))
3860 /* these are additional properties which are initially false when set */
3862 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
3864 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
3865 if (DONT_COLLIDE_WITH(i))
3866 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
3868 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
3869 if (CAN_SMASH_EVERYTHING(i))
3870 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
3871 if (CAN_SMASH_ENEMIES(i))
3872 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
3875 /* ---------- CAN_SMASH ------------------------------------------------ */
3876 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
3877 CAN_SMASH_ENEMIES(i) ||
3878 CAN_SMASH_EVERYTHING(i)));
3881 /* ---------- CAN_EXPLODE ---------------------------------------------- */
3882 SET_PROPERTY(i, EP_CAN_EXPLODE, (CAN_EXPLODE_BY_FIRE(i) ||
3883 CAN_EXPLODE_SMASHED(i) ||
3884 CAN_EXPLODE_IMPACT(i)));
3888 /* ---------- CAN_EXPLODE_3X3 ------------------------------------------ */
3890 SET_PROPERTY(i, EP_CAN_EXPLODE_3X3, (!CAN_EXPLODE_1X1(i) &&
3891 !CAN_EXPLODE_CROSS(i)));
3893 SET_PROPERTY(i, EP_CAN_EXPLODE_3X3, (CAN_EXPLODE(i) &&
3894 !CAN_EXPLODE_1X1(i) &&
3895 !CAN_EXPLODE_CROSS(i)));
3899 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
3900 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
3901 EXPLODES_BY_FIRE(i)));
3903 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
3904 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
3905 EXPLODES_SMASHED(i)));
3907 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
3908 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
3909 EXPLODES_IMPACT(i)));
3911 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
3912 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
3914 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
3915 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
3916 i == EL_BLACK_ORB));
3918 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
3919 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
3921 IS_CUSTOM_ELEMENT(i)));
3923 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
3924 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
3925 i == EL_SP_ELECTRON));
3927 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
3928 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
3929 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
3930 getMoveIntoAcidProperty(&level, i));
3932 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
3933 if (MAYBE_DONT_COLLIDE_WITH(i))
3934 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
3935 getDontCollideWithProperty(&level, i));
3937 /* ---------- SP_PORT -------------------------------------------------- */
3938 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
3939 IS_PASSABLE_INSIDE(i)));
3941 /* ---------- CAN_CHANGE ----------------------------------------------- */
3942 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
3943 for (j = 0; j < element_info[i].num_change_pages; j++)
3944 if (element_info[i].change_page[j].can_change)
3945 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
3947 /* ---------- GFX_CRUMBLED --------------------------------------------- */
3949 SET_PROPERTY(i, EP_GFX_CRUMBLED,
3950 element_info[i].crumbled[ACTION_DEFAULT] !=
3951 element_info[i].graphic[ACTION_DEFAULT]);
3953 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
3954 SET_PROPERTY(i, EP_GFX_CRUMBLED,
3955 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
3960 /* determine inactive elements (used for engine main loop optimization) */
3961 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3963 boolean active = FALSE;
3965 for (j = 0; i < NUM_ELEMENT_PROPERTIES; j++)
3967 if (HAS_PROPERTY(i, j))
3973 SET_PROPERTY(i, EP_INACTIVE, TRUE);
3978 /* dynamically adjust element properties according to game engine version */
3980 static int ep_em_slippery_wall[] =
3985 EL_EXPANDABLE_WALL_HORIZONTAL,
3986 EL_EXPANDABLE_WALL_VERTICAL,
3987 EL_EXPANDABLE_WALL_ANY,
3991 /* special EM style gems behaviour */
3992 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
3993 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
3994 level.em_slippery_gems);
3996 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
3997 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
3998 (level.em_slippery_gems &&
3999 engine_version > VERSION_IDENT(2,0,1,0)));
4003 /* set default push delay values (corrected since version 3.0.7-1) */
4004 if (engine_version < VERSION_IDENT(3,0,7,1))
4006 game.default_push_delay_fixed = 2;
4007 game.default_push_delay_random = 8;
4011 game.default_push_delay_fixed = 8;
4012 game.default_push_delay_random = 8;
4015 /* set uninitialized push delay values of custom elements in older levels */
4016 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4018 int element = EL_CUSTOM_START + i;
4020 if (element_info[element].push_delay_fixed == -1)
4021 element_info[element].push_delay_fixed = game.default_push_delay_fixed;
4022 if (element_info[element].push_delay_random == -1)
4023 element_info[element].push_delay_random = game.default_push_delay_random;
4026 /* set some other uninitialized values of custom elements in older levels */
4027 if (engine_version < VERSION_IDENT(3,1,0,0))
4029 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4031 int element = EL_CUSTOM_START + i;
4033 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4035 element_info[element].explosion_delay = 17;
4036 element_info[element].ignition_delay = 8;
4041 /* set element properties that were handled incorrectly in older levels */
4042 if (engine_version < VERSION_IDENT(3,1,0,0))
4044 SET_PROPERTY(EL_SP_SNIKSNAK, EP_DONT_COLLIDE_WITH, FALSE);
4045 SET_PROPERTY(EL_SP_ELECTRON, EP_DONT_COLLIDE_WITH, FALSE);
4051 /* this is needed because some graphics depend on element properties */
4052 if (game_status == GAME_MODE_PLAYING)
4053 InitElementGraphicInfo();
4056 static void InitGlobal()
4060 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4062 /* check if element_name_info entry defined for each element in "main.h" */
4063 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4064 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4066 element_info[i].token_name = element_name_info[i].token_name;
4067 element_info[i].class_name = element_name_info[i].class_name;
4068 element_info[i].editor_description=element_name_info[i].editor_description;
4071 global.autoplay_leveldir = NULL;
4072 global.convert_leveldir = NULL;
4074 global.frames_per_second = 0;
4075 global.fps_slowdown = FALSE;
4076 global.fps_slowdown_factor = 1;
4079 void Execute_Command(char *command)
4083 if (strcmp(command, "print graphicsinfo.conf") == 0)
4085 printf("# You can configure additional/alternative image files here.\n");
4086 printf("# (The entries below are default and therefore commented out.)\n");
4088 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4090 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4093 for (i = 0; image_config[i].token != NULL; i++)
4094 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
4095 image_config[i].value));
4099 else if (strcmp(command, "print soundsinfo.conf") == 0)
4101 printf("# You can configure additional/alternative sound files here.\n");
4102 printf("# (The entries below are default and therefore commented out.)\n");
4104 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4106 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4109 for (i = 0; sound_config[i].token != NULL; i++)
4110 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4111 sound_config[i].value));
4115 else if (strcmp(command, "print musicinfo.conf") == 0)
4117 printf("# You can configure additional/alternative music files here.\n");
4118 printf("# (The entries below are default and therefore commented out.)\n");
4120 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4122 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4125 for (i = 0; music_config[i].token != NULL; i++)
4126 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
4127 music_config[i].value));
4131 else if (strcmp(command, "print editorsetup.conf") == 0)
4133 printf("# You can configure your personal editor element list here.\n");
4134 printf("# (The entries below are default and therefore commented out.)\n");
4137 PrintEditorElementList();
4141 else if (strcmp(command, "print helpanim.conf") == 0)
4143 printf("# You can configure different element help animations here.\n");
4144 printf("# (The entries below are default and therefore commented out.)\n");
4147 for (i = 0; helpanim_config[i].token != NULL; i++)
4149 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4150 helpanim_config[i].value));
4152 if (strcmp(helpanim_config[i].token, "end") == 0)
4158 else if (strcmp(command, "print helptext.conf") == 0)
4160 printf("# You can configure different element help text here.\n");
4161 printf("# (The entries below are default and therefore commented out.)\n");
4164 for (i = 0; helptext_config[i].token != NULL; i++)
4165 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4166 helptext_config[i].value));
4170 else if (strncmp(command, "dump level ", 11) == 0)
4172 char *filename = &command[11];
4174 if (access(filename, F_OK) != 0)
4175 Error(ERR_EXIT, "cannot open file '%s'", filename);
4177 LoadLevelFromFilename(&level, filename);
4182 else if (strncmp(command, "dump tape ", 10) == 0)
4184 char *filename = &command[10];
4186 if (access(filename, F_OK) != 0)
4187 Error(ERR_EXIT, "cannot open file '%s'", filename);
4189 LoadTapeFromFilename(filename);
4194 else if (strncmp(command, "autoplay ", 9) == 0)
4196 char *str_copy = getStringCopy(&command[9]);
4197 char *str_ptr = strchr(str_copy, ' ');
4199 global.autoplay_leveldir = str_copy;
4200 global.autoplay_level_nr = -1;
4202 if (str_ptr != NULL)
4204 *str_ptr++ = '\0'; /* terminate leveldir string */
4205 global.autoplay_level_nr = atoi(str_ptr); /* get level_nr value */
4208 else if (strncmp(command, "convert ", 8) == 0)
4210 char *str_copy = getStringCopy(&command[8]);
4211 char *str_ptr = strchr(str_copy, ' ');
4213 global.convert_leveldir = str_copy;
4214 global.convert_level_nr = -1;
4216 if (str_ptr != NULL)
4218 *str_ptr++ = '\0'; /* terminate leveldir string */
4219 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
4224 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4228 static void InitSetup()
4230 LoadSetup(); /* global setup info */
4232 /* set some options from setup file */
4234 if (setup.options.verbose)
4235 options.verbose = TRUE;
4238 static void InitPlayerInfo()
4242 /* choose default local player */
4243 local_player = &stored_player[0];
4245 for (i = 0; i < MAX_PLAYERS; i++)
4246 stored_player[i].connected = FALSE;
4248 local_player->connected = TRUE;
4251 static void InitArtworkInfo()
4256 static char *get_string_in_brackets(char *string)
4258 char *string_in_brackets = checked_malloc(strlen(string) + 3);
4260 sprintf(string_in_brackets, "[%s]", string);
4262 return string_in_brackets;
4265 static char *get_level_id_suffix(int id_nr)
4267 char *id_suffix = checked_malloc(1 + 3 + 1);
4269 if (id_nr < 0 || id_nr > 999)
4272 sprintf(id_suffix, ".%03d", id_nr);
4278 static char *get_element_class_token(int element)
4280 char *element_class_name = element_info[element].class_name;
4281 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
4283 sprintf(element_class_token, "[%s]", element_class_name);
4285 return element_class_token;
4288 static char *get_action_class_token(int action)
4290 char *action_class_name = &element_action_info[action].suffix[1];
4291 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
4293 sprintf(action_class_token, "[%s]", action_class_name);
4295 return action_class_token;
4299 static void InitArtworkConfig()
4301 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
4302 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
4303 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
4304 static char *action_id_suffix[NUM_ACTIONS + 1];
4305 static char *direction_id_suffix[NUM_DIRECTIONS + 1];
4306 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
4307 static char *level_id_suffix[MAX_LEVELS + 1];
4308 static char *dummy[1] = { NULL };
4309 static char *ignore_generic_tokens[] =
4315 static char **ignore_image_tokens;
4316 static char **ignore_sound_tokens;
4317 static char **ignore_music_tokens;
4318 int num_ignore_generic_tokens;
4319 int num_ignore_image_tokens;
4320 int num_ignore_sound_tokens;
4321 int num_ignore_music_tokens;
4324 /* dynamically determine list of generic tokens to be ignored */
4325 num_ignore_generic_tokens = 0;
4326 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
4327 num_ignore_generic_tokens++;
4329 /* dynamically determine list of image tokens to be ignored */
4330 num_ignore_image_tokens = num_ignore_generic_tokens;
4331 for (i = 0; image_config_vars[i].token != NULL; i++)
4332 num_ignore_image_tokens++;
4333 ignore_image_tokens =
4334 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
4335 for (i = 0; i < num_ignore_generic_tokens; i++)
4336 ignore_image_tokens[i] = ignore_generic_tokens[i];
4337 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
4338 ignore_image_tokens[num_ignore_generic_tokens + i] =
4339 image_config_vars[i].token;
4340 ignore_image_tokens[num_ignore_image_tokens] = NULL;
4342 /* dynamically determine list of sound tokens to be ignored */
4343 num_ignore_sound_tokens = num_ignore_generic_tokens;
4344 ignore_sound_tokens =
4345 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
4346 for (i = 0; i < num_ignore_generic_tokens; i++)
4347 ignore_sound_tokens[i] = ignore_generic_tokens[i];
4348 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
4350 /* dynamically determine list of music tokens to be ignored */
4351 num_ignore_music_tokens = num_ignore_generic_tokens;
4352 ignore_music_tokens =
4353 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
4354 for (i = 0; i < num_ignore_generic_tokens; i++)
4355 ignore_music_tokens[i] = ignore_generic_tokens[i];
4356 ignore_music_tokens[num_ignore_music_tokens] = NULL;
4358 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4359 image_id_prefix[i] = element_info[i].token_name;
4360 for (i = 0; i < NUM_FONTS; i++)
4361 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
4362 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
4364 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4365 sound_id_prefix[i] = element_info[i].token_name;
4366 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4367 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
4368 get_string_in_brackets(element_info[i].class_name);
4369 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
4371 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
4372 music_id_prefix[i] = music_prefix_info[i].prefix;
4373 music_id_prefix[MAX_LEVELS] = NULL;
4375 for (i = 0; i < NUM_ACTIONS; i++)
4376 action_id_suffix[i] = element_action_info[i].suffix;
4377 action_id_suffix[NUM_ACTIONS] = NULL;
4379 for (i = 0; i < NUM_DIRECTIONS; i++)
4380 direction_id_suffix[i] = element_direction_info[i].suffix;
4381 direction_id_suffix[NUM_DIRECTIONS] = NULL;
4383 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
4384 special_id_suffix[i] = special_suffix_info[i].suffix;
4385 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
4387 for (i = 0; i < MAX_LEVELS; i++)
4388 level_id_suffix[i] = get_level_id_suffix(i);
4389 level_id_suffix[MAX_LEVELS] = NULL;
4391 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
4392 image_id_prefix, action_id_suffix, direction_id_suffix,
4393 special_id_suffix, ignore_image_tokens);
4394 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
4395 sound_id_prefix, action_id_suffix, dummy,
4396 special_id_suffix, ignore_sound_tokens);
4397 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
4398 music_id_prefix, special_id_suffix, level_id_suffix,
4399 dummy, ignore_music_tokens);
4402 static void InitMixer()
4410 char *filename_font_initial = NULL;
4411 Bitmap *bitmap_font_initial = NULL;
4414 /* determine settings for initial font (for displaying startup messages) */
4415 for (i = 0; image_config[i].token != NULL; i++)
4417 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4419 char font_token[128];
4422 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
4423 len_font_token = strlen(font_token);
4425 if (strcmp(image_config[i].token, font_token) == 0)
4426 filename_font_initial = image_config[i].value;
4427 else if (strlen(image_config[i].token) > len_font_token &&
4428 strncmp(image_config[i].token, font_token, len_font_token) == 0)
4430 if (strcmp(&image_config[i].token[len_font_token], ".x") == 0)
4431 font_initial[j].src_x = atoi(image_config[i].value);
4432 else if (strcmp(&image_config[i].token[len_font_token], ".y") == 0)
4433 font_initial[j].src_y = atoi(image_config[i].value);
4434 else if (strcmp(&image_config[i].token[len_font_token], ".width") == 0)
4435 font_initial[j].width = atoi(image_config[i].value);
4436 else if (strcmp(&image_config[i].token[len_font_token],".height") == 0)
4437 font_initial[j].height = atoi(image_config[i].value);
4442 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4444 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
4445 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
4448 if (filename_font_initial == NULL) /* should not happen */
4449 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
4451 /* create additional image buffers for double-buffering */
4452 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
4453 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
4455 /* initialize screen properties */
4456 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
4457 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
4459 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
4460 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
4461 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
4463 bitmap_font_initial = LoadCustomImage(filename_font_initial);
4465 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4466 font_initial[j].bitmap = bitmap_font_initial;
4468 InitFontGraphicInfo();
4470 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
4471 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
4473 DrawInitText("Loading graphics:", 120, FC_GREEN);
4475 InitTileClipmasks();
4478 void InitGfxBackground()
4482 drawto = backbuffer;
4483 fieldbuffer = bitmap_db_field;
4484 SetDrawtoField(DRAW_BACKBUFFER);
4486 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
4487 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
4488 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
4489 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
4491 for (x = 0; x < MAX_BUF_XSIZE; x++)
4492 for (y = 0; y < MAX_BUF_YSIZE; y++)
4495 redraw_mask = REDRAW_ALL;
4498 static void InitLevelInfo()
4500 LoadLevelInfo(); /* global level info */
4501 LoadLevelSetup_LastSeries(); /* last played series info */
4502 LoadLevelSetup_SeriesInfo(); /* last played level info */
4505 void InitLevelArtworkInfo()
4507 LoadLevelArtworkInfo();
4510 static void InitImages()
4513 setLevelArtworkDir(artwork.gfx_first);
4517 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
4518 leveldir_current->identifier,
4519 artwork.gfx_current_identifier,
4520 artwork.gfx_current->identifier,
4521 leveldir_current->graphics_set,
4522 leveldir_current->graphics_path);
4525 ReloadCustomImages();
4527 LoadCustomElementDescriptions();
4528 LoadSpecialMenuDesignSettings();
4530 ReinitializeGraphics();
4533 static void InitSound(char *identifier)
4535 if (identifier == NULL)
4536 identifier = artwork.snd_current->identifier;
4539 /* set artwork path to send it to the sound server process */
4540 setLevelArtworkDir(artwork.snd_first);
4543 InitReloadCustomSounds(identifier);
4544 ReinitializeSounds();
4547 static void InitMusic(char *identifier)
4549 if (identifier == NULL)
4550 identifier = artwork.mus_current->identifier;
4553 /* set artwork path to send it to the sound server process */
4554 setLevelArtworkDir(artwork.mus_first);
4557 InitReloadCustomMusic(identifier);
4558 ReinitializeMusic();
4561 void InitNetworkServer()
4563 #if defined(NETWORK_AVALIABLE)
4567 if (!options.network)
4570 #if defined(NETWORK_AVALIABLE)
4571 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
4573 if (!ConnectToServer(options.server_host, options.server_port))
4574 Error(ERR_EXIT, "cannot connect to network game server");
4576 SendToServer_PlayerName(setup.player_name);
4577 SendToServer_ProtocolVersion();
4580 SendToServer_NrWanted(nr_wanted);
4584 static char *getNewArtworkIdentifier(int type)
4586 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
4587 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
4588 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
4589 static boolean initialized[3] = { FALSE, FALSE, FALSE };
4590 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
4591 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
4592 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
4593 char *leveldir_identifier = leveldir_current->identifier;
4595 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
4596 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
4598 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
4600 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
4601 char *artwork_current_identifier;
4602 char *artwork_new_identifier = NULL; /* default: nothing has changed */
4604 /* leveldir_current may be invalid (level group, parent link) */
4605 if (!validLevelSeries(leveldir_current))
4608 /* 1st step: determine artwork set to be activated in descending order:
4609 --------------------------------------------------------------------
4610 1. setup artwork (when configured to override everything else)
4611 2. artwork set configured in "levelinfo.conf" of current level set
4612 (artwork in level directory will have priority when loading later)
4613 3. artwork in level directory (stored in artwork sub-directory)
4614 4. setup artwork (currently configured in setup menu) */
4616 if (setup_override_artwork)
4617 artwork_current_identifier = setup_artwork_set;
4618 else if (leveldir_artwork_set != NULL)
4619 artwork_current_identifier = leveldir_artwork_set;
4620 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
4621 artwork_current_identifier = leveldir_identifier;
4623 artwork_current_identifier = setup_artwork_set;
4626 /* 2nd step: check if it is really needed to reload artwork set
4627 ------------------------------------------------------------ */
4630 if (type == ARTWORK_TYPE_GRAPHICS)
4631 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
4632 artwork_new_identifier,
4633 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4634 artwork_current_identifier,
4635 leveldir_current->graphics_set,
4636 leveldir_current->identifier);
4639 /* ---------- reload if level set and also artwork set has changed ------- */
4640 if (leveldir_current_identifier[type] != leveldir_identifier &&
4641 (last_has_level_artwork_set[type] || has_level_artwork_set))
4642 artwork_new_identifier = artwork_current_identifier;
4644 leveldir_current_identifier[type] = leveldir_identifier;
4645 last_has_level_artwork_set[type] = has_level_artwork_set;
4648 if (type == ARTWORK_TYPE_GRAPHICS)
4649 printf("::: 1: '%s'\n", artwork_new_identifier);
4652 /* ---------- reload if "override artwork" setting has changed ----------- */
4653 if (last_override_level_artwork[type] != setup_override_artwork)
4654 artwork_new_identifier = artwork_current_identifier;
4656 last_override_level_artwork[type] = setup_override_artwork;
4659 if (type == ARTWORK_TYPE_GRAPHICS)
4660 printf("::: 2: '%s'\n", artwork_new_identifier);
4663 /* ---------- reload if current artwork identifier has changed ----------- */
4664 if (strcmp(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4665 artwork_current_identifier) != 0)
4666 artwork_new_identifier = artwork_current_identifier;
4668 *(&(ARTWORK_CURRENT_IDENTIFIER(artwork, type))) = artwork_current_identifier;
4671 if (type == ARTWORK_TYPE_GRAPHICS)
4672 printf("::: 3: '%s'\n", artwork_new_identifier);
4675 /* ---------- do not reload directly after starting ---------------------- */
4676 if (!initialized[type])
4677 artwork_new_identifier = NULL;
4679 initialized[type] = TRUE;
4682 if (type == ARTWORK_TYPE_GRAPHICS)
4683 printf("::: 4: '%s'\n", artwork_new_identifier);
4687 if (type == ARTWORK_TYPE_GRAPHICS)
4688 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
4689 artwork.gfx_current_identifier, artwork_current_identifier,
4690 artwork.gfx_current->identifier, leveldir_current->graphics_set,
4691 artwork_new_identifier);
4694 return artwork_new_identifier;
4697 void ReloadCustomArtwork(int force_reload)
4699 char *gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
4700 char *snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
4701 char *mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
4702 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
4703 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
4704 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
4705 boolean redraw_screen = FALSE;
4707 if (gfx_new_identifier != NULL || force_reload_gfx)
4710 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
4711 artwork.gfx_current_identifier,
4713 artwork.gfx_current->identifier,
4714 leveldir_current->graphics_set);
4717 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4722 printf("... '%s'\n",
4723 leveldir_current->graphics_set);
4726 FreeTileClipmasks();
4727 InitTileClipmasks();
4729 redraw_screen = TRUE;
4732 if (snd_new_identifier != NULL || force_reload_snd)
4734 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4736 InitSound(snd_new_identifier);
4738 redraw_screen = TRUE;
4741 if (mus_new_identifier != NULL || force_reload_mus)
4743 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4745 InitMusic(mus_new_identifier);
4747 redraw_screen = TRUE;
4752 InitGfxBackground();
4754 /* force redraw of (open or closed) door graphics */
4755 SetDoorState(DOOR_OPEN_ALL);
4756 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
4760 void KeyboardAutoRepeatOffUnlessAutoplay()
4762 if (global.autoplay_leveldir == NULL)
4763 KeyboardAutoRepeatOff();
4767 /* ========================================================================= */
4769 /* ========================================================================= */
4773 InitGlobal(); /* initialize some global variables */
4775 if (options.execute_command)
4776 Execute_Command(options.execute_command);
4778 if (options.serveronly)
4780 #if defined(PLATFORM_UNIX)
4781 NetworkServer(options.server_port, options.serveronly);
4783 Error(ERR_WARN, "networking only supported in Unix version");
4786 exit(0); /* never reached, server loops forever */
4792 InitArtworkInfo(); /* needed before loading gfx, sound & music */
4793 InitArtworkConfig(); /* needed before forking sound child process */
4798 InitRND(NEW_RANDOMIZE);
4799 InitSimpleRND(NEW_RANDOMIZE);
4804 InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
4807 InitEventFilter(FilterMouseMotionEvents);
4809 InitElementPropertiesStatic();
4810 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4815 InitLevelArtworkInfo();
4817 InitImages(); /* needs to know current level directory */
4818 InitSound(NULL); /* needs to know current level directory */
4819 InitMusic(NULL); /* needs to know current level directory */
4821 InitGfxBackground();
4823 if (global.autoplay_leveldir)
4828 else if (global.convert_leveldir)
4834 game_status = GAME_MODE_MAIN;
4842 InitNetworkServer();
4845 void CloseAllAndExit(int exit_value)
4850 CloseAudio(); /* called after freeing sounds (needed for SDL) */
4857 FreeTileClipmasks();
4859 #if defined(TARGET_SDL)
4860 if (network_server) /* terminate network server */
4861 SDL_KillThread(server_thread);
4864 CloseVideoDisplay();
4865 ClosePlatformDependentStuff();