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,
2532 #if 0 /* USE_GRAVITY_BUGFIX */
2533 EL_PLAYER_IS_LEAVING, /* needed for gravity + "block last field" */
2538 static int ep_walkable_inside[] =
2543 EL_TUBE_VERTICAL_LEFT,
2544 EL_TUBE_VERTICAL_RIGHT,
2545 EL_TUBE_HORIZONTAL_UP,
2546 EL_TUBE_HORIZONTAL_DOWN,
2554 static int ep_walkable_under[] =
2559 static int ep_passable_over[] =
2582 static int ep_passable_inside[] =
2588 EL_SP_PORT_HORIZONTAL,
2589 EL_SP_PORT_VERTICAL,
2591 EL_SP_GRAVITY_PORT_LEFT,
2592 EL_SP_GRAVITY_PORT_RIGHT,
2593 EL_SP_GRAVITY_PORT_UP,
2594 EL_SP_GRAVITY_PORT_DOWN,
2595 EL_SP_GRAVITY_ON_PORT_LEFT,
2596 EL_SP_GRAVITY_ON_PORT_RIGHT,
2597 EL_SP_GRAVITY_ON_PORT_UP,
2598 EL_SP_GRAVITY_ON_PORT_DOWN,
2599 EL_SP_GRAVITY_OFF_PORT_LEFT,
2600 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2601 EL_SP_GRAVITY_OFF_PORT_UP,
2602 EL_SP_GRAVITY_OFF_PORT_DOWN,
2606 static int ep_passable_under[] =
2611 static int ep_droppable[] =
2616 static int ep_explodes_1x1_old[] =
2621 static int ep_pushable[] =
2633 EL_SOKOBAN_FIELD_FULL,
2641 static int ep_explodes_cross_old[] =
2646 static int ep_protected[] =
2648 /* same elements as in 'ep_walkable_inside' */
2652 EL_TUBE_VERTICAL_LEFT,
2653 EL_TUBE_VERTICAL_RIGHT,
2654 EL_TUBE_HORIZONTAL_UP,
2655 EL_TUBE_HORIZONTAL_DOWN,
2661 /* same elements as in 'ep_passable_over' */
2681 /* same elements as in 'ep_passable_inside' */
2686 EL_SP_PORT_HORIZONTAL,
2687 EL_SP_PORT_VERTICAL,
2689 EL_SP_GRAVITY_PORT_LEFT,
2690 EL_SP_GRAVITY_PORT_RIGHT,
2691 EL_SP_GRAVITY_PORT_UP,
2692 EL_SP_GRAVITY_PORT_DOWN,
2693 EL_SP_GRAVITY_ON_PORT_LEFT,
2694 EL_SP_GRAVITY_ON_PORT_RIGHT,
2695 EL_SP_GRAVITY_ON_PORT_UP,
2696 EL_SP_GRAVITY_ON_PORT_DOWN,
2697 EL_SP_GRAVITY_OFF_PORT_LEFT,
2698 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2699 EL_SP_GRAVITY_OFF_PORT_UP,
2700 EL_SP_GRAVITY_OFF_PORT_DOWN,
2704 static int ep_throwable[] =
2709 static int ep_can_explode[] =
2711 /* same elements as in 'ep_explodes_impact' */
2716 /* same elements as in 'ep_explodes_smashed' */
2722 /* elements that can explode by explosion or by dragonfire */
2725 EL_DYNABOMB_PLAYER_1_ACTIVE,
2726 EL_DYNABOMB_PLAYER_2_ACTIVE,
2727 EL_DYNABOMB_PLAYER_3_ACTIVE,
2728 EL_DYNABOMB_PLAYER_4_ACTIVE,
2729 EL_DYNABOMB_INCREASE_NUMBER,
2730 EL_DYNABOMB_INCREASE_SIZE,
2731 EL_DYNABOMB_INCREASE_POWER,
2732 EL_SP_DISK_RED_ACTIVE,
2740 /* elements that can explode only by explosion */
2745 static int ep_gravity_reachable[] =
2751 EL_INVISIBLE_SAND_ACTIVE,
2756 EL_SP_PORT_HORIZONTAL,
2757 EL_SP_PORT_VERTICAL,
2759 EL_SP_GRAVITY_PORT_LEFT,
2760 EL_SP_GRAVITY_PORT_RIGHT,
2761 EL_SP_GRAVITY_PORT_UP,
2762 EL_SP_GRAVITY_PORT_DOWN,
2763 EL_SP_GRAVITY_ON_PORT_LEFT,
2764 EL_SP_GRAVITY_ON_PORT_RIGHT,
2765 EL_SP_GRAVITY_ON_PORT_UP,
2766 EL_SP_GRAVITY_ON_PORT_DOWN,
2767 EL_SP_GRAVITY_OFF_PORT_LEFT,
2768 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2769 EL_SP_GRAVITY_OFF_PORT_UP,
2770 EL_SP_GRAVITY_OFF_PORT_DOWN,
2775 static int ep_player[] =
2782 EL_SOKOBAN_FIELD_PLAYER,
2787 static int ep_can_pass_magic_wall[] =
2800 static int ep_switchable[] =
2804 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2805 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2806 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2807 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2808 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2809 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2810 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2811 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2812 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2813 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2814 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2815 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2816 EL_SWITCHGATE_SWITCH_UP,
2817 EL_SWITCHGATE_SWITCH_DOWN,
2819 EL_LIGHT_SWITCH_ACTIVE,
2821 EL_BALLOON_SWITCH_LEFT,
2822 EL_BALLOON_SWITCH_RIGHT,
2823 EL_BALLOON_SWITCH_UP,
2824 EL_BALLOON_SWITCH_DOWN,
2825 EL_BALLOON_SWITCH_ANY,
2828 EL_EMC_MAGIC_BALL_SWITCH,
2832 static int ep_bd_element[] =
2865 static int ep_sp_element[] =
2867 /* should always be valid */
2870 /* standard classic Supaplex elements */
2877 EL_SP_HARDWARE_GRAY,
2885 EL_SP_GRAVITY_PORT_RIGHT,
2886 EL_SP_GRAVITY_PORT_DOWN,
2887 EL_SP_GRAVITY_PORT_LEFT,
2888 EL_SP_GRAVITY_PORT_UP,
2893 EL_SP_PORT_VERTICAL,
2894 EL_SP_PORT_HORIZONTAL,
2900 EL_SP_HARDWARE_BASE_1,
2901 EL_SP_HARDWARE_GREEN,
2902 EL_SP_HARDWARE_BLUE,
2904 EL_SP_HARDWARE_YELLOW,
2905 EL_SP_HARDWARE_BASE_2,
2906 EL_SP_HARDWARE_BASE_3,
2907 EL_SP_HARDWARE_BASE_4,
2908 EL_SP_HARDWARE_BASE_5,
2909 EL_SP_HARDWARE_BASE_6,
2913 /* additional elements that appeared in newer Supaplex levels */
2916 /* additional gravity port elements (not switching, but setting gravity) */
2917 EL_SP_GRAVITY_ON_PORT_LEFT,
2918 EL_SP_GRAVITY_ON_PORT_RIGHT,
2919 EL_SP_GRAVITY_ON_PORT_UP,
2920 EL_SP_GRAVITY_ON_PORT_DOWN,
2921 EL_SP_GRAVITY_OFF_PORT_LEFT,
2922 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2923 EL_SP_GRAVITY_OFF_PORT_UP,
2924 EL_SP_GRAVITY_OFF_PORT_DOWN,
2926 /* more than one Murphy in a level results in an inactive clone */
2929 /* runtime Supaplex elements */
2930 EL_SP_DISK_RED_ACTIVE,
2931 EL_SP_TERMINAL_ACTIVE,
2932 EL_SP_BUGGY_BASE_ACTIVATING,
2933 EL_SP_BUGGY_BASE_ACTIVE,
2939 static int ep_sb_element[] =
2944 EL_SOKOBAN_FIELD_EMPTY,
2945 EL_SOKOBAN_FIELD_FULL,
2946 EL_SOKOBAN_FIELD_PLAYER,
2951 EL_INVISIBLE_STEELWALL,
2955 static int ep_gem[] =
2966 static int ep_food_dark_yamyam[] =
2993 static int ep_food_penguin[] =
3006 static int ep_food_pig[] =
3017 static int ep_historic_wall[] =
3042 EL_EXPANDABLE_WALL_HORIZONTAL,
3043 EL_EXPANDABLE_WALL_VERTICAL,
3044 EL_EXPANDABLE_WALL_ANY,
3045 EL_EXPANDABLE_WALL_GROWING,
3052 EL_SP_HARDWARE_GRAY,
3053 EL_SP_HARDWARE_GREEN,
3054 EL_SP_HARDWARE_BLUE,
3056 EL_SP_HARDWARE_YELLOW,
3057 EL_SP_HARDWARE_BASE_1,
3058 EL_SP_HARDWARE_BASE_2,
3059 EL_SP_HARDWARE_BASE_3,
3060 EL_SP_HARDWARE_BASE_4,
3061 EL_SP_HARDWARE_BASE_5,
3062 EL_SP_HARDWARE_BASE_6,
3064 EL_SP_TERMINAL_ACTIVE,
3067 EL_INVISIBLE_STEELWALL,
3068 EL_INVISIBLE_STEELWALL_ACTIVE,
3070 EL_INVISIBLE_WALL_ACTIVE,
3071 EL_STEELWALL_SLIPPERY,
3087 static int ep_historic_solid[] =
3091 EL_EXPANDABLE_WALL_HORIZONTAL,
3092 EL_EXPANDABLE_WALL_VERTICAL,
3093 EL_EXPANDABLE_WALL_ANY,
3106 EL_QUICKSAND_FILLING,
3107 EL_QUICKSAND_EMPTYING,
3109 EL_MAGIC_WALL_ACTIVE,
3110 EL_MAGIC_WALL_EMPTYING,
3111 EL_MAGIC_WALL_FILLING,
3115 EL_BD_MAGIC_WALL_ACTIVE,
3116 EL_BD_MAGIC_WALL_EMPTYING,
3117 EL_BD_MAGIC_WALL_FULL,
3118 EL_BD_MAGIC_WALL_FILLING,
3119 EL_BD_MAGIC_WALL_DEAD,
3128 EL_SP_TERMINAL_ACTIVE,
3132 EL_INVISIBLE_WALL_ACTIVE,
3133 EL_SWITCHGATE_SWITCH_UP,
3134 EL_SWITCHGATE_SWITCH_DOWN,
3136 EL_TIMEGATE_SWITCH_ACTIVE,
3148 /* the following elements are a direct copy of "indestructible" elements,
3149 except "EL_ACID", which is "indestructible", but not "solid"! */
3154 EL_ACID_POOL_TOPLEFT,
3155 EL_ACID_POOL_TOPRIGHT,
3156 EL_ACID_POOL_BOTTOMLEFT,
3157 EL_ACID_POOL_BOTTOM,
3158 EL_ACID_POOL_BOTTOMRIGHT,
3159 EL_SP_HARDWARE_GRAY,
3160 EL_SP_HARDWARE_GREEN,
3161 EL_SP_HARDWARE_BLUE,
3163 EL_SP_HARDWARE_YELLOW,
3164 EL_SP_HARDWARE_BASE_1,
3165 EL_SP_HARDWARE_BASE_2,
3166 EL_SP_HARDWARE_BASE_3,
3167 EL_SP_HARDWARE_BASE_4,
3168 EL_SP_HARDWARE_BASE_5,
3169 EL_SP_HARDWARE_BASE_6,
3170 EL_INVISIBLE_STEELWALL,
3171 EL_INVISIBLE_STEELWALL_ACTIVE,
3172 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3173 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3174 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3175 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3176 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3177 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3178 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3179 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3180 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3181 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3182 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3183 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3185 EL_LIGHT_SWITCH_ACTIVE,
3186 EL_SIGN_EXCLAMATION,
3187 EL_SIGN_RADIOACTIVITY,
3198 EL_STEELWALL_SLIPPERY,
3221 EL_SWITCHGATE_OPENING,
3222 EL_SWITCHGATE_CLOSED,
3223 EL_SWITCHGATE_CLOSING,
3225 EL_TIMEGATE_OPENING,
3227 EL_TIMEGATE_CLOSING,
3231 EL_TUBE_VERTICAL_LEFT,
3232 EL_TUBE_VERTICAL_RIGHT,
3233 EL_TUBE_HORIZONTAL_UP,
3234 EL_TUBE_HORIZONTAL_DOWN,
3242 static int ep_classic_enemy[] =
3258 static int ep_belt[] =
3260 EL_CONVEYOR_BELT_1_LEFT,
3261 EL_CONVEYOR_BELT_1_MIDDLE,
3262 EL_CONVEYOR_BELT_1_RIGHT,
3263 EL_CONVEYOR_BELT_2_LEFT,
3264 EL_CONVEYOR_BELT_2_MIDDLE,
3265 EL_CONVEYOR_BELT_2_RIGHT,
3266 EL_CONVEYOR_BELT_3_LEFT,
3267 EL_CONVEYOR_BELT_3_MIDDLE,
3268 EL_CONVEYOR_BELT_3_RIGHT,
3269 EL_CONVEYOR_BELT_4_LEFT,
3270 EL_CONVEYOR_BELT_4_MIDDLE,
3271 EL_CONVEYOR_BELT_4_RIGHT,
3275 static int ep_belt_active[] =
3277 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3278 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3279 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3280 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3281 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3282 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3283 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3284 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3285 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3286 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3287 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3288 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3292 static int ep_belt_switch[] =
3294 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3295 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3296 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3297 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3298 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3299 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3300 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3301 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3302 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3303 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3304 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3305 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3309 static int ep_tube[] =
3316 EL_TUBE_HORIZONTAL_UP,
3317 EL_TUBE_HORIZONTAL_DOWN,
3319 EL_TUBE_VERTICAL_LEFT,
3320 EL_TUBE_VERTICAL_RIGHT,
3325 static int ep_keygate[] =
3354 static int ep_amoeboid[] =
3364 static int ep_amoebalive[] =
3373 static int ep_has_content[] =
3383 static int ep_can_turn_each_move[] =
3385 /* !!! do something with this one !!! */
3389 static int ep_can_grow[] =
3401 static int ep_active_bomb[] =
3404 EL_DYNABOMB_PLAYER_1_ACTIVE,
3405 EL_DYNABOMB_PLAYER_2_ACTIVE,
3406 EL_DYNABOMB_PLAYER_3_ACTIVE,
3407 EL_DYNABOMB_PLAYER_4_ACTIVE,
3408 EL_SP_DISK_RED_ACTIVE,
3412 static int ep_inactive[] =
3461 EL_INVISIBLE_STEELWALL,
3469 EL_WALL_EMERALD_YELLOW,
3470 EL_DYNABOMB_INCREASE_NUMBER,
3471 EL_DYNABOMB_INCREASE_SIZE,
3472 EL_DYNABOMB_INCREASE_POWER,
3476 EL_SOKOBAN_FIELD_EMPTY,
3477 EL_SOKOBAN_FIELD_FULL,
3478 EL_WALL_EMERALD_RED,
3479 EL_WALL_EMERALD_PURPLE,
3480 EL_ACID_POOL_TOPLEFT,
3481 EL_ACID_POOL_TOPRIGHT,
3482 EL_ACID_POOL_BOTTOMLEFT,
3483 EL_ACID_POOL_BOTTOM,
3484 EL_ACID_POOL_BOTTOMRIGHT,
3488 EL_BD_MAGIC_WALL_DEAD,
3489 EL_AMOEBA_TO_DIAMOND,
3497 EL_SP_GRAVITY_PORT_RIGHT,
3498 EL_SP_GRAVITY_PORT_DOWN,
3499 EL_SP_GRAVITY_PORT_LEFT,
3500 EL_SP_GRAVITY_PORT_UP,
3501 EL_SP_PORT_HORIZONTAL,
3502 EL_SP_PORT_VERTICAL,
3513 EL_SP_HARDWARE_GRAY,
3514 EL_SP_HARDWARE_GREEN,
3515 EL_SP_HARDWARE_BLUE,
3517 EL_SP_HARDWARE_YELLOW,
3518 EL_SP_HARDWARE_BASE_1,
3519 EL_SP_HARDWARE_BASE_2,
3520 EL_SP_HARDWARE_BASE_3,
3521 EL_SP_HARDWARE_BASE_4,
3522 EL_SP_HARDWARE_BASE_5,
3523 EL_SP_HARDWARE_BASE_6,
3524 EL_SP_GRAVITY_ON_PORT_LEFT,
3525 EL_SP_GRAVITY_ON_PORT_RIGHT,
3526 EL_SP_GRAVITY_ON_PORT_UP,
3527 EL_SP_GRAVITY_ON_PORT_DOWN,
3528 EL_SP_GRAVITY_OFF_PORT_LEFT,
3529 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3530 EL_SP_GRAVITY_OFF_PORT_UP,
3531 EL_SP_GRAVITY_OFF_PORT_DOWN,
3532 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3533 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3534 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3535 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3536 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3537 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3538 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3539 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3540 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3541 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3542 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3543 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3544 EL_SIGN_EXCLAMATION,
3545 EL_SIGN_RADIOACTIVITY,
3556 EL_STEELWALL_SLIPPERY,
3561 EL_EMC_WALL_SLIPPERY_1,
3562 EL_EMC_WALL_SLIPPERY_2,
3563 EL_EMC_WALL_SLIPPERY_3,
3564 EL_EMC_WALL_SLIPPERY_4,
3584 static int ep_em_slippery_wall[] =
3589 static int ep_gfx_crumbled[] =
3602 } element_properties[] =
3604 { ep_diggable, EP_DIGGABLE },
3605 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
3606 { ep_dont_run_into, EP_DONT_RUN_INTO },
3607 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
3608 { ep_dont_touch, EP_DONT_TOUCH },
3609 { ep_indestructible, EP_INDESTRUCTIBLE },
3610 { ep_slippery, EP_SLIPPERY },
3611 { ep_can_change, EP_CAN_CHANGE },
3612 { ep_can_move, EP_CAN_MOVE },
3613 { ep_can_fall, EP_CAN_FALL },
3614 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
3615 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
3616 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
3617 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
3618 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
3619 { ep_explodes_impact, EP_EXPLODES_IMPACT },
3620 { ep_walkable_over, EP_WALKABLE_OVER },
3621 { ep_walkable_inside, EP_WALKABLE_INSIDE },
3622 { ep_walkable_under, EP_WALKABLE_UNDER },
3623 { ep_passable_over, EP_PASSABLE_OVER },
3624 { ep_passable_inside, EP_PASSABLE_INSIDE },
3625 { ep_passable_under, EP_PASSABLE_UNDER },
3626 { ep_droppable, EP_DROPPABLE },
3627 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
3628 { ep_pushable, EP_PUSHABLE },
3629 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
3630 { ep_protected, EP_PROTECTED },
3631 { ep_throwable, EP_THROWABLE },
3632 { ep_can_explode, EP_CAN_EXPLODE },
3633 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
3635 { ep_player, EP_PLAYER },
3636 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
3637 { ep_switchable, EP_SWITCHABLE },
3638 { ep_bd_element, EP_BD_ELEMENT },
3639 { ep_sp_element, EP_SP_ELEMENT },
3640 { ep_sb_element, EP_SB_ELEMENT },
3642 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
3643 { ep_food_penguin, EP_FOOD_PENGUIN },
3644 { ep_food_pig, EP_FOOD_PIG },
3645 { ep_historic_wall, EP_HISTORIC_WALL },
3646 { ep_historic_solid, EP_HISTORIC_SOLID },
3647 { ep_classic_enemy, EP_CLASSIC_ENEMY },
3648 { ep_belt, EP_BELT },
3649 { ep_belt_active, EP_BELT_ACTIVE },
3650 { ep_belt_switch, EP_BELT_SWITCH },
3651 { ep_tube, EP_TUBE },
3652 { ep_keygate, EP_KEYGATE },
3653 { ep_amoeboid, EP_AMOEBOID },
3654 { ep_amoebalive, EP_AMOEBALIVE },
3655 { ep_has_content, EP_HAS_CONTENT },
3656 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
3657 { ep_can_grow, EP_CAN_GROW },
3658 { ep_active_bomb, EP_ACTIVE_BOMB },
3659 { ep_inactive, EP_INACTIVE },
3661 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
3663 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
3670 /* always start with reliable default values (element has no properties) */
3671 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3672 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
3673 SET_PROPERTY(i, j, FALSE);
3675 /* set all base element properties from above array definitions */
3676 for (i = 0; element_properties[i].elements != NULL; i++)
3677 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
3678 SET_PROPERTY((element_properties[i].elements)[j],
3679 element_properties[i].property, TRUE);
3681 /* copy properties to some elements that are only stored in level file */
3682 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
3683 for (j = 0; copy_properties[j][0] != -1; j++)
3684 if (HAS_PROPERTY(copy_properties[j][0], i))
3685 for (k = 1; k <= 4; k++)
3686 SET_PROPERTY(copy_properties[j][k], i, TRUE);
3689 void InitElementPropertiesEngine(int engine_version)
3692 static int active_properties[] =
3697 EP_DONT_COLLIDE_WITH,
3701 EP_CAN_PASS_MAGIC_WALL,
3706 EP_EXPLODES_BY_FIRE,
3719 EP_EM_SLIPPERY_WALL,
3723 static int no_wall_properties[] =
3726 EP_COLLECTIBLE_ONLY,
3728 EP_DONT_COLLIDE_WITH,
3731 EP_CAN_SMASH_PLAYER,
3732 EP_CAN_SMASH_ENEMIES,
3733 EP_CAN_SMASH_EVERYTHING,
3738 EP_FOOD_DARK_YAMYAM,
3755 InitElementPropertiesStatic();
3758 /* important: after initialization in InitElementPropertiesStatic(), the
3759 elements are not again initialized to a default value; therefore all
3760 changes have to make sure that they leave the element with a defined
3761 property (which means that conditional property changes must be set to
3762 a reliable default value before) */
3764 /* set all special, combined or engine dependent element properties */
3765 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3768 for (j = EP_ACCESSIBLE_OVER; j < NUM_ELEMENT_PROPERTIES; j++)
3769 SET_PROPERTY(i, j, FALSE);
3772 /* ---------- INACTIVE ------------------------------------------------- */
3773 SET_PROPERTY(i, EP_INACTIVE, (i >= EL_CHAR_START && i <= EL_CHAR_END));
3775 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
3776 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
3777 IS_WALKABLE_INSIDE(i) ||
3778 IS_WALKABLE_UNDER(i)));
3780 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
3781 IS_PASSABLE_INSIDE(i) ||
3782 IS_PASSABLE_UNDER(i)));
3784 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
3785 IS_PASSABLE_OVER(i)));
3787 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
3788 IS_PASSABLE_INSIDE(i)));
3790 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
3791 IS_PASSABLE_UNDER(i)));
3793 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
3796 /* ---------- COLLECTIBLE ---------------------------------------------- */
3797 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
3801 /* ---------- SNAPPABLE ------------------------------------------------ */
3802 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
3803 IS_COLLECTIBLE(i) ||
3807 /* ---------- WALL ----------------------------------------------------- */
3808 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
3810 for (j = 0; no_wall_properties[j] != -1; j++)
3811 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
3812 i >= EL_FIRST_RUNTIME_UNREAL)
3813 SET_PROPERTY(i, EP_WALL, FALSE);
3815 if (IS_HISTORIC_WALL(i))
3816 SET_PROPERTY(i, EP_WALL, TRUE);
3818 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
3819 if (engine_version < VERSION_IDENT(2,2,0,0))
3820 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
3822 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
3824 !IS_COLLECTIBLE(i)));
3827 /* ---------- PROTECTED ------------------------------------------------ */
3828 if (IS_ACCESSIBLE_INSIDE(i))
3829 SET_PROPERTY(i, EP_PROTECTED, TRUE);
3832 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
3834 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
3835 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
3837 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
3838 IS_INDESTRUCTIBLE(i)));
3840 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
3842 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
3843 else if (engine_version < VERSION_IDENT(2,2,0,0))
3844 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
3847 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3852 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3853 !IS_WALKABLE_OVER(i) &&
3854 !IS_WALKABLE_UNDER(i)));
3856 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3861 if (IS_CUSTOM_ELEMENT(i))
3863 /* these are additional properties which are initially false when set */
3865 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
3867 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
3868 if (DONT_COLLIDE_WITH(i))
3869 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
3871 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
3872 if (CAN_SMASH_EVERYTHING(i))
3873 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
3874 if (CAN_SMASH_ENEMIES(i))
3875 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
3878 /* ---------- CAN_SMASH ------------------------------------------------ */
3879 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
3880 CAN_SMASH_ENEMIES(i) ||
3881 CAN_SMASH_EVERYTHING(i)));
3884 /* ---------- CAN_EXPLODE ---------------------------------------------- */
3885 SET_PROPERTY(i, EP_CAN_EXPLODE, (CAN_EXPLODE_BY_FIRE(i) ||
3886 CAN_EXPLODE_SMASHED(i) ||
3887 CAN_EXPLODE_IMPACT(i)));
3891 /* ---------- CAN_EXPLODE_3X3 ------------------------------------------ */
3893 SET_PROPERTY(i, EP_CAN_EXPLODE_3X3, (!CAN_EXPLODE_1X1(i) &&
3894 !CAN_EXPLODE_CROSS(i)));
3896 SET_PROPERTY(i, EP_CAN_EXPLODE_3X3, (CAN_EXPLODE(i) &&
3897 !CAN_EXPLODE_1X1(i) &&
3898 !CAN_EXPLODE_CROSS(i)));
3902 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
3903 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
3904 EXPLODES_BY_FIRE(i)));
3906 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
3907 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
3908 EXPLODES_SMASHED(i)));
3910 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
3911 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
3912 EXPLODES_IMPACT(i)));
3914 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
3915 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
3917 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
3918 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
3919 i == EL_BLACK_ORB));
3921 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
3922 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
3924 IS_CUSTOM_ELEMENT(i)));
3926 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
3927 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
3928 i == EL_SP_ELECTRON));
3930 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
3931 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
3932 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
3933 getMoveIntoAcidProperty(&level, i));
3935 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
3936 if (MAYBE_DONT_COLLIDE_WITH(i))
3937 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
3938 getDontCollideWithProperty(&level, i));
3940 /* ---------- SP_PORT -------------------------------------------------- */
3941 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
3942 IS_PASSABLE_INSIDE(i)));
3944 /* ---------- CAN_CHANGE ----------------------------------------------- */
3945 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
3946 for (j = 0; j < element_info[i].num_change_pages; j++)
3947 if (element_info[i].change_page[j].can_change)
3948 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
3950 /* ---------- GFX_CRUMBLED --------------------------------------------- */
3952 SET_PROPERTY(i, EP_GFX_CRUMBLED,
3953 element_info[i].crumbled[ACTION_DEFAULT] !=
3954 element_info[i].graphic[ACTION_DEFAULT]);
3956 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
3957 SET_PROPERTY(i, EP_GFX_CRUMBLED,
3958 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
3963 /* determine inactive elements (used for engine main loop optimization) */
3964 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3966 boolean active = FALSE;
3968 for (j = 0; i < NUM_ELEMENT_PROPERTIES; j++)
3970 if (HAS_PROPERTY(i, j))
3976 SET_PROPERTY(i, EP_INACTIVE, TRUE);
3981 /* dynamically adjust element properties according to game engine version */
3983 static int ep_em_slippery_wall[] =
3988 EL_EXPANDABLE_WALL_HORIZONTAL,
3989 EL_EXPANDABLE_WALL_VERTICAL,
3990 EL_EXPANDABLE_WALL_ANY,
3994 /* special EM style gems behaviour */
3995 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
3996 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
3997 level.em_slippery_gems);
3999 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4000 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4001 (level.em_slippery_gems &&
4002 engine_version > VERSION_IDENT(2,0,1,0)));
4006 /* set default push delay values (corrected since version 3.0.7-1) */
4007 if (engine_version < VERSION_IDENT(3,0,7,1))
4009 game.default_push_delay_fixed = 2;
4010 game.default_push_delay_random = 8;
4014 game.default_push_delay_fixed = 8;
4015 game.default_push_delay_random = 8;
4018 /* set uninitialized push delay values of custom elements in older levels */
4019 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4021 int element = EL_CUSTOM_START + i;
4023 if (element_info[element].push_delay_fixed == -1)
4024 element_info[element].push_delay_fixed = game.default_push_delay_fixed;
4025 if (element_info[element].push_delay_random == -1)
4026 element_info[element].push_delay_random = game.default_push_delay_random;
4029 /* set some other uninitialized values of custom elements in older levels */
4030 if (engine_version < VERSION_IDENT(3,1,0,0))
4032 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4034 int element = EL_CUSTOM_START + i;
4036 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4038 element_info[element].explosion_delay = 17;
4039 element_info[element].ignition_delay = 8;
4044 /* set element properties that were handled incorrectly in older levels */
4045 if (engine_version < VERSION_IDENT(3,1,0,0))
4047 SET_PROPERTY(EL_SP_SNIKSNAK, EP_DONT_COLLIDE_WITH, FALSE);
4048 SET_PROPERTY(EL_SP_ELECTRON, EP_DONT_COLLIDE_WITH, FALSE);
4054 /* this is needed because some graphics depend on element properties */
4055 if (game_status == GAME_MODE_PLAYING)
4056 InitElementGraphicInfo();
4059 static void InitGlobal()
4063 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4065 /* check if element_name_info entry defined for each element in "main.h" */
4066 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4067 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4069 element_info[i].token_name = element_name_info[i].token_name;
4070 element_info[i].class_name = element_name_info[i].class_name;
4071 element_info[i].editor_description=element_name_info[i].editor_description;
4074 global.autoplay_leveldir = NULL;
4075 global.convert_leveldir = NULL;
4077 global.frames_per_second = 0;
4078 global.fps_slowdown = FALSE;
4079 global.fps_slowdown_factor = 1;
4082 void Execute_Command(char *command)
4086 if (strcmp(command, "print graphicsinfo.conf") == 0)
4088 printf("# You can configure additional/alternative image files here.\n");
4089 printf("# (The entries below are default and therefore commented out.)\n");
4091 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4093 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4096 for (i = 0; image_config[i].token != NULL; i++)
4097 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
4098 image_config[i].value));
4102 else if (strcmp(command, "print soundsinfo.conf") == 0)
4104 printf("# You can configure additional/alternative sound files here.\n");
4105 printf("# (The entries below are default and therefore commented out.)\n");
4107 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4109 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4112 for (i = 0; sound_config[i].token != NULL; i++)
4113 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4114 sound_config[i].value));
4118 else if (strcmp(command, "print musicinfo.conf") == 0)
4120 printf("# You can configure additional/alternative music files here.\n");
4121 printf("# (The entries below are default and therefore commented out.)\n");
4123 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4125 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4128 for (i = 0; music_config[i].token != NULL; i++)
4129 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
4130 music_config[i].value));
4134 else if (strcmp(command, "print editorsetup.conf") == 0)
4136 printf("# You can configure your personal editor element list here.\n");
4137 printf("# (The entries below are default and therefore commented out.)\n");
4140 PrintEditorElementList();
4144 else if (strcmp(command, "print helpanim.conf") == 0)
4146 printf("# You can configure different element help animations here.\n");
4147 printf("# (The entries below are default and therefore commented out.)\n");
4150 for (i = 0; helpanim_config[i].token != NULL; i++)
4152 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4153 helpanim_config[i].value));
4155 if (strcmp(helpanim_config[i].token, "end") == 0)
4161 else if (strcmp(command, "print helptext.conf") == 0)
4163 printf("# You can configure different element help text here.\n");
4164 printf("# (The entries below are default and therefore commented out.)\n");
4167 for (i = 0; helptext_config[i].token != NULL; i++)
4168 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4169 helptext_config[i].value));
4173 else if (strncmp(command, "dump level ", 11) == 0)
4175 char *filename = &command[11];
4177 if (!fileExists(filename))
4178 Error(ERR_EXIT, "cannot open file '%s'", filename);
4180 LoadLevelFromFilename(&level, filename);
4185 else if (strncmp(command, "dump tape ", 10) == 0)
4187 char *filename = &command[10];
4189 if (!fileExists(filename))
4190 Error(ERR_EXIT, "cannot open file '%s'", filename);
4192 LoadTapeFromFilename(filename);
4197 else if (strncmp(command, "autoplay ", 9) == 0)
4199 char *str_copy = getStringCopy(&command[9]);
4200 char *str_ptr = strchr(str_copy, ' ');
4202 global.autoplay_leveldir = str_copy;
4203 global.autoplay_level_nr = -1;
4205 if (str_ptr != NULL)
4207 *str_ptr++ = '\0'; /* terminate leveldir string */
4208 global.autoplay_level_nr = atoi(str_ptr); /* get level_nr value */
4211 else if (strncmp(command, "convert ", 8) == 0)
4213 char *str_copy = getStringCopy(&command[8]);
4214 char *str_ptr = strchr(str_copy, ' ');
4216 global.convert_leveldir = str_copy;
4217 global.convert_level_nr = -1;
4219 if (str_ptr != NULL)
4221 *str_ptr++ = '\0'; /* terminate leveldir string */
4222 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
4227 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4231 static void InitSetup()
4233 LoadSetup(); /* global setup info */
4235 /* set some options from setup file */
4237 if (setup.options.verbose)
4238 options.verbose = TRUE;
4241 static void InitPlayerInfo()
4245 /* choose default local player */
4246 local_player = &stored_player[0];
4248 for (i = 0; i < MAX_PLAYERS; i++)
4249 stored_player[i].connected = FALSE;
4251 local_player->connected = TRUE;
4254 static void InitArtworkInfo()
4259 static char *get_string_in_brackets(char *string)
4261 char *string_in_brackets = checked_malloc(strlen(string) + 3);
4263 sprintf(string_in_brackets, "[%s]", string);
4265 return string_in_brackets;
4268 static char *get_level_id_suffix(int id_nr)
4270 char *id_suffix = checked_malloc(1 + 3 + 1);
4272 if (id_nr < 0 || id_nr > 999)
4275 sprintf(id_suffix, ".%03d", id_nr);
4281 static char *get_element_class_token(int element)
4283 char *element_class_name = element_info[element].class_name;
4284 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
4286 sprintf(element_class_token, "[%s]", element_class_name);
4288 return element_class_token;
4291 static char *get_action_class_token(int action)
4293 char *action_class_name = &element_action_info[action].suffix[1];
4294 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
4296 sprintf(action_class_token, "[%s]", action_class_name);
4298 return action_class_token;
4302 static void InitArtworkConfig()
4304 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
4305 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
4306 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
4307 static char *action_id_suffix[NUM_ACTIONS + 1];
4308 static char *direction_id_suffix[NUM_DIRECTIONS + 1];
4309 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
4310 static char *level_id_suffix[MAX_LEVELS + 1];
4311 static char *dummy[1] = { NULL };
4312 static char *ignore_generic_tokens[] =
4318 static char **ignore_image_tokens;
4319 static char **ignore_sound_tokens;
4320 static char **ignore_music_tokens;
4321 int num_ignore_generic_tokens;
4322 int num_ignore_image_tokens;
4323 int num_ignore_sound_tokens;
4324 int num_ignore_music_tokens;
4327 /* dynamically determine list of generic tokens to be ignored */
4328 num_ignore_generic_tokens = 0;
4329 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
4330 num_ignore_generic_tokens++;
4332 /* dynamically determine list of image tokens to be ignored */
4333 num_ignore_image_tokens = num_ignore_generic_tokens;
4334 for (i = 0; image_config_vars[i].token != NULL; i++)
4335 num_ignore_image_tokens++;
4336 ignore_image_tokens =
4337 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
4338 for (i = 0; i < num_ignore_generic_tokens; i++)
4339 ignore_image_tokens[i] = ignore_generic_tokens[i];
4340 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
4341 ignore_image_tokens[num_ignore_generic_tokens + i] =
4342 image_config_vars[i].token;
4343 ignore_image_tokens[num_ignore_image_tokens] = NULL;
4345 /* dynamically determine list of sound tokens to be ignored */
4346 num_ignore_sound_tokens = num_ignore_generic_tokens;
4347 ignore_sound_tokens =
4348 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
4349 for (i = 0; i < num_ignore_generic_tokens; i++)
4350 ignore_sound_tokens[i] = ignore_generic_tokens[i];
4351 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
4353 /* dynamically determine list of music tokens to be ignored */
4354 num_ignore_music_tokens = num_ignore_generic_tokens;
4355 ignore_music_tokens =
4356 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
4357 for (i = 0; i < num_ignore_generic_tokens; i++)
4358 ignore_music_tokens[i] = ignore_generic_tokens[i];
4359 ignore_music_tokens[num_ignore_music_tokens] = NULL;
4361 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4362 image_id_prefix[i] = element_info[i].token_name;
4363 for (i = 0; i < NUM_FONTS; i++)
4364 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
4365 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
4367 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4368 sound_id_prefix[i] = element_info[i].token_name;
4369 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4370 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
4371 get_string_in_brackets(element_info[i].class_name);
4372 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
4374 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
4375 music_id_prefix[i] = music_prefix_info[i].prefix;
4376 music_id_prefix[MAX_LEVELS] = NULL;
4378 for (i = 0; i < NUM_ACTIONS; i++)
4379 action_id_suffix[i] = element_action_info[i].suffix;
4380 action_id_suffix[NUM_ACTIONS] = NULL;
4382 for (i = 0; i < NUM_DIRECTIONS; i++)
4383 direction_id_suffix[i] = element_direction_info[i].suffix;
4384 direction_id_suffix[NUM_DIRECTIONS] = NULL;
4386 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
4387 special_id_suffix[i] = special_suffix_info[i].suffix;
4388 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
4390 for (i = 0; i < MAX_LEVELS; i++)
4391 level_id_suffix[i] = get_level_id_suffix(i);
4392 level_id_suffix[MAX_LEVELS] = NULL;
4394 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
4395 image_id_prefix, action_id_suffix, direction_id_suffix,
4396 special_id_suffix, ignore_image_tokens);
4397 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
4398 sound_id_prefix, action_id_suffix, dummy,
4399 special_id_suffix, ignore_sound_tokens);
4400 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
4401 music_id_prefix, special_id_suffix, level_id_suffix,
4402 dummy, ignore_music_tokens);
4405 static void InitMixer()
4413 char *filename_font_initial = NULL;
4414 Bitmap *bitmap_font_initial = NULL;
4417 /* determine settings for initial font (for displaying startup messages) */
4418 for (i = 0; image_config[i].token != NULL; i++)
4420 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4422 char font_token[128];
4425 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
4426 len_font_token = strlen(font_token);
4428 if (strcmp(image_config[i].token, font_token) == 0)
4429 filename_font_initial = image_config[i].value;
4430 else if (strlen(image_config[i].token) > len_font_token &&
4431 strncmp(image_config[i].token, font_token, len_font_token) == 0)
4433 if (strcmp(&image_config[i].token[len_font_token], ".x") == 0)
4434 font_initial[j].src_x = atoi(image_config[i].value);
4435 else if (strcmp(&image_config[i].token[len_font_token], ".y") == 0)
4436 font_initial[j].src_y = atoi(image_config[i].value);
4437 else if (strcmp(&image_config[i].token[len_font_token], ".width") == 0)
4438 font_initial[j].width = atoi(image_config[i].value);
4439 else if (strcmp(&image_config[i].token[len_font_token],".height") == 0)
4440 font_initial[j].height = atoi(image_config[i].value);
4445 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4447 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
4448 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
4451 if (filename_font_initial == NULL) /* should not happen */
4452 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
4454 /* create additional image buffers for double-buffering */
4455 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
4456 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
4458 /* initialize screen properties */
4459 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
4460 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
4462 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
4463 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
4464 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
4466 bitmap_font_initial = LoadCustomImage(filename_font_initial);
4468 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4469 font_initial[j].bitmap = bitmap_font_initial;
4471 InitFontGraphicInfo();
4473 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
4474 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
4476 DrawInitText("Loading graphics:", 120, FC_GREEN);
4478 InitTileClipmasks();
4481 void InitGfxBackground()
4485 drawto = backbuffer;
4486 fieldbuffer = bitmap_db_field;
4487 SetDrawtoField(DRAW_BACKBUFFER);
4489 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
4490 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
4491 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
4492 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
4494 for (x = 0; x < MAX_BUF_XSIZE; x++)
4495 for (y = 0; y < MAX_BUF_YSIZE; y++)
4498 redraw_mask = REDRAW_ALL;
4501 static void InitLevelInfo()
4503 LoadLevelInfo(); /* global level info */
4504 LoadLevelSetup_LastSeries(); /* last played series info */
4505 LoadLevelSetup_SeriesInfo(); /* last played level info */
4508 void InitLevelArtworkInfo()
4510 LoadLevelArtworkInfo();
4513 static void InitImages()
4516 setLevelArtworkDir(artwork.gfx_first);
4520 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
4521 leveldir_current->identifier,
4522 artwork.gfx_current_identifier,
4523 artwork.gfx_current->identifier,
4524 leveldir_current->graphics_set,
4525 leveldir_current->graphics_path);
4528 ReloadCustomImages();
4530 LoadCustomElementDescriptions();
4531 LoadSpecialMenuDesignSettings();
4533 ReinitializeGraphics();
4536 static void InitSound(char *identifier)
4538 if (identifier == NULL)
4539 identifier = artwork.snd_current->identifier;
4542 /* set artwork path to send it to the sound server process */
4543 setLevelArtworkDir(artwork.snd_first);
4546 InitReloadCustomSounds(identifier);
4547 ReinitializeSounds();
4550 static void InitMusic(char *identifier)
4552 if (identifier == NULL)
4553 identifier = artwork.mus_current->identifier;
4556 /* set artwork path to send it to the sound server process */
4557 setLevelArtworkDir(artwork.mus_first);
4560 InitReloadCustomMusic(identifier);
4561 ReinitializeMusic();
4564 void InitNetworkServer()
4566 #if defined(NETWORK_AVALIABLE)
4570 if (!options.network)
4573 #if defined(NETWORK_AVALIABLE)
4574 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
4576 if (!ConnectToServer(options.server_host, options.server_port))
4577 Error(ERR_EXIT, "cannot connect to network game server");
4579 SendToServer_PlayerName(setup.player_name);
4580 SendToServer_ProtocolVersion();
4583 SendToServer_NrWanted(nr_wanted);
4587 static char *getNewArtworkIdentifier(int type)
4589 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
4590 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
4591 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
4592 static boolean initialized[3] = { FALSE, FALSE, FALSE };
4593 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
4594 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
4595 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
4596 char *leveldir_identifier = leveldir_current->identifier;
4598 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
4599 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
4601 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
4603 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
4604 char *artwork_current_identifier;
4605 char *artwork_new_identifier = NULL; /* default: nothing has changed */
4607 /* leveldir_current may be invalid (level group, parent link) */
4608 if (!validLevelSeries(leveldir_current))
4611 /* 1st step: determine artwork set to be activated in descending order:
4612 --------------------------------------------------------------------
4613 1. setup artwork (when configured to override everything else)
4614 2. artwork set configured in "levelinfo.conf" of current level set
4615 (artwork in level directory will have priority when loading later)
4616 3. artwork in level directory (stored in artwork sub-directory)
4617 4. setup artwork (currently configured in setup menu) */
4619 if (setup_override_artwork)
4620 artwork_current_identifier = setup_artwork_set;
4621 else if (leveldir_artwork_set != NULL)
4622 artwork_current_identifier = leveldir_artwork_set;
4623 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
4624 artwork_current_identifier = leveldir_identifier;
4626 artwork_current_identifier = setup_artwork_set;
4629 /* 2nd step: check if it is really needed to reload artwork set
4630 ------------------------------------------------------------ */
4633 if (type == ARTWORK_TYPE_GRAPHICS)
4634 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
4635 artwork_new_identifier,
4636 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4637 artwork_current_identifier,
4638 leveldir_current->graphics_set,
4639 leveldir_current->identifier);
4642 /* ---------- reload if level set and also artwork set has changed ------- */
4643 if (leveldir_current_identifier[type] != leveldir_identifier &&
4644 (last_has_level_artwork_set[type] || has_level_artwork_set))
4645 artwork_new_identifier = artwork_current_identifier;
4647 leveldir_current_identifier[type] = leveldir_identifier;
4648 last_has_level_artwork_set[type] = has_level_artwork_set;
4651 if (type == ARTWORK_TYPE_GRAPHICS)
4652 printf("::: 1: '%s'\n", artwork_new_identifier);
4655 /* ---------- reload if "override artwork" setting has changed ----------- */
4656 if (last_override_level_artwork[type] != setup_override_artwork)
4657 artwork_new_identifier = artwork_current_identifier;
4659 last_override_level_artwork[type] = setup_override_artwork;
4662 if (type == ARTWORK_TYPE_GRAPHICS)
4663 printf("::: 2: '%s'\n", artwork_new_identifier);
4666 /* ---------- reload if current artwork identifier has changed ----------- */
4667 if (strcmp(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4668 artwork_current_identifier) != 0)
4669 artwork_new_identifier = artwork_current_identifier;
4671 *(&(ARTWORK_CURRENT_IDENTIFIER(artwork, type))) = artwork_current_identifier;
4674 if (type == ARTWORK_TYPE_GRAPHICS)
4675 printf("::: 3: '%s'\n", artwork_new_identifier);
4678 /* ---------- do not reload directly after starting ---------------------- */
4679 if (!initialized[type])
4680 artwork_new_identifier = NULL;
4682 initialized[type] = TRUE;
4685 if (type == ARTWORK_TYPE_GRAPHICS)
4686 printf("::: 4: '%s'\n", artwork_new_identifier);
4690 if (type == ARTWORK_TYPE_GRAPHICS)
4691 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
4692 artwork.gfx_current_identifier, artwork_current_identifier,
4693 artwork.gfx_current->identifier, leveldir_current->graphics_set,
4694 artwork_new_identifier);
4697 return artwork_new_identifier;
4700 void ReloadCustomArtwork(int force_reload)
4702 char *gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
4703 char *snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
4704 char *mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
4705 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
4706 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
4707 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
4708 boolean redraw_screen = FALSE;
4710 if (gfx_new_identifier != NULL || force_reload_gfx)
4713 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
4714 artwork.gfx_current_identifier,
4716 artwork.gfx_current->identifier,
4717 leveldir_current->graphics_set);
4720 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4725 printf("... '%s'\n",
4726 leveldir_current->graphics_set);
4729 FreeTileClipmasks();
4730 InitTileClipmasks();
4732 redraw_screen = TRUE;
4735 if (snd_new_identifier != NULL || force_reload_snd)
4737 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4739 InitSound(snd_new_identifier);
4741 redraw_screen = TRUE;
4744 if (mus_new_identifier != NULL || force_reload_mus)
4746 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4748 InitMusic(mus_new_identifier);
4750 redraw_screen = TRUE;
4755 InitGfxBackground();
4757 /* force redraw of (open or closed) door graphics */
4758 SetDoorState(DOOR_OPEN_ALL);
4759 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
4763 void KeyboardAutoRepeatOffUnlessAutoplay()
4765 if (global.autoplay_leveldir == NULL)
4766 KeyboardAutoRepeatOff();
4770 /* ========================================================================= */
4772 /* ========================================================================= */
4776 InitGlobal(); /* initialize some global variables */
4778 if (options.execute_command)
4779 Execute_Command(options.execute_command);
4781 if (options.serveronly)
4783 #if defined(PLATFORM_UNIX)
4784 NetworkServer(options.server_port, options.serveronly);
4786 Error(ERR_WARN, "networking only supported in Unix version");
4789 exit(0); /* never reached, server loops forever */
4795 InitArtworkInfo(); /* needed before loading gfx, sound & music */
4796 InitArtworkConfig(); /* needed before forking sound child process */
4801 InitRND(NEW_RANDOMIZE);
4802 InitSimpleRND(NEW_RANDOMIZE);
4807 InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
4810 InitEventFilter(FilterMouseMotionEvents);
4812 InitElementPropertiesStatic();
4813 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4818 InitLevelArtworkInfo();
4820 InitImages(); /* needs to know current level directory */
4821 InitSound(NULL); /* needs to know current level directory */
4822 InitMusic(NULL); /* needs to know current level directory */
4824 InitGfxBackground();
4826 if (global.autoplay_leveldir)
4831 else if (global.convert_leveldir)
4837 game_status = GAME_MODE_MAIN;
4845 InitNetworkServer();
4848 void CloseAllAndExit(int exit_value)
4853 CloseAudio(); /* called after freeing sounds (needed for SDL) */
4860 FreeTileClipmasks();
4862 #if defined(TARGET_SDL)
4863 if (network_server) /* terminate network server */
4864 SDL_KillThread(server_thread);
4867 CloseVideoDisplay();
4868 ClosePlatformDependentStuff();