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,
2533 #if 0 /* USE_GRAVITY_BUGFIX_OLD */
2534 EL_PLAYER_IS_LEAVING, /* needed for gravity + "block last field" */
2540 static int ep_walkable_inside[] =
2545 EL_TUBE_VERTICAL_LEFT,
2546 EL_TUBE_VERTICAL_RIGHT,
2547 EL_TUBE_HORIZONTAL_UP,
2548 EL_TUBE_HORIZONTAL_DOWN,
2556 static int ep_walkable_under[] =
2561 static int ep_passable_over[] =
2584 static int ep_passable_inside[] =
2590 EL_SP_PORT_HORIZONTAL,
2591 EL_SP_PORT_VERTICAL,
2593 EL_SP_GRAVITY_PORT_LEFT,
2594 EL_SP_GRAVITY_PORT_RIGHT,
2595 EL_SP_GRAVITY_PORT_UP,
2596 EL_SP_GRAVITY_PORT_DOWN,
2597 EL_SP_GRAVITY_ON_PORT_LEFT,
2598 EL_SP_GRAVITY_ON_PORT_RIGHT,
2599 EL_SP_GRAVITY_ON_PORT_UP,
2600 EL_SP_GRAVITY_ON_PORT_DOWN,
2601 EL_SP_GRAVITY_OFF_PORT_LEFT,
2602 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2603 EL_SP_GRAVITY_OFF_PORT_UP,
2604 EL_SP_GRAVITY_OFF_PORT_DOWN,
2608 static int ep_passable_under[] =
2613 static int ep_droppable[] =
2618 static int ep_explodes_1x1_old[] =
2623 static int ep_pushable[] =
2635 EL_SOKOBAN_FIELD_FULL,
2643 static int ep_explodes_cross_old[] =
2648 static int ep_protected[] =
2650 /* same elements as in 'ep_walkable_inside' */
2654 EL_TUBE_VERTICAL_LEFT,
2655 EL_TUBE_VERTICAL_RIGHT,
2656 EL_TUBE_HORIZONTAL_UP,
2657 EL_TUBE_HORIZONTAL_DOWN,
2663 /* same elements as in 'ep_passable_over' */
2683 /* same elements as in 'ep_passable_inside' */
2688 EL_SP_PORT_HORIZONTAL,
2689 EL_SP_PORT_VERTICAL,
2691 EL_SP_GRAVITY_PORT_LEFT,
2692 EL_SP_GRAVITY_PORT_RIGHT,
2693 EL_SP_GRAVITY_PORT_UP,
2694 EL_SP_GRAVITY_PORT_DOWN,
2695 EL_SP_GRAVITY_ON_PORT_LEFT,
2696 EL_SP_GRAVITY_ON_PORT_RIGHT,
2697 EL_SP_GRAVITY_ON_PORT_UP,
2698 EL_SP_GRAVITY_ON_PORT_DOWN,
2699 EL_SP_GRAVITY_OFF_PORT_LEFT,
2700 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2701 EL_SP_GRAVITY_OFF_PORT_UP,
2702 EL_SP_GRAVITY_OFF_PORT_DOWN,
2706 static int ep_throwable[] =
2711 static int ep_can_explode[] =
2713 /* same elements as in 'ep_explodes_impact' */
2718 /* same elements as in 'ep_explodes_smashed' */
2724 /* elements that can explode by explosion or by dragonfire */
2727 EL_DYNABOMB_PLAYER_1_ACTIVE,
2728 EL_DYNABOMB_PLAYER_2_ACTIVE,
2729 EL_DYNABOMB_PLAYER_3_ACTIVE,
2730 EL_DYNABOMB_PLAYER_4_ACTIVE,
2731 EL_DYNABOMB_INCREASE_NUMBER,
2732 EL_DYNABOMB_INCREASE_SIZE,
2733 EL_DYNABOMB_INCREASE_POWER,
2734 EL_SP_DISK_RED_ACTIVE,
2742 /* elements that can explode only by explosion */
2747 static int ep_gravity_reachable[] =
2753 EL_INVISIBLE_SAND_ACTIVE,
2758 EL_SP_PORT_HORIZONTAL,
2759 EL_SP_PORT_VERTICAL,
2761 EL_SP_GRAVITY_PORT_LEFT,
2762 EL_SP_GRAVITY_PORT_RIGHT,
2763 EL_SP_GRAVITY_PORT_UP,
2764 EL_SP_GRAVITY_PORT_DOWN,
2765 EL_SP_GRAVITY_ON_PORT_LEFT,
2766 EL_SP_GRAVITY_ON_PORT_RIGHT,
2767 EL_SP_GRAVITY_ON_PORT_UP,
2768 EL_SP_GRAVITY_ON_PORT_DOWN,
2769 EL_SP_GRAVITY_OFF_PORT_LEFT,
2770 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2771 EL_SP_GRAVITY_OFF_PORT_UP,
2772 EL_SP_GRAVITY_OFF_PORT_DOWN,
2777 static int ep_player[] =
2784 EL_SOKOBAN_FIELD_PLAYER,
2789 static int ep_can_pass_magic_wall[] =
2802 static int ep_switchable[] =
2806 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2807 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2808 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2809 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2810 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2811 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2812 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2813 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2814 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2815 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2816 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2817 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2818 EL_SWITCHGATE_SWITCH_UP,
2819 EL_SWITCHGATE_SWITCH_DOWN,
2821 EL_LIGHT_SWITCH_ACTIVE,
2823 EL_BALLOON_SWITCH_LEFT,
2824 EL_BALLOON_SWITCH_RIGHT,
2825 EL_BALLOON_SWITCH_UP,
2826 EL_BALLOON_SWITCH_DOWN,
2827 EL_BALLOON_SWITCH_ANY,
2830 EL_EMC_MAGIC_BALL_SWITCH,
2834 static int ep_bd_element[] =
2867 static int ep_sp_element[] =
2869 /* should always be valid */
2872 /* standard classic Supaplex elements */
2879 EL_SP_HARDWARE_GRAY,
2887 EL_SP_GRAVITY_PORT_RIGHT,
2888 EL_SP_GRAVITY_PORT_DOWN,
2889 EL_SP_GRAVITY_PORT_LEFT,
2890 EL_SP_GRAVITY_PORT_UP,
2895 EL_SP_PORT_VERTICAL,
2896 EL_SP_PORT_HORIZONTAL,
2902 EL_SP_HARDWARE_BASE_1,
2903 EL_SP_HARDWARE_GREEN,
2904 EL_SP_HARDWARE_BLUE,
2906 EL_SP_HARDWARE_YELLOW,
2907 EL_SP_HARDWARE_BASE_2,
2908 EL_SP_HARDWARE_BASE_3,
2909 EL_SP_HARDWARE_BASE_4,
2910 EL_SP_HARDWARE_BASE_5,
2911 EL_SP_HARDWARE_BASE_6,
2915 /* additional elements that appeared in newer Supaplex levels */
2918 /* additional gravity port elements (not switching, but setting gravity) */
2919 EL_SP_GRAVITY_ON_PORT_LEFT,
2920 EL_SP_GRAVITY_ON_PORT_RIGHT,
2921 EL_SP_GRAVITY_ON_PORT_UP,
2922 EL_SP_GRAVITY_ON_PORT_DOWN,
2923 EL_SP_GRAVITY_OFF_PORT_LEFT,
2924 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2925 EL_SP_GRAVITY_OFF_PORT_UP,
2926 EL_SP_GRAVITY_OFF_PORT_DOWN,
2928 /* more than one Murphy in a level results in an inactive clone */
2931 /* runtime Supaplex elements */
2932 EL_SP_DISK_RED_ACTIVE,
2933 EL_SP_TERMINAL_ACTIVE,
2934 EL_SP_BUGGY_BASE_ACTIVATING,
2935 EL_SP_BUGGY_BASE_ACTIVE,
2941 static int ep_sb_element[] =
2946 EL_SOKOBAN_FIELD_EMPTY,
2947 EL_SOKOBAN_FIELD_FULL,
2948 EL_SOKOBAN_FIELD_PLAYER,
2953 EL_INVISIBLE_STEELWALL,
2957 static int ep_gem[] =
2968 static int ep_food_dark_yamyam[] =
2995 static int ep_food_penguin[] =
3008 static int ep_food_pig[] =
3019 static int ep_historic_wall[] =
3044 EL_EXPANDABLE_WALL_HORIZONTAL,
3045 EL_EXPANDABLE_WALL_VERTICAL,
3046 EL_EXPANDABLE_WALL_ANY,
3047 EL_EXPANDABLE_WALL_GROWING,
3054 EL_SP_HARDWARE_GRAY,
3055 EL_SP_HARDWARE_GREEN,
3056 EL_SP_HARDWARE_BLUE,
3058 EL_SP_HARDWARE_YELLOW,
3059 EL_SP_HARDWARE_BASE_1,
3060 EL_SP_HARDWARE_BASE_2,
3061 EL_SP_HARDWARE_BASE_3,
3062 EL_SP_HARDWARE_BASE_4,
3063 EL_SP_HARDWARE_BASE_5,
3064 EL_SP_HARDWARE_BASE_6,
3066 EL_SP_TERMINAL_ACTIVE,
3069 EL_INVISIBLE_STEELWALL,
3070 EL_INVISIBLE_STEELWALL_ACTIVE,
3072 EL_INVISIBLE_WALL_ACTIVE,
3073 EL_STEELWALL_SLIPPERY,
3089 static int ep_historic_solid[] =
3093 EL_EXPANDABLE_WALL_HORIZONTAL,
3094 EL_EXPANDABLE_WALL_VERTICAL,
3095 EL_EXPANDABLE_WALL_ANY,
3108 EL_QUICKSAND_FILLING,
3109 EL_QUICKSAND_EMPTYING,
3111 EL_MAGIC_WALL_ACTIVE,
3112 EL_MAGIC_WALL_EMPTYING,
3113 EL_MAGIC_WALL_FILLING,
3117 EL_BD_MAGIC_WALL_ACTIVE,
3118 EL_BD_MAGIC_WALL_EMPTYING,
3119 EL_BD_MAGIC_WALL_FULL,
3120 EL_BD_MAGIC_WALL_FILLING,
3121 EL_BD_MAGIC_WALL_DEAD,
3130 EL_SP_TERMINAL_ACTIVE,
3134 EL_INVISIBLE_WALL_ACTIVE,
3135 EL_SWITCHGATE_SWITCH_UP,
3136 EL_SWITCHGATE_SWITCH_DOWN,
3138 EL_TIMEGATE_SWITCH_ACTIVE,
3150 /* the following elements are a direct copy of "indestructible" elements,
3151 except "EL_ACID", which is "indestructible", but not "solid"! */
3156 EL_ACID_POOL_TOPLEFT,
3157 EL_ACID_POOL_TOPRIGHT,
3158 EL_ACID_POOL_BOTTOMLEFT,
3159 EL_ACID_POOL_BOTTOM,
3160 EL_ACID_POOL_BOTTOMRIGHT,
3161 EL_SP_HARDWARE_GRAY,
3162 EL_SP_HARDWARE_GREEN,
3163 EL_SP_HARDWARE_BLUE,
3165 EL_SP_HARDWARE_YELLOW,
3166 EL_SP_HARDWARE_BASE_1,
3167 EL_SP_HARDWARE_BASE_2,
3168 EL_SP_HARDWARE_BASE_3,
3169 EL_SP_HARDWARE_BASE_4,
3170 EL_SP_HARDWARE_BASE_5,
3171 EL_SP_HARDWARE_BASE_6,
3172 EL_INVISIBLE_STEELWALL,
3173 EL_INVISIBLE_STEELWALL_ACTIVE,
3174 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3175 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3176 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3177 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3178 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3179 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3180 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3181 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3182 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3183 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3184 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3185 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3187 EL_LIGHT_SWITCH_ACTIVE,
3188 EL_SIGN_EXCLAMATION,
3189 EL_SIGN_RADIOACTIVITY,
3200 EL_STEELWALL_SLIPPERY,
3223 EL_SWITCHGATE_OPENING,
3224 EL_SWITCHGATE_CLOSED,
3225 EL_SWITCHGATE_CLOSING,
3227 EL_TIMEGATE_OPENING,
3229 EL_TIMEGATE_CLOSING,
3233 EL_TUBE_VERTICAL_LEFT,
3234 EL_TUBE_VERTICAL_RIGHT,
3235 EL_TUBE_HORIZONTAL_UP,
3236 EL_TUBE_HORIZONTAL_DOWN,
3244 static int ep_classic_enemy[] =
3260 static int ep_belt[] =
3262 EL_CONVEYOR_BELT_1_LEFT,
3263 EL_CONVEYOR_BELT_1_MIDDLE,
3264 EL_CONVEYOR_BELT_1_RIGHT,
3265 EL_CONVEYOR_BELT_2_LEFT,
3266 EL_CONVEYOR_BELT_2_MIDDLE,
3267 EL_CONVEYOR_BELT_2_RIGHT,
3268 EL_CONVEYOR_BELT_3_LEFT,
3269 EL_CONVEYOR_BELT_3_MIDDLE,
3270 EL_CONVEYOR_BELT_3_RIGHT,
3271 EL_CONVEYOR_BELT_4_LEFT,
3272 EL_CONVEYOR_BELT_4_MIDDLE,
3273 EL_CONVEYOR_BELT_4_RIGHT,
3277 static int ep_belt_active[] =
3279 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3280 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3281 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3282 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3283 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3284 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3285 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3286 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3287 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3288 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3289 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3290 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3294 static int ep_belt_switch[] =
3296 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3297 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3298 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3299 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3300 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3301 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3302 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3303 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3304 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3305 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3306 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3307 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3311 static int ep_tube[] =
3318 EL_TUBE_HORIZONTAL_UP,
3319 EL_TUBE_HORIZONTAL_DOWN,
3321 EL_TUBE_VERTICAL_LEFT,
3322 EL_TUBE_VERTICAL_RIGHT,
3327 static int ep_keygate[] =
3356 static int ep_amoeboid[] =
3366 static int ep_amoebalive[] =
3375 static int ep_has_content[] =
3385 static int ep_can_turn_each_move[] =
3387 /* !!! do something with this one !!! */
3391 static int ep_can_grow[] =
3403 static int ep_active_bomb[] =
3406 EL_DYNABOMB_PLAYER_1_ACTIVE,
3407 EL_DYNABOMB_PLAYER_2_ACTIVE,
3408 EL_DYNABOMB_PLAYER_3_ACTIVE,
3409 EL_DYNABOMB_PLAYER_4_ACTIVE,
3410 EL_SP_DISK_RED_ACTIVE,
3414 static int ep_inactive[] =
3463 EL_INVISIBLE_STEELWALL,
3471 EL_WALL_EMERALD_YELLOW,
3472 EL_DYNABOMB_INCREASE_NUMBER,
3473 EL_DYNABOMB_INCREASE_SIZE,
3474 EL_DYNABOMB_INCREASE_POWER,
3478 EL_SOKOBAN_FIELD_EMPTY,
3479 EL_SOKOBAN_FIELD_FULL,
3480 EL_WALL_EMERALD_RED,
3481 EL_WALL_EMERALD_PURPLE,
3482 EL_ACID_POOL_TOPLEFT,
3483 EL_ACID_POOL_TOPRIGHT,
3484 EL_ACID_POOL_BOTTOMLEFT,
3485 EL_ACID_POOL_BOTTOM,
3486 EL_ACID_POOL_BOTTOMRIGHT,
3490 EL_BD_MAGIC_WALL_DEAD,
3491 EL_AMOEBA_TO_DIAMOND,
3499 EL_SP_GRAVITY_PORT_RIGHT,
3500 EL_SP_GRAVITY_PORT_DOWN,
3501 EL_SP_GRAVITY_PORT_LEFT,
3502 EL_SP_GRAVITY_PORT_UP,
3503 EL_SP_PORT_HORIZONTAL,
3504 EL_SP_PORT_VERTICAL,
3515 EL_SP_HARDWARE_GRAY,
3516 EL_SP_HARDWARE_GREEN,
3517 EL_SP_HARDWARE_BLUE,
3519 EL_SP_HARDWARE_YELLOW,
3520 EL_SP_HARDWARE_BASE_1,
3521 EL_SP_HARDWARE_BASE_2,
3522 EL_SP_HARDWARE_BASE_3,
3523 EL_SP_HARDWARE_BASE_4,
3524 EL_SP_HARDWARE_BASE_5,
3525 EL_SP_HARDWARE_BASE_6,
3526 EL_SP_GRAVITY_ON_PORT_LEFT,
3527 EL_SP_GRAVITY_ON_PORT_RIGHT,
3528 EL_SP_GRAVITY_ON_PORT_UP,
3529 EL_SP_GRAVITY_ON_PORT_DOWN,
3530 EL_SP_GRAVITY_OFF_PORT_LEFT,
3531 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3532 EL_SP_GRAVITY_OFF_PORT_UP,
3533 EL_SP_GRAVITY_OFF_PORT_DOWN,
3534 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3535 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3536 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3537 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3538 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3539 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3540 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3541 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3542 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3543 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3544 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3545 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3546 EL_SIGN_EXCLAMATION,
3547 EL_SIGN_RADIOACTIVITY,
3558 EL_STEELWALL_SLIPPERY,
3563 EL_EMC_WALL_SLIPPERY_1,
3564 EL_EMC_WALL_SLIPPERY_2,
3565 EL_EMC_WALL_SLIPPERY_3,
3566 EL_EMC_WALL_SLIPPERY_4,
3586 static int ep_em_slippery_wall[] =
3591 static int ep_gfx_crumbled[] =
3604 } element_properties[] =
3606 { ep_diggable, EP_DIGGABLE },
3607 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
3608 { ep_dont_run_into, EP_DONT_RUN_INTO },
3609 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
3610 { ep_dont_touch, EP_DONT_TOUCH },
3611 { ep_indestructible, EP_INDESTRUCTIBLE },
3612 { ep_slippery, EP_SLIPPERY },
3613 { ep_can_change, EP_CAN_CHANGE },
3614 { ep_can_move, EP_CAN_MOVE },
3615 { ep_can_fall, EP_CAN_FALL },
3616 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
3617 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
3618 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
3619 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
3620 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
3621 { ep_explodes_impact, EP_EXPLODES_IMPACT },
3622 { ep_walkable_over, EP_WALKABLE_OVER },
3623 { ep_walkable_inside, EP_WALKABLE_INSIDE },
3624 { ep_walkable_under, EP_WALKABLE_UNDER },
3625 { ep_passable_over, EP_PASSABLE_OVER },
3626 { ep_passable_inside, EP_PASSABLE_INSIDE },
3627 { ep_passable_under, EP_PASSABLE_UNDER },
3628 { ep_droppable, EP_DROPPABLE },
3629 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
3630 { ep_pushable, EP_PUSHABLE },
3631 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
3632 { ep_protected, EP_PROTECTED },
3633 { ep_throwable, EP_THROWABLE },
3634 { ep_can_explode, EP_CAN_EXPLODE },
3635 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
3637 { ep_player, EP_PLAYER },
3638 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
3639 { ep_switchable, EP_SWITCHABLE },
3640 { ep_bd_element, EP_BD_ELEMENT },
3641 { ep_sp_element, EP_SP_ELEMENT },
3642 { ep_sb_element, EP_SB_ELEMENT },
3644 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
3645 { ep_food_penguin, EP_FOOD_PENGUIN },
3646 { ep_food_pig, EP_FOOD_PIG },
3647 { ep_historic_wall, EP_HISTORIC_WALL },
3648 { ep_historic_solid, EP_HISTORIC_SOLID },
3649 { ep_classic_enemy, EP_CLASSIC_ENEMY },
3650 { ep_belt, EP_BELT },
3651 { ep_belt_active, EP_BELT_ACTIVE },
3652 { ep_belt_switch, EP_BELT_SWITCH },
3653 { ep_tube, EP_TUBE },
3654 { ep_keygate, EP_KEYGATE },
3655 { ep_amoeboid, EP_AMOEBOID },
3656 { ep_amoebalive, EP_AMOEBALIVE },
3657 { ep_has_content, EP_HAS_CONTENT },
3658 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
3659 { ep_can_grow, EP_CAN_GROW },
3660 { ep_active_bomb, EP_ACTIVE_BOMB },
3661 { ep_inactive, EP_INACTIVE },
3663 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
3665 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
3672 /* always start with reliable default values (element has no properties) */
3673 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3674 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
3675 SET_PROPERTY(i, j, FALSE);
3677 /* set all base element properties from above array definitions */
3678 for (i = 0; element_properties[i].elements != NULL; i++)
3679 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
3680 SET_PROPERTY((element_properties[i].elements)[j],
3681 element_properties[i].property, TRUE);
3683 /* copy properties to some elements that are only stored in level file */
3684 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
3685 for (j = 0; copy_properties[j][0] != -1; j++)
3686 if (HAS_PROPERTY(copy_properties[j][0], i))
3687 for (k = 1; k <= 4; k++)
3688 SET_PROPERTY(copy_properties[j][k], i, TRUE);
3691 void InitElementPropertiesEngine(int engine_version)
3694 static int active_properties[] =
3699 EP_DONT_COLLIDE_WITH,
3703 EP_CAN_PASS_MAGIC_WALL,
3708 EP_EXPLODES_BY_FIRE,
3721 EP_EM_SLIPPERY_WALL,
3725 static int no_wall_properties[] =
3728 EP_COLLECTIBLE_ONLY,
3730 EP_DONT_COLLIDE_WITH,
3733 EP_CAN_SMASH_PLAYER,
3734 EP_CAN_SMASH_ENEMIES,
3735 EP_CAN_SMASH_EVERYTHING,
3740 EP_FOOD_DARK_YAMYAM,
3757 InitElementPropertiesStatic();
3760 /* important: after initialization in InitElementPropertiesStatic(), the
3761 elements are not again initialized to a default value; therefore all
3762 changes have to make sure that they leave the element with a defined
3763 property (which means that conditional property changes must be set to
3764 a reliable default value before) */
3766 /* set all special, combined or engine dependent element properties */
3767 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3770 for (j = EP_ACCESSIBLE_OVER; j < NUM_ELEMENT_PROPERTIES; j++)
3771 SET_PROPERTY(i, j, FALSE);
3774 /* ---------- INACTIVE ------------------------------------------------- */
3775 SET_PROPERTY(i, EP_INACTIVE, (i >= EL_CHAR_START && i <= EL_CHAR_END));
3777 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
3778 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
3779 IS_WALKABLE_INSIDE(i) ||
3780 IS_WALKABLE_UNDER(i)));
3782 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
3783 IS_PASSABLE_INSIDE(i) ||
3784 IS_PASSABLE_UNDER(i)));
3786 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
3787 IS_PASSABLE_OVER(i)));
3789 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
3790 IS_PASSABLE_INSIDE(i)));
3792 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
3793 IS_PASSABLE_UNDER(i)));
3795 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
3798 /* ---------- COLLECTIBLE ---------------------------------------------- */
3799 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
3803 /* ---------- SNAPPABLE ------------------------------------------------ */
3804 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
3805 IS_COLLECTIBLE(i) ||
3809 /* ---------- WALL ----------------------------------------------------- */
3810 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
3812 for (j = 0; no_wall_properties[j] != -1; j++)
3813 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
3814 i >= EL_FIRST_RUNTIME_UNREAL)
3815 SET_PROPERTY(i, EP_WALL, FALSE);
3817 if (IS_HISTORIC_WALL(i))
3818 SET_PROPERTY(i, EP_WALL, TRUE);
3820 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
3821 if (engine_version < VERSION_IDENT(2,2,0,0))
3822 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
3824 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
3826 !IS_COLLECTIBLE(i)));
3829 /* ---------- PROTECTED ------------------------------------------------ */
3830 if (IS_ACCESSIBLE_INSIDE(i))
3831 SET_PROPERTY(i, EP_PROTECTED, TRUE);
3834 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
3836 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
3837 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
3839 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
3840 IS_INDESTRUCTIBLE(i)));
3842 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
3844 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
3845 else if (engine_version < VERSION_IDENT(2,2,0,0))
3846 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
3849 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3854 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3855 !IS_WALKABLE_OVER(i) &&
3856 !IS_WALKABLE_UNDER(i)));
3858 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3863 if (IS_CUSTOM_ELEMENT(i))
3865 /* these are additional properties which are initially false when set */
3867 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
3869 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
3870 if (DONT_COLLIDE_WITH(i))
3871 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
3873 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
3874 if (CAN_SMASH_EVERYTHING(i))
3875 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
3876 if (CAN_SMASH_ENEMIES(i))
3877 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
3880 /* ---------- CAN_SMASH ------------------------------------------------ */
3881 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
3882 CAN_SMASH_ENEMIES(i) ||
3883 CAN_SMASH_EVERYTHING(i)));
3886 /* ---------- CAN_EXPLODE ---------------------------------------------- */
3887 SET_PROPERTY(i, EP_CAN_EXPLODE, (CAN_EXPLODE_BY_FIRE(i) ||
3888 CAN_EXPLODE_SMASHED(i) ||
3889 CAN_EXPLODE_IMPACT(i)));
3893 /* ---------- CAN_EXPLODE_3X3 ------------------------------------------ */
3895 SET_PROPERTY(i, EP_CAN_EXPLODE_3X3, (!CAN_EXPLODE_1X1(i) &&
3896 !CAN_EXPLODE_CROSS(i)));
3898 SET_PROPERTY(i, EP_CAN_EXPLODE_3X3, (CAN_EXPLODE(i) &&
3899 !CAN_EXPLODE_1X1(i) &&
3900 !CAN_EXPLODE_CROSS(i)));
3904 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
3905 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
3906 EXPLODES_BY_FIRE(i)));
3908 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
3909 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
3910 EXPLODES_SMASHED(i)));
3912 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
3913 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
3914 EXPLODES_IMPACT(i)));
3916 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
3917 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
3919 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
3920 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
3921 i == EL_BLACK_ORB));
3923 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
3924 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
3926 IS_CUSTOM_ELEMENT(i)));
3928 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
3929 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
3930 i == EL_SP_ELECTRON));
3932 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
3933 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
3934 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
3935 getMoveIntoAcidProperty(&level, i));
3937 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
3938 if (MAYBE_DONT_COLLIDE_WITH(i))
3939 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
3940 getDontCollideWithProperty(&level, i));
3942 /* ---------- SP_PORT -------------------------------------------------- */
3943 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
3944 IS_PASSABLE_INSIDE(i)));
3946 /* ---------- CAN_CHANGE ----------------------------------------------- */
3947 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
3948 for (j = 0; j < element_info[i].num_change_pages; j++)
3949 if (element_info[i].change_page[j].can_change)
3950 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
3952 /* ---------- GFX_CRUMBLED --------------------------------------------- */
3954 SET_PROPERTY(i, EP_GFX_CRUMBLED,
3955 element_info[i].crumbled[ACTION_DEFAULT] !=
3956 element_info[i].graphic[ACTION_DEFAULT]);
3958 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
3959 SET_PROPERTY(i, EP_GFX_CRUMBLED,
3960 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
3965 /* determine inactive elements (used for engine main loop optimization) */
3966 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3968 boolean active = FALSE;
3970 for (j = 0; i < NUM_ELEMENT_PROPERTIES; j++)
3972 if (HAS_PROPERTY(i, j))
3978 SET_PROPERTY(i, EP_INACTIVE, TRUE);
3983 /* dynamically adjust element properties according to game engine version */
3985 static int ep_em_slippery_wall[] =
3990 EL_EXPANDABLE_WALL_HORIZONTAL,
3991 EL_EXPANDABLE_WALL_VERTICAL,
3992 EL_EXPANDABLE_WALL_ANY,
3996 /* special EM style gems behaviour */
3997 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
3998 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
3999 level.em_slippery_gems);
4001 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4002 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4003 (level.em_slippery_gems &&
4004 engine_version > VERSION_IDENT(2,0,1,0)));
4008 /* set default push delay values (corrected since version 3.0.7-1) */
4009 if (engine_version < VERSION_IDENT(3,0,7,1))
4011 game.default_push_delay_fixed = 2;
4012 game.default_push_delay_random = 8;
4016 game.default_push_delay_fixed = 8;
4017 game.default_push_delay_random = 8;
4020 /* set uninitialized push delay values of custom elements in older levels */
4021 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4023 int element = EL_CUSTOM_START + i;
4025 if (element_info[element].push_delay_fixed == -1)
4026 element_info[element].push_delay_fixed = game.default_push_delay_fixed;
4027 if (element_info[element].push_delay_random == -1)
4028 element_info[element].push_delay_random = game.default_push_delay_random;
4031 /* set some other uninitialized values of custom elements in older levels */
4032 if (engine_version < VERSION_IDENT(3,1,0,0))
4034 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4036 int element = EL_CUSTOM_START + i;
4038 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4040 element_info[element].explosion_delay = 17;
4041 element_info[element].ignition_delay = 8;
4046 /* set element properties that were handled incorrectly in older levels */
4047 if (engine_version < VERSION_IDENT(3,1,0,0))
4049 SET_PROPERTY(EL_SP_SNIKSNAK, EP_DONT_COLLIDE_WITH, FALSE);
4050 SET_PROPERTY(EL_SP_ELECTRON, EP_DONT_COLLIDE_WITH, FALSE);
4056 /* this is needed because some graphics depend on element properties */
4057 if (game_status == GAME_MODE_PLAYING)
4058 InitElementGraphicInfo();
4061 static void InitGlobal()
4065 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4067 /* check if element_name_info entry defined for each element in "main.h" */
4068 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4069 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4071 element_info[i].token_name = element_name_info[i].token_name;
4072 element_info[i].class_name = element_name_info[i].class_name;
4073 element_info[i].editor_description=element_name_info[i].editor_description;
4076 global.autoplay_leveldir = NULL;
4077 global.convert_leveldir = NULL;
4079 global.frames_per_second = 0;
4080 global.fps_slowdown = FALSE;
4081 global.fps_slowdown_factor = 1;
4084 void Execute_Command(char *command)
4088 if (strcmp(command, "print graphicsinfo.conf") == 0)
4090 printf("# You can configure additional/alternative image files here.\n");
4091 printf("# (The entries below are default and therefore commented out.)\n");
4093 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4095 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4098 for (i = 0; image_config[i].token != NULL; i++)
4099 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
4100 image_config[i].value));
4104 else if (strcmp(command, "print soundsinfo.conf") == 0)
4106 printf("# You can configure additional/alternative sound files here.\n");
4107 printf("# (The entries below are default and therefore commented out.)\n");
4109 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4111 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4114 for (i = 0; sound_config[i].token != NULL; i++)
4115 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4116 sound_config[i].value));
4120 else if (strcmp(command, "print musicinfo.conf") == 0)
4122 printf("# You can configure additional/alternative music files here.\n");
4123 printf("# (The entries below are default and therefore commented out.)\n");
4125 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4127 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4130 for (i = 0; music_config[i].token != NULL; i++)
4131 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
4132 music_config[i].value));
4136 else if (strcmp(command, "print editorsetup.conf") == 0)
4138 printf("# You can configure your personal editor element list here.\n");
4139 printf("# (The entries below are default and therefore commented out.)\n");
4142 PrintEditorElementList();
4146 else if (strcmp(command, "print helpanim.conf") == 0)
4148 printf("# You can configure different element help animations here.\n");
4149 printf("# (The entries below are default and therefore commented out.)\n");
4152 for (i = 0; helpanim_config[i].token != NULL; i++)
4154 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4155 helpanim_config[i].value));
4157 if (strcmp(helpanim_config[i].token, "end") == 0)
4163 else if (strcmp(command, "print helptext.conf") == 0)
4165 printf("# You can configure different element help text here.\n");
4166 printf("# (The entries below are default and therefore commented out.)\n");
4169 for (i = 0; helptext_config[i].token != NULL; i++)
4170 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4171 helptext_config[i].value));
4175 else if (strncmp(command, "dump level ", 11) == 0)
4177 char *filename = &command[11];
4179 if (!fileExists(filename))
4180 Error(ERR_EXIT, "cannot open file '%s'", filename);
4182 LoadLevelFromFilename(&level, filename);
4187 else if (strncmp(command, "dump tape ", 10) == 0)
4189 char *filename = &command[10];
4191 if (!fileExists(filename))
4192 Error(ERR_EXIT, "cannot open file '%s'", filename);
4194 LoadTapeFromFilename(filename);
4199 else if (strncmp(command, "autoplay ", 9) == 0)
4201 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
4203 while (*str_ptr != '\0') /* continue parsing string */
4205 /* cut leading whitespace from string, replace it by string terminator */
4206 while (*str_ptr == ' ' || *str_ptr == '\t')
4209 if (*str_ptr == '\0') /* end of string reached */
4212 if (global.autoplay_leveldir == NULL) /* read level set string */
4214 global.autoplay_leveldir = str_ptr;
4215 global.autoplay_all = TRUE; /* default: play all tapes */
4217 for (i = 0; i < MAX_TAPES_PER_SET; i++)
4218 global.autoplay_level[i] = FALSE;
4220 else /* read level number string */
4222 int level_nr = atoi(str_ptr); /* get level_nr value */
4224 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
4225 global.autoplay_level[level_nr] = TRUE;
4227 global.autoplay_all = FALSE;
4230 /* advance string pointer to the next whitespace (or end of string) */
4231 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
4236 printf("level set == '%s'\n", global.autoplay_leveldir);
4238 if (global.autoplay_all)
4239 printf("play all levels\n");
4242 printf("play the following levels:");
4244 for (i = 0; i < MAX_TAPES_PER_SET; i++)
4245 if (global.autoplay_level[i])
4253 else if (strncmp(command, "convert ", 8) == 0)
4255 char *str_copy = getStringCopy(&command[8]);
4256 char *str_ptr = strchr(str_copy, ' ');
4258 global.convert_leveldir = str_copy;
4259 global.convert_level_nr = -1;
4261 if (str_ptr != NULL) /* level number follows */
4263 *str_ptr++ = '\0'; /* terminate leveldir string */
4264 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
4269 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4273 static void InitSetup()
4275 LoadSetup(); /* global setup info */
4277 /* set some options from setup file */
4279 if (setup.options.verbose)
4280 options.verbose = TRUE;
4283 static void InitPlayerInfo()
4287 /* choose default local player */
4288 local_player = &stored_player[0];
4290 for (i = 0; i < MAX_PLAYERS; i++)
4291 stored_player[i].connected = FALSE;
4293 local_player->connected = TRUE;
4296 static void InitArtworkInfo()
4301 static char *get_string_in_brackets(char *string)
4303 char *string_in_brackets = checked_malloc(strlen(string) + 3);
4305 sprintf(string_in_brackets, "[%s]", string);
4307 return string_in_brackets;
4310 static char *get_level_id_suffix(int id_nr)
4312 char *id_suffix = checked_malloc(1 + 3 + 1);
4314 if (id_nr < 0 || id_nr > 999)
4317 sprintf(id_suffix, ".%03d", id_nr);
4323 static char *get_element_class_token(int element)
4325 char *element_class_name = element_info[element].class_name;
4326 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
4328 sprintf(element_class_token, "[%s]", element_class_name);
4330 return element_class_token;
4333 static char *get_action_class_token(int action)
4335 char *action_class_name = &element_action_info[action].suffix[1];
4336 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
4338 sprintf(action_class_token, "[%s]", action_class_name);
4340 return action_class_token;
4344 static void InitArtworkConfig()
4346 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
4347 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
4348 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
4349 static char *action_id_suffix[NUM_ACTIONS + 1];
4350 static char *direction_id_suffix[NUM_DIRECTIONS + 1];
4351 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
4352 static char *level_id_suffix[MAX_LEVELS + 1];
4353 static char *dummy[1] = { NULL };
4354 static char *ignore_generic_tokens[] =
4360 static char **ignore_image_tokens;
4361 static char **ignore_sound_tokens;
4362 static char **ignore_music_tokens;
4363 int num_ignore_generic_tokens;
4364 int num_ignore_image_tokens;
4365 int num_ignore_sound_tokens;
4366 int num_ignore_music_tokens;
4369 /* dynamically determine list of generic tokens to be ignored */
4370 num_ignore_generic_tokens = 0;
4371 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
4372 num_ignore_generic_tokens++;
4374 /* dynamically determine list of image tokens to be ignored */
4375 num_ignore_image_tokens = num_ignore_generic_tokens;
4376 for (i = 0; image_config_vars[i].token != NULL; i++)
4377 num_ignore_image_tokens++;
4378 ignore_image_tokens =
4379 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
4380 for (i = 0; i < num_ignore_generic_tokens; i++)
4381 ignore_image_tokens[i] = ignore_generic_tokens[i];
4382 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
4383 ignore_image_tokens[num_ignore_generic_tokens + i] =
4384 image_config_vars[i].token;
4385 ignore_image_tokens[num_ignore_image_tokens] = NULL;
4387 /* dynamically determine list of sound tokens to be ignored */
4388 num_ignore_sound_tokens = num_ignore_generic_tokens;
4389 ignore_sound_tokens =
4390 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
4391 for (i = 0; i < num_ignore_generic_tokens; i++)
4392 ignore_sound_tokens[i] = ignore_generic_tokens[i];
4393 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
4395 /* dynamically determine list of music tokens to be ignored */
4396 num_ignore_music_tokens = num_ignore_generic_tokens;
4397 ignore_music_tokens =
4398 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
4399 for (i = 0; i < num_ignore_generic_tokens; i++)
4400 ignore_music_tokens[i] = ignore_generic_tokens[i];
4401 ignore_music_tokens[num_ignore_music_tokens] = NULL;
4403 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4404 image_id_prefix[i] = element_info[i].token_name;
4405 for (i = 0; i < NUM_FONTS; i++)
4406 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
4407 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
4409 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4410 sound_id_prefix[i] = element_info[i].token_name;
4411 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4412 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
4413 get_string_in_brackets(element_info[i].class_name);
4414 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
4416 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
4417 music_id_prefix[i] = music_prefix_info[i].prefix;
4418 music_id_prefix[MAX_LEVELS] = NULL;
4420 for (i = 0; i < NUM_ACTIONS; i++)
4421 action_id_suffix[i] = element_action_info[i].suffix;
4422 action_id_suffix[NUM_ACTIONS] = NULL;
4424 for (i = 0; i < NUM_DIRECTIONS; i++)
4425 direction_id_suffix[i] = element_direction_info[i].suffix;
4426 direction_id_suffix[NUM_DIRECTIONS] = NULL;
4428 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
4429 special_id_suffix[i] = special_suffix_info[i].suffix;
4430 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
4432 for (i = 0; i < MAX_LEVELS; i++)
4433 level_id_suffix[i] = get_level_id_suffix(i);
4434 level_id_suffix[MAX_LEVELS] = NULL;
4436 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
4437 image_id_prefix, action_id_suffix, direction_id_suffix,
4438 special_id_suffix, ignore_image_tokens);
4439 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
4440 sound_id_prefix, action_id_suffix, dummy,
4441 special_id_suffix, ignore_sound_tokens);
4442 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
4443 music_id_prefix, special_id_suffix, level_id_suffix,
4444 dummy, ignore_music_tokens);
4447 static void InitMixer()
4455 char *filename_font_initial = NULL;
4456 Bitmap *bitmap_font_initial = NULL;
4459 /* determine settings for initial font (for displaying startup messages) */
4460 for (i = 0; image_config[i].token != NULL; i++)
4462 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4464 char font_token[128];
4467 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
4468 len_font_token = strlen(font_token);
4470 if (strcmp(image_config[i].token, font_token) == 0)
4471 filename_font_initial = image_config[i].value;
4472 else if (strlen(image_config[i].token) > len_font_token &&
4473 strncmp(image_config[i].token, font_token, len_font_token) == 0)
4475 if (strcmp(&image_config[i].token[len_font_token], ".x") == 0)
4476 font_initial[j].src_x = atoi(image_config[i].value);
4477 else if (strcmp(&image_config[i].token[len_font_token], ".y") == 0)
4478 font_initial[j].src_y = atoi(image_config[i].value);
4479 else if (strcmp(&image_config[i].token[len_font_token], ".width") == 0)
4480 font_initial[j].width = atoi(image_config[i].value);
4481 else if (strcmp(&image_config[i].token[len_font_token],".height") == 0)
4482 font_initial[j].height = atoi(image_config[i].value);
4487 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4489 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
4490 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
4493 if (filename_font_initial == NULL) /* should not happen */
4494 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
4496 /* create additional image buffers for double-buffering */
4497 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
4498 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
4500 /* initialize screen properties */
4501 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
4502 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
4504 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
4505 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
4506 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
4508 bitmap_font_initial = LoadCustomImage(filename_font_initial);
4510 for (j = 0; j < NUM_INITIAL_FONTS; j++)
4511 font_initial[j].bitmap = bitmap_font_initial;
4513 InitFontGraphicInfo();
4515 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
4516 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
4518 DrawInitText("Loading graphics:", 120, FC_GREEN);
4520 InitTileClipmasks();
4523 void InitGfxBackground()
4527 drawto = backbuffer;
4528 fieldbuffer = bitmap_db_field;
4529 SetDrawtoField(DRAW_BACKBUFFER);
4531 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
4532 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
4533 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
4534 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
4536 for (x = 0; x < MAX_BUF_XSIZE; x++)
4537 for (y = 0; y < MAX_BUF_YSIZE; y++)
4540 redraw_mask = REDRAW_ALL;
4543 static void InitLevelInfo()
4545 LoadLevelInfo(); /* global level info */
4546 LoadLevelSetup_LastSeries(); /* last played series info */
4547 LoadLevelSetup_SeriesInfo(); /* last played level info */
4550 void InitLevelArtworkInfo()
4552 LoadLevelArtworkInfo();
4555 static void InitImages()
4558 setLevelArtworkDir(artwork.gfx_first);
4562 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
4563 leveldir_current->identifier,
4564 artwork.gfx_current_identifier,
4565 artwork.gfx_current->identifier,
4566 leveldir_current->graphics_set,
4567 leveldir_current->graphics_path);
4570 ReloadCustomImages();
4572 LoadCustomElementDescriptions();
4573 LoadSpecialMenuDesignSettings();
4575 ReinitializeGraphics();
4578 static void InitSound(char *identifier)
4580 if (identifier == NULL)
4581 identifier = artwork.snd_current->identifier;
4584 /* set artwork path to send it to the sound server process */
4585 setLevelArtworkDir(artwork.snd_first);
4588 InitReloadCustomSounds(identifier);
4589 ReinitializeSounds();
4592 static void InitMusic(char *identifier)
4594 if (identifier == NULL)
4595 identifier = artwork.mus_current->identifier;
4598 /* set artwork path to send it to the sound server process */
4599 setLevelArtworkDir(artwork.mus_first);
4602 InitReloadCustomMusic(identifier);
4603 ReinitializeMusic();
4606 void InitNetworkServer()
4608 #if defined(NETWORK_AVALIABLE)
4612 if (!options.network)
4615 #if defined(NETWORK_AVALIABLE)
4616 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
4618 if (!ConnectToServer(options.server_host, options.server_port))
4619 Error(ERR_EXIT, "cannot connect to network game server");
4621 SendToServer_PlayerName(setup.player_name);
4622 SendToServer_ProtocolVersion();
4625 SendToServer_NrWanted(nr_wanted);
4629 static char *getNewArtworkIdentifier(int type)
4631 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
4632 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
4633 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
4634 static boolean initialized[3] = { FALSE, FALSE, FALSE };
4635 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
4636 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
4637 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
4638 char *leveldir_identifier = leveldir_current->identifier;
4640 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
4641 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
4643 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
4645 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
4646 char *artwork_current_identifier;
4647 char *artwork_new_identifier = NULL; /* default: nothing has changed */
4649 /* leveldir_current may be invalid (level group, parent link) */
4650 if (!validLevelSeries(leveldir_current))
4653 /* 1st step: determine artwork set to be activated in descending order:
4654 --------------------------------------------------------------------
4655 1. setup artwork (when configured to override everything else)
4656 2. artwork set configured in "levelinfo.conf" of current level set
4657 (artwork in level directory will have priority when loading later)
4658 3. artwork in level directory (stored in artwork sub-directory)
4659 4. setup artwork (currently configured in setup menu) */
4661 if (setup_override_artwork)
4662 artwork_current_identifier = setup_artwork_set;
4663 else if (leveldir_artwork_set != NULL)
4664 artwork_current_identifier = leveldir_artwork_set;
4665 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
4666 artwork_current_identifier = leveldir_identifier;
4668 artwork_current_identifier = setup_artwork_set;
4671 /* 2nd step: check if it is really needed to reload artwork set
4672 ------------------------------------------------------------ */
4675 if (type == ARTWORK_TYPE_GRAPHICS)
4676 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
4677 artwork_new_identifier,
4678 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4679 artwork_current_identifier,
4680 leveldir_current->graphics_set,
4681 leveldir_current->identifier);
4684 /* ---------- reload if level set and also artwork set has changed ------- */
4685 if (leveldir_current_identifier[type] != leveldir_identifier &&
4686 (last_has_level_artwork_set[type] || has_level_artwork_set))
4687 artwork_new_identifier = artwork_current_identifier;
4689 leveldir_current_identifier[type] = leveldir_identifier;
4690 last_has_level_artwork_set[type] = has_level_artwork_set;
4693 if (type == ARTWORK_TYPE_GRAPHICS)
4694 printf("::: 1: '%s'\n", artwork_new_identifier);
4697 /* ---------- reload if "override artwork" setting has changed ----------- */
4698 if (last_override_level_artwork[type] != setup_override_artwork)
4699 artwork_new_identifier = artwork_current_identifier;
4701 last_override_level_artwork[type] = setup_override_artwork;
4704 if (type == ARTWORK_TYPE_GRAPHICS)
4705 printf("::: 2: '%s'\n", artwork_new_identifier);
4708 /* ---------- reload if current artwork identifier has changed ----------- */
4709 if (strcmp(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4710 artwork_current_identifier) != 0)
4711 artwork_new_identifier = artwork_current_identifier;
4713 *(&(ARTWORK_CURRENT_IDENTIFIER(artwork, type))) = artwork_current_identifier;
4716 if (type == ARTWORK_TYPE_GRAPHICS)
4717 printf("::: 3: '%s'\n", artwork_new_identifier);
4720 /* ---------- do not reload directly after starting ---------------------- */
4721 if (!initialized[type])
4722 artwork_new_identifier = NULL;
4724 initialized[type] = TRUE;
4727 if (type == ARTWORK_TYPE_GRAPHICS)
4728 printf("::: 4: '%s'\n", artwork_new_identifier);
4732 if (type == ARTWORK_TYPE_GRAPHICS)
4733 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
4734 artwork.gfx_current_identifier, artwork_current_identifier,
4735 artwork.gfx_current->identifier, leveldir_current->graphics_set,
4736 artwork_new_identifier);
4739 return artwork_new_identifier;
4742 void ReloadCustomArtwork(int force_reload)
4744 char *gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
4745 char *snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
4746 char *mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
4747 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
4748 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
4749 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
4750 boolean redraw_screen = FALSE;
4752 if (gfx_new_identifier != NULL || force_reload_gfx)
4755 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
4756 artwork.gfx_current_identifier,
4758 artwork.gfx_current->identifier,
4759 leveldir_current->graphics_set);
4762 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4767 printf("... '%s'\n",
4768 leveldir_current->graphics_set);
4771 FreeTileClipmasks();
4772 InitTileClipmasks();
4774 redraw_screen = TRUE;
4777 if (snd_new_identifier != NULL || force_reload_snd)
4779 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4781 InitSound(snd_new_identifier);
4783 redraw_screen = TRUE;
4786 if (mus_new_identifier != NULL || force_reload_mus)
4788 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4790 InitMusic(mus_new_identifier);
4792 redraw_screen = TRUE;
4797 InitGfxBackground();
4799 /* force redraw of (open or closed) door graphics */
4800 SetDoorState(DOOR_OPEN_ALL);
4801 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
4805 void KeyboardAutoRepeatOffUnlessAutoplay()
4807 if (global.autoplay_leveldir == NULL)
4808 KeyboardAutoRepeatOff();
4812 /* ========================================================================= */
4814 /* ========================================================================= */
4818 InitGlobal(); /* initialize some global variables */
4820 if (options.execute_command)
4821 Execute_Command(options.execute_command);
4823 if (options.serveronly)
4825 #if defined(PLATFORM_UNIX)
4826 NetworkServer(options.server_port, options.serveronly);
4828 Error(ERR_WARN, "networking only supported in Unix version");
4831 exit(0); /* never reached, server loops forever */
4837 InitArtworkInfo(); /* needed before loading gfx, sound & music */
4838 InitArtworkConfig(); /* needed before forking sound child process */
4843 InitRND(NEW_RANDOMIZE);
4844 InitSimpleRND(NEW_RANDOMIZE);
4849 InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
4852 InitEventFilter(FilterMouseMotionEvents);
4854 InitElementPropertiesStatic();
4855 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4860 InitLevelArtworkInfo();
4862 InitImages(); /* needs to know current level directory */
4863 InitSound(NULL); /* needs to know current level directory */
4864 InitMusic(NULL); /* needs to know current level directory */
4866 InitGfxBackground();
4868 if (global.autoplay_leveldir)
4873 else if (global.convert_leveldir)
4879 game_status = GAME_MODE_MAIN;
4887 InitNetworkServer();
4890 void CloseAllAndExit(int exit_value)
4895 CloseAudio(); /* called after freeing sounds (needed for SDL) */
4902 FreeTileClipmasks();
4904 #if defined(TARGET_SDL)
4905 if (network_server) /* terminate network server */
4906 SDL_KillThread(server_thread);
4909 CloseVideoDisplay();
4910 ClosePlatformDependentStuff();