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 EL_PLAYER_IS_LEAVING, /* needed for gravity + "block last field" */
2536 static int ep_walkable_inside[] =
2541 EL_TUBE_VERTICAL_LEFT,
2542 EL_TUBE_VERTICAL_RIGHT,
2543 EL_TUBE_HORIZONTAL_UP,
2544 EL_TUBE_HORIZONTAL_DOWN,
2552 static int ep_walkable_under[] =
2557 static int ep_passable_over[] =
2580 static int ep_passable_inside[] =
2586 EL_SP_PORT_HORIZONTAL,
2587 EL_SP_PORT_VERTICAL,
2589 EL_SP_GRAVITY_PORT_LEFT,
2590 EL_SP_GRAVITY_PORT_RIGHT,
2591 EL_SP_GRAVITY_PORT_UP,
2592 EL_SP_GRAVITY_PORT_DOWN,
2593 EL_SP_GRAVITY_ON_PORT_LEFT,
2594 EL_SP_GRAVITY_ON_PORT_RIGHT,
2595 EL_SP_GRAVITY_ON_PORT_UP,
2596 EL_SP_GRAVITY_ON_PORT_DOWN,
2597 EL_SP_GRAVITY_OFF_PORT_LEFT,
2598 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2599 EL_SP_GRAVITY_OFF_PORT_UP,
2600 EL_SP_GRAVITY_OFF_PORT_DOWN,
2604 static int ep_passable_under[] =
2609 static int ep_droppable[] =
2614 static int ep_explodes_1x1_old[] =
2619 static int ep_pushable[] =
2631 EL_SOKOBAN_FIELD_FULL,
2639 static int ep_explodes_cross_old[] =
2644 static int ep_protected[] =
2646 /* same elements as in 'ep_walkable_inside' */
2650 EL_TUBE_VERTICAL_LEFT,
2651 EL_TUBE_VERTICAL_RIGHT,
2652 EL_TUBE_HORIZONTAL_UP,
2653 EL_TUBE_HORIZONTAL_DOWN,
2659 /* same elements as in 'ep_passable_over' */
2679 /* same elements as in 'ep_passable_inside' */
2684 EL_SP_PORT_HORIZONTAL,
2685 EL_SP_PORT_VERTICAL,
2687 EL_SP_GRAVITY_PORT_LEFT,
2688 EL_SP_GRAVITY_PORT_RIGHT,
2689 EL_SP_GRAVITY_PORT_UP,
2690 EL_SP_GRAVITY_PORT_DOWN,
2691 EL_SP_GRAVITY_ON_PORT_LEFT,
2692 EL_SP_GRAVITY_ON_PORT_RIGHT,
2693 EL_SP_GRAVITY_ON_PORT_UP,
2694 EL_SP_GRAVITY_ON_PORT_DOWN,
2695 EL_SP_GRAVITY_OFF_PORT_LEFT,
2696 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2697 EL_SP_GRAVITY_OFF_PORT_UP,
2698 EL_SP_GRAVITY_OFF_PORT_DOWN,
2702 static int ep_throwable[] =
2707 static int ep_can_explode[] =
2709 /* same elements as in 'ep_explodes_impact' */
2714 /* same elements as in 'ep_explodes_smashed' */
2720 /* elements that can explode by explosion or by dragonfire */
2723 EL_DYNABOMB_PLAYER_1_ACTIVE,
2724 EL_DYNABOMB_PLAYER_2_ACTIVE,
2725 EL_DYNABOMB_PLAYER_3_ACTIVE,
2726 EL_DYNABOMB_PLAYER_4_ACTIVE,
2727 EL_DYNABOMB_INCREASE_NUMBER,
2728 EL_DYNABOMB_INCREASE_SIZE,
2729 EL_DYNABOMB_INCREASE_POWER,
2730 EL_SP_DISK_RED_ACTIVE,
2738 /* elements that can explode only by explosion */
2743 static int ep_gravity_reachable[] =
2749 EL_INVISIBLE_SAND_ACTIVE,
2754 EL_SP_PORT_HORIZONTAL,
2755 EL_SP_PORT_VERTICAL,
2757 EL_SP_GRAVITY_PORT_LEFT,
2758 EL_SP_GRAVITY_PORT_RIGHT,
2759 EL_SP_GRAVITY_PORT_UP,
2760 EL_SP_GRAVITY_PORT_DOWN,
2761 EL_SP_GRAVITY_ON_PORT_LEFT,
2762 EL_SP_GRAVITY_ON_PORT_RIGHT,
2763 EL_SP_GRAVITY_ON_PORT_UP,
2764 EL_SP_GRAVITY_ON_PORT_DOWN,
2765 EL_SP_GRAVITY_OFF_PORT_LEFT,
2766 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2767 EL_SP_GRAVITY_OFF_PORT_UP,
2768 EL_SP_GRAVITY_OFF_PORT_DOWN,
2773 static int ep_player[] =
2780 EL_SOKOBAN_FIELD_PLAYER,
2785 static int ep_can_pass_magic_wall[] =
2798 static int ep_switchable[] =
2802 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2803 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2804 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2805 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2806 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2807 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2808 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2809 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2810 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2811 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2812 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2813 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2814 EL_SWITCHGATE_SWITCH_UP,
2815 EL_SWITCHGATE_SWITCH_DOWN,
2817 EL_LIGHT_SWITCH_ACTIVE,
2819 EL_BALLOON_SWITCH_LEFT,
2820 EL_BALLOON_SWITCH_RIGHT,
2821 EL_BALLOON_SWITCH_UP,
2822 EL_BALLOON_SWITCH_DOWN,
2823 EL_BALLOON_SWITCH_ANY,
2826 EL_EMC_MAGIC_BALL_SWITCH,
2830 static int ep_bd_element[] =
2863 static int ep_sp_element[] =
2865 /* should always be valid */
2868 /* standard classic Supaplex elements */
2875 EL_SP_HARDWARE_GRAY,
2883 EL_SP_GRAVITY_PORT_RIGHT,
2884 EL_SP_GRAVITY_PORT_DOWN,
2885 EL_SP_GRAVITY_PORT_LEFT,
2886 EL_SP_GRAVITY_PORT_UP,
2891 EL_SP_PORT_VERTICAL,
2892 EL_SP_PORT_HORIZONTAL,
2898 EL_SP_HARDWARE_BASE_1,
2899 EL_SP_HARDWARE_GREEN,
2900 EL_SP_HARDWARE_BLUE,
2902 EL_SP_HARDWARE_YELLOW,
2903 EL_SP_HARDWARE_BASE_2,
2904 EL_SP_HARDWARE_BASE_3,
2905 EL_SP_HARDWARE_BASE_4,
2906 EL_SP_HARDWARE_BASE_5,
2907 EL_SP_HARDWARE_BASE_6,
2911 /* additional elements that appeared in newer Supaplex levels */
2914 /* additional gravity port elements (not switching, but setting gravity) */
2915 EL_SP_GRAVITY_ON_PORT_LEFT,
2916 EL_SP_GRAVITY_ON_PORT_RIGHT,
2917 EL_SP_GRAVITY_ON_PORT_UP,
2918 EL_SP_GRAVITY_ON_PORT_DOWN,
2919 EL_SP_GRAVITY_OFF_PORT_LEFT,
2920 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2921 EL_SP_GRAVITY_OFF_PORT_UP,
2922 EL_SP_GRAVITY_OFF_PORT_DOWN,
2924 /* more than one Murphy in a level results in an inactive clone */
2927 /* runtime Supaplex elements */
2928 EL_SP_DISK_RED_ACTIVE,
2929 EL_SP_TERMINAL_ACTIVE,
2930 EL_SP_BUGGY_BASE_ACTIVATING,
2931 EL_SP_BUGGY_BASE_ACTIVE,
2937 static int ep_sb_element[] =
2942 EL_SOKOBAN_FIELD_EMPTY,
2943 EL_SOKOBAN_FIELD_FULL,
2944 EL_SOKOBAN_FIELD_PLAYER,
2949 EL_INVISIBLE_STEELWALL,
2953 static int ep_gem[] =
2964 static int ep_food_dark_yamyam[] =
2991 static int ep_food_penguin[] =
3004 static int ep_food_pig[] =
3015 static int ep_historic_wall[] =
3040 EL_EXPANDABLE_WALL_HORIZONTAL,
3041 EL_EXPANDABLE_WALL_VERTICAL,
3042 EL_EXPANDABLE_WALL_ANY,
3043 EL_EXPANDABLE_WALL_GROWING,
3050 EL_SP_HARDWARE_GRAY,
3051 EL_SP_HARDWARE_GREEN,
3052 EL_SP_HARDWARE_BLUE,
3054 EL_SP_HARDWARE_YELLOW,
3055 EL_SP_HARDWARE_BASE_1,
3056 EL_SP_HARDWARE_BASE_2,
3057 EL_SP_HARDWARE_BASE_3,
3058 EL_SP_HARDWARE_BASE_4,
3059 EL_SP_HARDWARE_BASE_5,
3060 EL_SP_HARDWARE_BASE_6,
3062 EL_SP_TERMINAL_ACTIVE,
3065 EL_INVISIBLE_STEELWALL,
3066 EL_INVISIBLE_STEELWALL_ACTIVE,
3068 EL_INVISIBLE_WALL_ACTIVE,
3069 EL_STEELWALL_SLIPPERY,
3085 static int ep_historic_solid[] =
3089 EL_EXPANDABLE_WALL_HORIZONTAL,
3090 EL_EXPANDABLE_WALL_VERTICAL,
3091 EL_EXPANDABLE_WALL_ANY,
3104 EL_QUICKSAND_FILLING,
3105 EL_QUICKSAND_EMPTYING,
3107 EL_MAGIC_WALL_ACTIVE,
3108 EL_MAGIC_WALL_EMPTYING,
3109 EL_MAGIC_WALL_FILLING,
3113 EL_BD_MAGIC_WALL_ACTIVE,
3114 EL_BD_MAGIC_WALL_EMPTYING,
3115 EL_BD_MAGIC_WALL_FULL,
3116 EL_BD_MAGIC_WALL_FILLING,
3117 EL_BD_MAGIC_WALL_DEAD,
3126 EL_SP_TERMINAL_ACTIVE,
3130 EL_INVISIBLE_WALL_ACTIVE,
3131 EL_SWITCHGATE_SWITCH_UP,
3132 EL_SWITCHGATE_SWITCH_DOWN,
3134 EL_TIMEGATE_SWITCH_ACTIVE,
3146 /* the following elements are a direct copy of "indestructible" elements,
3147 except "EL_ACID", which is "indestructible", but not "solid"! */
3152 EL_ACID_POOL_TOPLEFT,
3153 EL_ACID_POOL_TOPRIGHT,
3154 EL_ACID_POOL_BOTTOMLEFT,
3155 EL_ACID_POOL_BOTTOM,
3156 EL_ACID_POOL_BOTTOMRIGHT,
3157 EL_SP_HARDWARE_GRAY,
3158 EL_SP_HARDWARE_GREEN,
3159 EL_SP_HARDWARE_BLUE,
3161 EL_SP_HARDWARE_YELLOW,
3162 EL_SP_HARDWARE_BASE_1,
3163 EL_SP_HARDWARE_BASE_2,
3164 EL_SP_HARDWARE_BASE_3,
3165 EL_SP_HARDWARE_BASE_4,
3166 EL_SP_HARDWARE_BASE_5,
3167 EL_SP_HARDWARE_BASE_6,
3168 EL_INVISIBLE_STEELWALL,
3169 EL_INVISIBLE_STEELWALL_ACTIVE,
3170 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3171 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3172 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3173 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3174 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3175 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3176 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3177 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3178 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3179 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3180 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3181 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3183 EL_LIGHT_SWITCH_ACTIVE,
3184 EL_SIGN_EXCLAMATION,
3185 EL_SIGN_RADIOACTIVITY,
3196 EL_STEELWALL_SLIPPERY,
3219 EL_SWITCHGATE_OPENING,
3220 EL_SWITCHGATE_CLOSED,
3221 EL_SWITCHGATE_CLOSING,
3223 EL_TIMEGATE_OPENING,
3225 EL_TIMEGATE_CLOSING,
3229 EL_TUBE_VERTICAL_LEFT,
3230 EL_TUBE_VERTICAL_RIGHT,
3231 EL_TUBE_HORIZONTAL_UP,
3232 EL_TUBE_HORIZONTAL_DOWN,
3240 static int ep_classic_enemy[] =
3256 static int ep_belt[] =
3258 EL_CONVEYOR_BELT_1_LEFT,
3259 EL_CONVEYOR_BELT_1_MIDDLE,
3260 EL_CONVEYOR_BELT_1_RIGHT,
3261 EL_CONVEYOR_BELT_2_LEFT,
3262 EL_CONVEYOR_BELT_2_MIDDLE,
3263 EL_CONVEYOR_BELT_2_RIGHT,
3264 EL_CONVEYOR_BELT_3_LEFT,
3265 EL_CONVEYOR_BELT_3_MIDDLE,
3266 EL_CONVEYOR_BELT_3_RIGHT,
3267 EL_CONVEYOR_BELT_4_LEFT,
3268 EL_CONVEYOR_BELT_4_MIDDLE,
3269 EL_CONVEYOR_BELT_4_RIGHT,
3273 static int ep_belt_active[] =
3275 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3276 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3277 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3278 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3279 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3280 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3281 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3282 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3283 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3284 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3285 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3286 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3290 static int ep_belt_switch[] =
3292 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3293 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3294 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3295 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3296 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3297 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3298 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3299 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3300 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3301 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3302 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3303 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3307 static int ep_tube[] =
3314 EL_TUBE_HORIZONTAL_UP,
3315 EL_TUBE_HORIZONTAL_DOWN,
3317 EL_TUBE_VERTICAL_LEFT,
3318 EL_TUBE_VERTICAL_RIGHT,
3323 static int ep_keygate[] =
3352 static int ep_amoeboid[] =
3362 static int ep_amoebalive[] =
3371 static int ep_has_content[] =
3381 static int ep_can_turn_each_move[] =
3383 /* !!! do something with this one !!! */
3387 static int ep_can_grow[] =
3399 static int ep_active_bomb[] =
3402 EL_DYNABOMB_PLAYER_1_ACTIVE,
3403 EL_DYNABOMB_PLAYER_2_ACTIVE,
3404 EL_DYNABOMB_PLAYER_3_ACTIVE,
3405 EL_DYNABOMB_PLAYER_4_ACTIVE,
3406 EL_SP_DISK_RED_ACTIVE,
3410 static int ep_inactive[] =
3459 EL_INVISIBLE_STEELWALL,
3467 EL_WALL_EMERALD_YELLOW,
3468 EL_DYNABOMB_INCREASE_NUMBER,
3469 EL_DYNABOMB_INCREASE_SIZE,
3470 EL_DYNABOMB_INCREASE_POWER,
3474 EL_SOKOBAN_FIELD_EMPTY,
3475 EL_SOKOBAN_FIELD_FULL,
3476 EL_WALL_EMERALD_RED,
3477 EL_WALL_EMERALD_PURPLE,
3478 EL_ACID_POOL_TOPLEFT,
3479 EL_ACID_POOL_TOPRIGHT,
3480 EL_ACID_POOL_BOTTOMLEFT,
3481 EL_ACID_POOL_BOTTOM,
3482 EL_ACID_POOL_BOTTOMRIGHT,
3486 EL_BD_MAGIC_WALL_DEAD,
3487 EL_AMOEBA_TO_DIAMOND,
3495 EL_SP_GRAVITY_PORT_RIGHT,
3496 EL_SP_GRAVITY_PORT_DOWN,
3497 EL_SP_GRAVITY_PORT_LEFT,
3498 EL_SP_GRAVITY_PORT_UP,
3499 EL_SP_PORT_HORIZONTAL,
3500 EL_SP_PORT_VERTICAL,
3511 EL_SP_HARDWARE_GRAY,
3512 EL_SP_HARDWARE_GREEN,
3513 EL_SP_HARDWARE_BLUE,
3515 EL_SP_HARDWARE_YELLOW,
3516 EL_SP_HARDWARE_BASE_1,
3517 EL_SP_HARDWARE_BASE_2,
3518 EL_SP_HARDWARE_BASE_3,
3519 EL_SP_HARDWARE_BASE_4,
3520 EL_SP_HARDWARE_BASE_5,
3521 EL_SP_HARDWARE_BASE_6,
3522 EL_SP_GRAVITY_ON_PORT_LEFT,
3523 EL_SP_GRAVITY_ON_PORT_RIGHT,
3524 EL_SP_GRAVITY_ON_PORT_UP,
3525 EL_SP_GRAVITY_ON_PORT_DOWN,
3526 EL_SP_GRAVITY_OFF_PORT_LEFT,
3527 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3528 EL_SP_GRAVITY_OFF_PORT_UP,
3529 EL_SP_GRAVITY_OFF_PORT_DOWN,
3530 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3531 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3532 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3533 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3534 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3535 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3536 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3537 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3538 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3539 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3540 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3541 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3542 EL_SIGN_EXCLAMATION,
3543 EL_SIGN_RADIOACTIVITY,
3554 EL_STEELWALL_SLIPPERY,
3559 EL_EMC_WALL_SLIPPERY_1,
3560 EL_EMC_WALL_SLIPPERY_2,
3561 EL_EMC_WALL_SLIPPERY_3,
3562 EL_EMC_WALL_SLIPPERY_4,
3582 static int ep_em_slippery_wall[] =
3587 static int ep_gfx_crumbled[] =
3600 } element_properties[] =
3602 { ep_diggable, EP_DIGGABLE },
3603 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
3604 { ep_dont_run_into, EP_DONT_RUN_INTO },
3605 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
3606 { ep_dont_touch, EP_DONT_TOUCH },
3607 { ep_indestructible, EP_INDESTRUCTIBLE },
3608 { ep_slippery, EP_SLIPPERY },
3609 { ep_can_change, EP_CAN_CHANGE },
3610 { ep_can_move, EP_CAN_MOVE },
3611 { ep_can_fall, EP_CAN_FALL },
3612 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
3613 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
3614 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
3615 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
3616 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
3617 { ep_explodes_impact, EP_EXPLODES_IMPACT },
3618 { ep_walkable_over, EP_WALKABLE_OVER },
3619 { ep_walkable_inside, EP_WALKABLE_INSIDE },
3620 { ep_walkable_under, EP_WALKABLE_UNDER },
3621 { ep_passable_over, EP_PASSABLE_OVER },
3622 { ep_passable_inside, EP_PASSABLE_INSIDE },
3623 { ep_passable_under, EP_PASSABLE_UNDER },
3624 { ep_droppable, EP_DROPPABLE },
3625 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
3626 { ep_pushable, EP_PUSHABLE },
3627 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
3628 { ep_protected, EP_PROTECTED },
3629 { ep_throwable, EP_THROWABLE },
3630 { ep_can_explode, EP_CAN_EXPLODE },
3631 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
3633 { ep_player, EP_PLAYER },
3634 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
3635 { ep_switchable, EP_SWITCHABLE },
3636 { ep_bd_element, EP_BD_ELEMENT },
3637 { ep_sp_element, EP_SP_ELEMENT },
3638 { ep_sb_element, EP_SB_ELEMENT },
3640 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
3641 { ep_food_penguin, EP_FOOD_PENGUIN },
3642 { ep_food_pig, EP_FOOD_PIG },
3643 { ep_historic_wall, EP_HISTORIC_WALL },
3644 { ep_historic_solid, EP_HISTORIC_SOLID },
3645 { ep_classic_enemy, EP_CLASSIC_ENEMY },
3646 { ep_belt, EP_BELT },
3647 { ep_belt_active, EP_BELT_ACTIVE },
3648 { ep_belt_switch, EP_BELT_SWITCH },
3649 { ep_tube, EP_TUBE },
3650 { ep_keygate, EP_KEYGATE },
3651 { ep_amoeboid, EP_AMOEBOID },
3652 { ep_amoebalive, EP_AMOEBALIVE },
3653 { ep_has_content, EP_HAS_CONTENT },
3654 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
3655 { ep_can_grow, EP_CAN_GROW },
3656 { ep_active_bomb, EP_ACTIVE_BOMB },
3657 { ep_inactive, EP_INACTIVE },
3659 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
3661 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
3668 /* always start with reliable default values (element has no properties) */
3669 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3670 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
3671 SET_PROPERTY(i, j, FALSE);
3673 /* set all base element properties from above array definitions */
3674 for (i = 0; element_properties[i].elements != NULL; i++)
3675 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
3676 SET_PROPERTY((element_properties[i].elements)[j],
3677 element_properties[i].property, TRUE);
3679 /* copy properties to some elements that are only stored in level file */
3680 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
3681 for (j = 0; copy_properties[j][0] != -1; j++)
3682 if (HAS_PROPERTY(copy_properties[j][0], i))
3683 for (k = 1; k <= 4; k++)
3684 SET_PROPERTY(copy_properties[j][k], i, TRUE);
3687 void InitElementPropertiesEngine(int engine_version)
3690 static int active_properties[] =
3695 EP_DONT_COLLIDE_WITH,
3699 EP_CAN_PASS_MAGIC_WALL,
3704 EP_EXPLODES_BY_FIRE,
3717 EP_EM_SLIPPERY_WALL,
3721 static int no_wall_properties[] =
3724 EP_COLLECTIBLE_ONLY,
3726 EP_DONT_COLLIDE_WITH,
3729 EP_CAN_SMASH_PLAYER,
3730 EP_CAN_SMASH_ENEMIES,
3731 EP_CAN_SMASH_EVERYTHING,
3736 EP_FOOD_DARK_YAMYAM,
3753 InitElementPropertiesStatic();
3756 /* important: after initialization in InitElementPropertiesStatic(), the
3757 elements are not again initialized to a default value; therefore all
3758 changes have to make sure that they leave the element with a defined
3759 property (which means that conditional property changes must be set to
3760 a reliable default value before) */
3762 /* set all special, combined or engine dependent element properties */
3763 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3766 for (j = EP_ACCESSIBLE_OVER; j < NUM_ELEMENT_PROPERTIES; j++)
3767 SET_PROPERTY(i, j, FALSE);
3770 /* ---------- INACTIVE ------------------------------------------------- */
3771 SET_PROPERTY(i, EP_INACTIVE, (i >= EL_CHAR_START && i <= EL_CHAR_END));
3773 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
3774 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
3775 IS_WALKABLE_INSIDE(i) ||
3776 IS_WALKABLE_UNDER(i)));
3778 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
3779 IS_PASSABLE_INSIDE(i) ||
3780 IS_PASSABLE_UNDER(i)));
3782 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
3783 IS_PASSABLE_OVER(i)));
3785 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
3786 IS_PASSABLE_INSIDE(i)));
3788 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
3789 IS_PASSABLE_UNDER(i)));
3791 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
3794 /* ---------- COLLECTIBLE ---------------------------------------------- */
3795 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
3799 /* ---------- SNAPPABLE ------------------------------------------------ */
3800 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
3801 IS_COLLECTIBLE(i) ||
3805 /* ---------- WALL ----------------------------------------------------- */
3806 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
3808 for (j = 0; no_wall_properties[j] != -1; j++)
3809 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
3810 i >= EL_FIRST_RUNTIME_UNREAL)
3811 SET_PROPERTY(i, EP_WALL, FALSE);
3813 if (IS_HISTORIC_WALL(i))
3814 SET_PROPERTY(i, EP_WALL, TRUE);
3816 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
3817 if (engine_version < VERSION_IDENT(2,2,0,0))
3818 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
3820 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
3822 !IS_COLLECTIBLE(i)));
3825 /* ---------- PROTECTED ------------------------------------------------ */
3826 if (IS_ACCESSIBLE_INSIDE(i))
3827 SET_PROPERTY(i, EP_PROTECTED, TRUE);
3830 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
3832 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
3833 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
3835 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
3836 IS_INDESTRUCTIBLE(i)));
3838 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
3840 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
3841 else if (engine_version < VERSION_IDENT(2,2,0,0))
3842 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
3845 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3850 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3851 !IS_WALKABLE_OVER(i) &&
3852 !IS_WALKABLE_UNDER(i)));
3854 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3859 if (IS_CUSTOM_ELEMENT(i))
3861 /* these are additional properties which are initially false when set */
3863 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
3865 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
3866 if (DONT_COLLIDE_WITH(i))
3867 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
3869 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
3870 if (CAN_SMASH_EVERYTHING(i))
3871 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
3872 if (CAN_SMASH_ENEMIES(i))
3873 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
3876 /* ---------- CAN_SMASH ------------------------------------------------ */
3877 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
3878 CAN_SMASH_ENEMIES(i) ||
3879 CAN_SMASH_EVERYTHING(i)));
3882 /* ---------- CAN_EXPLODE ---------------------------------------------- */
3883 SET_PROPERTY(i, EP_CAN_EXPLODE, (CAN_EXPLODE_BY_FIRE(i) ||
3884 CAN_EXPLODE_SMASHED(i) ||
3885 CAN_EXPLODE_IMPACT(i)));
3889 /* ---------- CAN_EXPLODE_3X3 ------------------------------------------ */
3891 SET_PROPERTY(i, EP_CAN_EXPLODE_3X3, (!CAN_EXPLODE_1X1(i) &&
3892 !CAN_EXPLODE_CROSS(i)));
3894 SET_PROPERTY(i, EP_CAN_EXPLODE_3X3, (CAN_EXPLODE(i) &&
3895 !CAN_EXPLODE_1X1(i) &&
3896 !CAN_EXPLODE_CROSS(i)));
3900 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
3901 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
3902 EXPLODES_BY_FIRE(i)));
3904 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
3905 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
3906 EXPLODES_SMASHED(i)));
3908 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
3909 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
3910 EXPLODES_IMPACT(i)));
3912 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
3913 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
3915 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
3916 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
3917 i == EL_BLACK_ORB));
3919 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
3920 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
3922 IS_CUSTOM_ELEMENT(i)));
3924 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
3925 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
3926 i == EL_SP_ELECTRON));
3928 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
3929 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
3930 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
3931 getMoveIntoAcidProperty(&level, i));
3933 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
3934 if (MAYBE_DONT_COLLIDE_WITH(i))
3935 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
3936 getDontCollideWithProperty(&level, i));
3938 /* ---------- SP_PORT -------------------------------------------------- */
3939 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
3940 IS_PASSABLE_INSIDE(i)));
3942 /* ---------- CAN_CHANGE ----------------------------------------------- */
3943 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
3944 for (j = 0; j < element_info[i].num_change_pages; j++)
3945 if (element_info[i].change_page[j].can_change)
3946 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
3948 /* ---------- GFX_CRUMBLED --------------------------------------------- */
3950 SET_PROPERTY(i, EP_GFX_CRUMBLED,
3951 element_info[i].crumbled[ACTION_DEFAULT] !=
3952 element_info[i].graphic[ACTION_DEFAULT]);
3954 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
3955 SET_PROPERTY(i, EP_GFX_CRUMBLED,
3956 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
3961 /* determine inactive elements (used for engine main loop optimization) */
3962 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3964 boolean active = FALSE;
3966 for (j = 0; i < NUM_ELEMENT_PROPERTIES; j++)
3968 if (HAS_PROPERTY(i, j))
3974 SET_PROPERTY(i, EP_INACTIVE, TRUE);
3979 /* dynamically adjust element properties according to game engine version */
3981 static int ep_em_slippery_wall[] =
3986 EL_EXPANDABLE_WALL_HORIZONTAL,
3987 EL_EXPANDABLE_WALL_VERTICAL,
3988 EL_EXPANDABLE_WALL_ANY,
3992 /* special EM style gems behaviour */
3993 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
3994 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
3995 level.em_slippery_gems);
3997 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
3998 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
3999 (level.em_slippery_gems &&
4000 engine_version > VERSION_IDENT(2,0,1,0)));
4004 /* set default push delay values (corrected since version 3.0.7-1) */
4005 if (engine_version < VERSION_IDENT(3,0,7,1))
4007 game.default_push_delay_fixed = 2;
4008 game.default_push_delay_random = 8;
4012 game.default_push_delay_fixed = 8;
4013 game.default_push_delay_random = 8;
4016 /* set uninitialized push delay values of custom elements in older levels */
4017 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4019 int element = EL_CUSTOM_START + i;
4021 if (element_info[element].push_delay_fixed == -1)
4022 element_info[element].push_delay_fixed = game.default_push_delay_fixed;
4023 if (element_info[element].push_delay_random == -1)
4024 element_info[element].push_delay_random = game.default_push_delay_random;
4027 /* set some other uninitialized values of custom elements in older levels */
4028 if (engine_version < VERSION_IDENT(3,1,0,0))
4030 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4032 int element = EL_CUSTOM_START + i;
4034 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4036 element_info[element].explosion_delay = 17;
4037 element_info[element].ignition_delay = 8;
4042 /* set element properties that were handled incorrectly in older levels */
4043 if (engine_version < VERSION_IDENT(3,1,0,0))
4045 SET_PROPERTY(EL_SP_SNIKSNAK, EP_DONT_COLLIDE_WITH, FALSE);
4046 SET_PROPERTY(EL_SP_ELECTRON, EP_DONT_COLLIDE_WITH, FALSE);
4052 /* this is needed because some graphics depend on element properties */
4053 if (game_status == GAME_MODE_PLAYING)
4054 InitElementGraphicInfo();
4057 static void InitGlobal()
4061 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4063 /* check if element_name_info entry defined for each element in "main.h" */
4064 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4065 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4067 element_info[i].token_name = element_name_info[i].token_name;
4068 element_info[i].class_name = element_name_info[i].class_name;
4069 element_info[i].editor_description=element_name_info[i].editor_description;
4072 global.autoplay_leveldir = NULL;
4073 global.convert_leveldir = NULL;
4075 global.frames_per_second = 0;
4076 global.fps_slowdown = FALSE;
4077 global.fps_slowdown_factor = 1;
4080 void Execute_Command(char *command)
4084 if (strcmp(command, "print graphicsinfo.conf") == 0)
4086 printf("# You can configure additional/alternative image files here.\n");
4087 printf("# (The entries below are default and therefore commented out.)\n");
4089 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4091 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4094 for (i = 0; image_config[i].token != NULL; i++)
4095 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
4096 image_config[i].value));
4100 else if (strcmp(command, "print soundsinfo.conf") == 0)
4102 printf("# You can configure additional/alternative sound files here.\n");
4103 printf("# (The entries below are default and therefore commented out.)\n");
4105 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4107 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4110 for (i = 0; sound_config[i].token != NULL; i++)
4111 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4112 sound_config[i].value));
4116 else if (strcmp(command, "print musicinfo.conf") == 0)
4118 printf("# You can configure additional/alternative music files here.\n");
4119 printf("# (The entries below are default and therefore commented out.)\n");
4121 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4123 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4126 for (i = 0; music_config[i].token != NULL; i++)
4127 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
4128 music_config[i].value));
4132 else if (strcmp(command, "print editorsetup.conf") == 0)
4134 printf("# You can configure your personal editor element list here.\n");
4135 printf("# (The entries below are default and therefore commented out.)\n");
4138 PrintEditorElementList();
4142 else if (strcmp(command, "print helpanim.conf") == 0)
4144 printf("# You can configure different element help animations here.\n");
4145 printf("# (The entries below are default and therefore commented out.)\n");
4148 for (i = 0; helpanim_config[i].token != NULL; i++)
4150 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4151 helpanim_config[i].value));
4153 if (strcmp(helpanim_config[i].token, "end") == 0)
4159 else if (strcmp(command, "print helptext.conf") == 0)
4161 printf("# You can configure different element help text here.\n");
4162 printf("# (The entries below are default and therefore commented out.)\n");
4165 for (i = 0; helptext_config[i].token != NULL; i++)
4166 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4167 helptext_config[i].value));
4171 else if (strncmp(command, "dump level ", 11) == 0)
4173 char *filename = &command[11];
4175 if (access(filename, F_OK) != 0)
4176 Error(ERR_EXIT, "cannot open file '%s'", filename);
4178 LoadLevelFromFilename(&level, filename);
4183 else if (strncmp(command, "dump tape ", 10) == 0)
4185 char *filename = &command[10];
4187 if (access(filename, F_OK) != 0)
4188 Error(ERR_EXIT, "cannot open file '%s'", filename);
4190 LoadTapeFromFilename(filename);
4195 else if (strncmp(command, "autoplay ", 9) == 0)
4197 char *str_copy = getStringCopy(&command[9]);
4198 char *str_ptr = strchr(str_copy, ' ');
4200 global.autoplay_leveldir = str_copy;
4201 global.autoplay_level_nr = -1;
4203 if (str_ptr != NULL)
4205 *str_ptr++ = '\0'; /* terminate leveldir string */
4206 global.autoplay_level_nr = atoi(str_ptr); /* get level_nr value */
4209 else if (strncmp(command, "convert ", 8) == 0)
4211 char *str_copy = getStringCopy(&command[8]);
4212 char *str_ptr = strchr(str_copy, ' ');
4214 global.convert_leveldir = str_copy;
4215 global.convert_level_nr = -1;
4217 if (str_ptr != NULL)
4219 *str_ptr++ = '\0'; /* terminate leveldir string */
4220 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
4225 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4229 static void InitSetup()
4231 LoadSetup(); /* global setup info */
4233 /* set some options from setup file */
4235 if (setup.options.verbose)
4236 options.verbose = TRUE;
4239 static void InitPlayerInfo()
4243 /* choose default local player */
4244 local_player = &stored_player[0];
4246 for (i = 0; i < MAX_PLAYERS; i++)
4247 stored_player[i].connected = FALSE;
4249 local_player->connected = TRUE;
4252 static void InitArtworkInfo()
4257 static char *get_string_in_brackets(char *string)
4259 char *string_in_brackets = checked_malloc(strlen(string) + 3);
4261 sprintf(string_in_brackets, "[%s]", string);
4263 return string_in_brackets;
4266 static char *get_level_id_suffix(int id_nr)
4268 char *id_suffix = checked_malloc(1 + 3 + 1);
4270 if (id_nr < 0 || id_nr > 999)
4273 sprintf(id_suffix, ".%03d", id_nr);
4279 static char *get_element_class_token(int element)
4281 char *element_class_name = element_info[element].class_name;
4282 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
4284 sprintf(element_class_token, "[%s]", element_class_name);
4286 return element_class_token;
4289 static char *get_action_class_token(int action)
4291 char *action_class_name = &element_action_info[action].suffix[1];
4292 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
4294 sprintf(action_class_token, "[%s]", action_class_name);
4296 return action_class_token;
4300 static void InitArtworkConfig()
4302 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
4303 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
4304 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
4305 static char *action_id_suffix[NUM_ACTIONS + 1];
4306 static char *direction_id_suffix[NUM_DIRECTIONS + 1];
4307 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
4308 static char *level_id_suffix[MAX_LEVELS + 1];
4309 static char *dummy[1] = { NULL };
4310 static char *ignore_generic_tokens[] =
4316 static char **ignore_image_tokens;
4317 static char **ignore_sound_tokens;
4318 static char **ignore_music_tokens;
4319 int num_ignore_generic_tokens;
4320 int num_ignore_image_tokens;
4321 int num_ignore_sound_tokens;
4322 int num_ignore_music_tokens;
4325 /* dynamically determine list of generic tokens to be ignored */
4326 num_ignore_generic_tokens = 0;
4327 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
4328 num_ignore_generic_tokens++;
4330 /* dynamically determine list of image tokens to be ignored */
4331 num_ignore_image_tokens = num_ignore_generic_tokens;
4332 for (i = 0; image_config_vars[i].token != NULL; i++)
4333 num_ignore_image_tokens++;
4334 ignore_image_tokens =
4335 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
4336 for (i = 0; i < num_ignore_generic_tokens; i++)
4337 ignore_image_tokens[i] = ignore_generic_tokens[i];
4338 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
4339 ignore_image_tokens[num_ignore_generic_tokens + i] =
4340 image_config_vars[i].token;
4341 ignore_image_tokens[num_ignore_image_tokens] = NULL;
4343 /* dynamically determine list of sound tokens to be ignored */
4344 num_ignore_sound_tokens = num_ignore_generic_tokens;
4345 ignore_sound_tokens =
4346 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
4347 for (i = 0; i < num_ignore_generic_tokens; i++)
4348 ignore_sound_tokens[i] = ignore_generic_tokens[i];
4349 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
4351 /* dynamically determine list of music tokens to be ignored */
4352 num_ignore_music_tokens = num_ignore_generic_tokens;
4353 ignore_music_tokens =
4354 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
4355 for (i = 0; i < num_ignore_generic_tokens; i++)
4356 ignore_music_tokens[i] = ignore_generic_tokens[i];
4357 ignore_music_tokens[num_ignore_music_tokens] = NULL;
4359 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4360 image_id_prefix[i] = element_info[i].token_name;
4361 for (i = 0; i < NUM_FONTS; i++)
4362 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
4363 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
4365 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4366 sound_id_prefix[i] = element_info[i].token_name;
4367 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4368 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
4369 get_string_in_brackets(element_info[i].class_name);
4370 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
4372 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
4373 music_id_prefix[i] = music_prefix_info[i].prefix;
4374 music_id_prefix[MAX_LEVELS] = NULL;
4376 for (i = 0; i < NUM_ACTIONS; i++)
4377 action_id_suffix[i] = element_action_info[i].suffix;
4378 action_id_suffix[NUM_ACTIONS] = NULL;
4380 for (i = 0; i < NUM_DIRECTIONS; i++)
4381 direction_id_suffix[i] = element_direction_info[i].suffix;
4382 direction_id_suffix[NUM_DIRECTIONS] = NULL;
4384 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
4385 special_id_suffix[i] = special_suffix_info[i].suffix;
4386 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
4388 for (i = 0; i < MAX_LEVELS; i++)
4389 level_id_suffix[i] = get_level_id_suffix(i);
4390 level_id_suffix[MAX_LEVELS] = NULL;
4392 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
4393 image_id_prefix, action_id_suffix, direction_id_suffix,
4394 special_id_suffix, ignore_image_tokens);
4395 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
4396 sound_id_prefix, action_id_suffix, dummy,
4397 special_id_suffix, ignore_sound_tokens);
4398 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
4399 music_id_prefix, special_id_suffix, level_id_suffix,
4400 dummy, ignore_music_tokens);
4403 static void InitMixer()
4411 char *filename_font_initial = NULL;
4412 Bitmap *bitmap_font_initial = NULL;
4415 /* determine settings for initial font (for displaying startup messages) */
4416 for (i = 0; image_config[i].token != NULL; i++)
4418 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4420 char font_token[128];
4423 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
4424 len_font_token = strlen(font_token);
4426 if (strcmp(image_config[i].token, font_token) == 0)
4427 filename_font_initial = image_config[i].value;
4428 else if (strlen(image_config[i].token) > len_font_token &&
4429 strncmp(image_config[i].token, font_token, len_font_token) == 0)
4431 if (strcmp(&image_config[i].token[len_font_token], ".x") == 0)
4432 font_initial[j].src_x = atoi(image_config[i].value);
4433 else if (strcmp(&image_config[i].token[len_font_token], ".y") == 0)
4434 font_initial[j].src_y = atoi(image_config[i].value);
4435 else if (strcmp(&image_config[i].token[len_font_token], ".width") == 0)
4436 font_initial[j].width = atoi(image_config[i].value);
4437 else if (strcmp(&image_config[i].token[len_font_token],".height") == 0)
4438 font_initial[j].height = atoi(image_config[i].value);
4443 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4445 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
4446 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
4449 if (filename_font_initial == NULL) /* should not happen */
4450 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
4452 /* create additional image buffers for double-buffering */
4453 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
4454 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
4456 /* initialize screen properties */
4457 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
4458 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
4460 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
4461 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
4462 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
4464 bitmap_font_initial = LoadCustomImage(filename_font_initial);
4466 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4467 font_initial[j].bitmap = bitmap_font_initial;
4469 InitFontGraphicInfo();
4471 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
4472 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
4474 DrawInitText("Loading graphics:", 120, FC_GREEN);
4476 InitTileClipmasks();
4479 void InitGfxBackground()
4483 drawto = backbuffer;
4484 fieldbuffer = bitmap_db_field;
4485 SetDrawtoField(DRAW_BACKBUFFER);
4487 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
4488 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
4489 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
4490 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
4492 for (x = 0; x < MAX_BUF_XSIZE; x++)
4493 for (y = 0; y < MAX_BUF_YSIZE; y++)
4496 redraw_mask = REDRAW_ALL;
4499 static void InitLevelInfo()
4501 LoadLevelInfo(); /* global level info */
4502 LoadLevelSetup_LastSeries(); /* last played series info */
4503 LoadLevelSetup_SeriesInfo(); /* last played level info */
4506 void InitLevelArtworkInfo()
4508 LoadLevelArtworkInfo();
4511 static void InitImages()
4514 setLevelArtworkDir(artwork.gfx_first);
4518 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
4519 leveldir_current->identifier,
4520 artwork.gfx_current_identifier,
4521 artwork.gfx_current->identifier,
4522 leveldir_current->graphics_set,
4523 leveldir_current->graphics_path);
4526 ReloadCustomImages();
4528 LoadCustomElementDescriptions();
4529 LoadSpecialMenuDesignSettings();
4531 ReinitializeGraphics();
4534 static void InitSound(char *identifier)
4536 if (identifier == NULL)
4537 identifier = artwork.snd_current->identifier;
4540 /* set artwork path to send it to the sound server process */
4541 setLevelArtworkDir(artwork.snd_first);
4544 InitReloadCustomSounds(identifier);
4545 ReinitializeSounds();
4548 static void InitMusic(char *identifier)
4550 if (identifier == NULL)
4551 identifier = artwork.mus_current->identifier;
4554 /* set artwork path to send it to the sound server process */
4555 setLevelArtworkDir(artwork.mus_first);
4558 InitReloadCustomMusic(identifier);
4559 ReinitializeMusic();
4562 void InitNetworkServer()
4564 #if defined(NETWORK_AVALIABLE)
4568 if (!options.network)
4571 #if defined(NETWORK_AVALIABLE)
4572 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
4574 if (!ConnectToServer(options.server_host, options.server_port))
4575 Error(ERR_EXIT, "cannot connect to network game server");
4577 SendToServer_PlayerName(setup.player_name);
4578 SendToServer_ProtocolVersion();
4581 SendToServer_NrWanted(nr_wanted);
4585 static char *getNewArtworkIdentifier(int type)
4587 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
4588 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
4589 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
4590 static boolean initialized[3] = { FALSE, FALSE, FALSE };
4591 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
4592 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
4593 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
4594 char *leveldir_identifier = leveldir_current->identifier;
4596 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
4597 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
4599 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
4601 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
4602 char *artwork_current_identifier;
4603 char *artwork_new_identifier = NULL; /* default: nothing has changed */
4605 /* leveldir_current may be invalid (level group, parent link) */
4606 if (!validLevelSeries(leveldir_current))
4609 /* 1st step: determine artwork set to be activated in descending order:
4610 --------------------------------------------------------------------
4611 1. setup artwork (when configured to override everything else)
4612 2. artwork set configured in "levelinfo.conf" of current level set
4613 (artwork in level directory will have priority when loading later)
4614 3. artwork in level directory (stored in artwork sub-directory)
4615 4. setup artwork (currently configured in setup menu) */
4617 if (setup_override_artwork)
4618 artwork_current_identifier = setup_artwork_set;
4619 else if (leveldir_artwork_set != NULL)
4620 artwork_current_identifier = leveldir_artwork_set;
4621 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
4622 artwork_current_identifier = leveldir_identifier;
4624 artwork_current_identifier = setup_artwork_set;
4627 /* 2nd step: check if it is really needed to reload artwork set
4628 ------------------------------------------------------------ */
4631 if (type == ARTWORK_TYPE_GRAPHICS)
4632 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
4633 artwork_new_identifier,
4634 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4635 artwork_current_identifier,
4636 leveldir_current->graphics_set,
4637 leveldir_current->identifier);
4640 /* ---------- reload if level set and also artwork set has changed ------- */
4641 if (leveldir_current_identifier[type] != leveldir_identifier &&
4642 (last_has_level_artwork_set[type] || has_level_artwork_set))
4643 artwork_new_identifier = artwork_current_identifier;
4645 leveldir_current_identifier[type] = leveldir_identifier;
4646 last_has_level_artwork_set[type] = has_level_artwork_set;
4649 if (type == ARTWORK_TYPE_GRAPHICS)
4650 printf("::: 1: '%s'\n", artwork_new_identifier);
4653 /* ---------- reload if "override artwork" setting has changed ----------- */
4654 if (last_override_level_artwork[type] != setup_override_artwork)
4655 artwork_new_identifier = artwork_current_identifier;
4657 last_override_level_artwork[type] = setup_override_artwork;
4660 if (type == ARTWORK_TYPE_GRAPHICS)
4661 printf("::: 2: '%s'\n", artwork_new_identifier);
4664 /* ---------- reload if current artwork identifier has changed ----------- */
4665 if (strcmp(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4666 artwork_current_identifier) != 0)
4667 artwork_new_identifier = artwork_current_identifier;
4669 *(&(ARTWORK_CURRENT_IDENTIFIER(artwork, type))) = artwork_current_identifier;
4672 if (type == ARTWORK_TYPE_GRAPHICS)
4673 printf("::: 3: '%s'\n", artwork_new_identifier);
4676 /* ---------- do not reload directly after starting ---------------------- */
4677 if (!initialized[type])
4678 artwork_new_identifier = NULL;
4680 initialized[type] = TRUE;
4683 if (type == ARTWORK_TYPE_GRAPHICS)
4684 printf("::: 4: '%s'\n", artwork_new_identifier);
4688 if (type == ARTWORK_TYPE_GRAPHICS)
4689 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
4690 artwork.gfx_current_identifier, artwork_current_identifier,
4691 artwork.gfx_current->identifier, leveldir_current->graphics_set,
4692 artwork_new_identifier);
4695 return artwork_new_identifier;
4698 void ReloadCustomArtwork(int force_reload)
4700 char *gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
4701 char *snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
4702 char *mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
4703 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
4704 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
4705 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
4706 boolean redraw_screen = FALSE;
4708 if (gfx_new_identifier != NULL || force_reload_gfx)
4711 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
4712 artwork.gfx_current_identifier,
4714 artwork.gfx_current->identifier,
4715 leveldir_current->graphics_set);
4718 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4723 printf("... '%s'\n",
4724 leveldir_current->graphics_set);
4727 FreeTileClipmasks();
4728 InitTileClipmasks();
4730 redraw_screen = TRUE;
4733 if (snd_new_identifier != NULL || force_reload_snd)
4735 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4737 InitSound(snd_new_identifier);
4739 redraw_screen = TRUE;
4742 if (mus_new_identifier != NULL || force_reload_mus)
4744 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4746 InitMusic(mus_new_identifier);
4748 redraw_screen = TRUE;
4753 InitGfxBackground();
4755 /* force redraw of (open or closed) door graphics */
4756 SetDoorState(DOOR_OPEN_ALL);
4757 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
4761 void KeyboardAutoRepeatOffUnlessAutoplay()
4763 if (global.autoplay_leveldir == NULL)
4764 KeyboardAutoRepeatOff();
4768 /* ========================================================================= */
4770 /* ========================================================================= */
4774 InitGlobal(); /* initialize some global variables */
4776 if (options.execute_command)
4777 Execute_Command(options.execute_command);
4779 if (options.serveronly)
4781 #if defined(PLATFORM_UNIX)
4782 NetworkServer(options.server_port, options.serveronly);
4784 Error(ERR_WARN, "networking only supported in Unix version");
4787 exit(0); /* never reached, server loops forever */
4793 InitArtworkInfo(); /* needed before loading gfx, sound & music */
4794 InitArtworkConfig(); /* needed before forking sound child process */
4799 InitRND(NEW_RANDOMIZE);
4800 InitSimpleRND(NEW_RANDOMIZE);
4805 InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
4808 InitEventFilter(FilterMouseMotionEvents);
4810 InitElementPropertiesStatic();
4811 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4816 InitLevelArtworkInfo();
4818 InitImages(); /* needs to know current level directory */
4819 InitSound(NULL); /* needs to know current level directory */
4820 InitMusic(NULL); /* needs to know current level directory */
4822 InitGfxBackground();
4824 if (global.autoplay_leveldir)
4829 else if (global.convert_leveldir)
4835 game_status = GAME_MODE_MAIN;
4843 InitNetworkServer();
4846 void CloseAllAndExit(int exit_value)
4851 CloseAudio(); /* called after freeing sounds (needed for SDL) */
4858 FreeTileClipmasks();
4860 #if defined(TARGET_SDL)
4861 if (network_server) /* terminate network server */
4862 SDL_KillThread(server_thread);
4865 CloseVideoDisplay();
4866 ClosePlatformDependentStuff();